
Janosik
io.github.VitalyTolstikPublished by GitHub account VitalyTolstikv0.5.1Updated Nov 4, 2026
Drive a Janosik Kanban board from any MCP client: ready work, leases and task specs.
Overview
Connects an AI client to a self-hosted Janosik Kanban board so the assistant can read and change boards, columns, cards, checklists and comments.
- What you can do
- Work with boards, columns and cards: create, edit, move, archive and search them
- Manage labels, checklists, card links, comments, activity and attachments
- Optionally handle members, invitations, share links and account actions via extra toolsets
- Writes go through the same command log as the web UI, so they can be undone and appear live to other board members
- When to use it
- Useful when a team keeps its work on a self-hosted Janosik board and wants an agent to pick up ready tasks, claim cards under a lease, keep specs and checklists up to date, or report blocked work instead of closing it.
- Requirements
- A running Janosik instance in server mode and a personal API key created in the app (JANOSIK_TOKEN, starting with jnk_). Set JANOSIK_URL to the instance origin, and JANOSIK_APP_BASE only if the app is not served at the site root. Runs locally via npx; Node.js is needed.
Installation
In SourceWeft
- Open Janosik in the dashboard and add it to a workspace.
- Enable the server for the chats that should use its tools.
Desktop only via STDIO. STDIO servers start a local process, so they need the SourceWeft desktop host.
Other MCP clients
Follow the launch instructions in the repository.
README
Janosik
A self-hosted Kanban board for teams and AI agents. Server mode provides accounts, shared boards and realtime sync. The UI and API share one pure reducer and a command log; the installable PWA can reopen cached pages offline.
[React] [TypeScript] [Vite] [Tailwind CSS] [NestJS] [CI] [License: AGPL-3.0]
Janosik runs in server mode in development and production. The UI applies edits optimistically, then sends them to the API as commands (
POST /boards/:id/commands); the UI and API use the sameboardReducer. Unit tests can exercise the reducer without an API. The PWA caches its app shell and assets, so previously loaded pages can reopen offline, but saving changes requires a server connection. Realtime updates use SSE and resume from?since=after a dropped connection. See ROADMAP.md §7 for the architecture history.
Repository layout — the workspaces
This is an npm workspaces monorepo with seven workspaces and one root lockfile. ui, shared and backend make up the application; brand, site, video and mcp support its design system, website, media and agent integrations. Install dependencies once with npm install from the repository root.
Why shared matters: a board mutation is written once (in the reducer), executed in the browser for instant feedback and on the server when the command arrives — so a card can never move differently in the UI and in the database. The same applies to validation and to DTO types: change a field in shared/src/admin.ts and both sides fail to compile until they agree.
Highlights
- Four board views — Kanban, Calendar (drag deadlines, "unscheduled" panel, week/month, day panel), Table (sorting, inline editing, configurable columns) and Watch (a read-only status view with a live activity feed and 20/50/100-item pages).
- Card density — a
Simplify designtoggle switches every card to a compact one-line tile (title, label dots, blocked marker, checklist progress, priority and assignee) with far fewer elements; the full face stays one click away in the card dialog. - Drag & drop — move cards within/between columns and reorder columns (
@dnd-kit), inline Trello-style "+" zones, keyboard sensor and drag overlay. - Rich card content — WYSIWYG description (MDXEditor) that is the card's document (up to 64k characters), checklists with progress badges (items up to 500 characters), due dates with overdue/soon badges, color/gradient covers, 14-color labels, and a read-only machine-readable acceptance-criteria / definition-of-done contract.
- Card & board archive — Trello-style archiving with restore (WIP-aware) and permanent delete; board archive with restore.
- Multi-boards — switcher, create/rename/archive/delete, deep links
/board/:id, global search across boards with snippets. - Search & filters — by title/description/labels, label ANY/ALL matching, due status, creation date; hotkeys
/andCtrl/Cmd+K, match counter. - WIP limits — per-column caps with counters, blocked composers/drags and toasts.
- Activity feed — per-card event history covering every board action, with relative timestamps and an "Agent" badge on entries an agent's API token caused.
- Keyboard-first — shortcut palette (
?),j/kcursor navigation,n/ccomposers,e/Enteredit. - Undo / redo — 50-step history with coalescing,
Ctrl/Cmd+Z,Ctrl/Cmd+Shift+Z,Ctrl+Y, header buttons. - PWA — installable (manifest + icons). The service worker caches the app shell and hashed assets, so previously loaded pages can reopen offline. Writes still need the API: if it is unreachable, an optimistic edit rolls back with a message. There is no persistent outbox yet, so reloading discards unsynced changes; previously loaded data remains available offline.
- Server mode — sign in to work with boards stored in PostgreSQL. The UI applies edits optimistically and sends each one through the command log (
POST /boards/:id/commands); rejected edits roll back with a message. Per-entity version checks protect typed text from a stale undo. A request already in flight can finish during a reload. The no-API local-only mode is used by unit tests; development and production builds require the API. - Realtime — a
GET /boards/:id/eventsSSE stream carries every committed command ({type, seq, action, actorId}) and the client replays foreign actions through the very same reducer. Edits appear in other browsers with no reload; a dropped stream resumes exactly where it stopped (?since=) and window focus remains the fallback. Your own commands are never applied twice, and a stale undo still refuses to clobber someone else's text. - Shared boards — a Members (N) dialog in the header: admins invite by email, switch roles (
ADMIN/MEMBER/VIEWER), bound a viewer's access with an expiry date ("access expired" badge) and remove members — the last admin can never be demoted or removed. Invitations are opt-in: the invitee gets a badge on the header bell and accepts or declines there; nothing is shared until they accept. Everyone else sees the same member list read-only, and aVIEWERgets a genuinely read-only board: no drag, no composers, no menus, no inline editors, a read-only card dialog — while the server independently answers 403 to every mutation. - Master panel — a separate
/adminarea for the platform operator: metrics, all users and boards, command log, audit trail and moderation (block a user and their sessions die instantly, revoke API tokens, archive/soft-delete a board, create accounts with a one-time password). Master accounts live outside the user table, have their own login, cookie and JWT audience, and are created only by the server CLI (npm run admin:create -w backend);OWNERcan add more masters,OPERATORcannot. Panel tables are schema-first: columns are named after Prisma fields (Board.id,BoardMember.userId,Card.columnId,Comment.authorId, …), foreign keys are shown as copyable IDs (title/email only as a caption) and search matches those IDs — a row can be traced to its parents even when names are not unique. - AI agents (MCP + skill) —
@janosik/mcpgives compatible clients (Claude, Cursor, VS Code, opencode and Codex) access to board tools through a personal API key. Thejanosikskill provides workflow guidance: claim a card under a temporary lease, keep its description, checklist and comments structured, and return blocked work with evidence. Keys can be scoped to one board, made read-only and rate-limited. Commands retain actor attribution, history and undo. See Drive it from an AI agent. - Performance — the editor and calendar load on demand; vendor libraries use separate cacheable chunks, and board rows and cards are memoized. Performance measurements and their test conditions are recorded in docs/PERF-BASELINE.md.
- Data safety — debounced saves, JSON export/import, automatic backups (20 snapshots, rotated), error boundary + toasts, input/collection limits everywhere.
- Themes & polish — dark/light with no-flash preflight, four board backgrounds, adjustable column glass,
prefers-reduced-motion, custom scrollbars. - i18n — English & Russian with type-safe keys and pluralization; 12h/24h time format toggle.
- Brand — Space Grotesk wordmark (self-hosted) + animated "Перо Яношика" feather logo.
Tech stack
Quick start
Prerequisites: Node.js 22.17+ — the repo pins 24 via .nvmrc (nvm use), and that is what CI runs. npm. Docker for server mode (PostgreSQL/Redis).
Per-OS walkthroughs (macOS, Windows 11, Linux) — both Docker and from-source, with the OS-specific gotchas — live in docs/INSTALL-BY-OS.md.
Server mode (accounts + PostgreSQL)
The dev UI is always in server mode: it calls /api/v1 (Vite proxies it to :3000), so you get a sign-in screen and npm run dev alone does not show a board. Bring the database and API up first:
Register at http://localhost:5173 (registration is open by default) — the boards then live in PostgreSQL and sync through the command log. To open the master panel at /admin, create the first master on the server (see below).
Local-only / no-API build. The app can also render with no backend — that is the in-browser mode the unit tests use (
MODE=test), with the seeded "Product Launch" board inlocalStorage. Thenpm run dev/npm run buildbuilds are not that mode: they always talk to the API and show the login screen, so "just look at the demo board, no login" is not available from the dev server.
Marketing site (Astro) — dev
The marketing site and docs live in site/ (Astro + Starlight) and run on their own dev server:
In dev the app is not served under /app/ on the site — that path belongs to the self-host image, where one server serves the site at / and the app at /app/. So the site's "Sign in" / "Create account" CTAs must be pointed at the UI dev server, otherwise they 404:
The reverse link — the in-app Help → Documentation — points at the site, so give the UI dev server VITE_SITE_URL (otherwise it opens /docs/ on the UI origin and hits the not-found page):
The self-host image sets both by serving the site at / and the app at /app/ on one origin; a split deployment (two hosts) sets PUBLIC_APP_URL and VITE_SITE_URL to the two origins — see docs/SELF-HOSTING.md.
Enabling outgoing email (optional — off by default)
Email delivery is not enabled by default. The API boots fine with no mail setup: with no SMTP transport configured it runs in log mode — every message (verification codes, email-change notices) is written to the server log instead of being sent, and registration auto-verifies so nobody is locked out. Messages are never actually delivered until you configure a transport in the master panel.
To actually send mail, open /admin → Email service (owner only), pick a preset and paste the credentials, then flip Enable delivery and hit Send test email:
- Gmail / Yandex / Mail.ru — configure the provider's SMTP settings and use an app password where the provider requires one.
- Brevo / SendGrid — transactional email services. SendGrid uses
apikeyas the username and your API key as the password. - Custom SMTP — any host / port / TLS.
Trying it out locally (Mailpit). The Mailpit (sandbox) preset sends email to a local catcher and needs no credentials. Messages appear in its web inbox instead of being sent to a real address. Start it, then open the inbox:
Self-hosting with Docker (production)
The fastest way to run Janosik is the prebuilt image: one container serves the
whole app (API under /api/v1 + the built SPA), next to PostgreSQL and
Redis. No separate web server or proxy config — SSE and cookies work on a
single origin.
Create a master (platform admin) account for the /admin panel — the CLI
is the only door, there is deliberately no HTTP endpoint for it:
Upgrade and back up:
Environment variables (see .env.example for the full annotated list):
To build the image from a checkout instead of pulling, uncomment build: .
in docker-compose.yml. For a TLS-terminating proxy in front, keep
PUBLIC_ORIGIN=https://…, set COOKIE_SECURE=true and TRUST_PROXY=1.
Full guide — TLS setup (Caddy/nginx/Traefik), backups & restore, the environment reference and troubleshooting: docs/SELF-HOSTING.md.
Master panel (platform admin)
Regular accounts are not admins — the panel at /admin belongs to the platform operator (the "master"), and there is deliberately no HTTP endpoint that can create a master: registration always creates a regular user, and no request can grant master rights. Masters live in their own table with their own login, cookie and JWT audience, so a user session can never open /admin (and a master token never works on user routes).
Creating a master account (admin:create)
The CLI is the only door: registration always creates regular users, and no API call can grant master rights. Run the commands from the repository root, with backend dependencies installed and backend/.env present (its DATABASE_URL must point at the same database the API uses).
Rules worth knowing:
- Password: 8–100 characters. There is deliberately no
--passwordflag — a password inargvleaks intopsoutput and shell history. Without a TTY and withoutADMIN_PASSWORDthe CLI refuses to run. - Role: the first master in an empty database becomes
OWNERautomatically; every later CLI master isOPERATORunless--owneris passed. Owners can add/block/reset masters right in the panel (Masters page); operators have full data access but cannot manage masters, so a stolen operator session cannot escalate. - Email is required and normalized to lowercase; creating a duplicate fails with a hint to use
admin:passwd. - Audit: every create/re-key writes an
AdminAuditLogrow (via: "cli"), visible on the panel's Audit page. - Sign in at
http://localhost:5173/admin(dev) orhttps://your-host/admin(self-hosted). Sign-out sits in the top-right corner. - What you get there: metrics with 14-day sparklines plus a runtime card (version, uptime, DB latency), all users (search, filter, create with a one-time password, block → sessions die instantly, revoke API tokens), all boards (create for an owner, archive/restore, soft-delete), all cards and comments (search + moderation), active sessions and personal API tokens (scoped to a board, read-only or rate-limited) with per-row revoke, the cross-board command log, and the audit trail of every master action. Tables follow the database schema (see Highlights) and search matches foreign-key IDs. The board content editor (
/admin/boards/:id/content) creates and renames columns and cards through the command log on behalf of the board owner, so the board UI stays consistent. - Hardening that ships with it: argon2id hashes, 5-failed-login lockout (15 min) plus rate limiting, per-entity refresh rotation with reuse detection, response shapes that never include password/token hashes, and an audit row for every login attempt and mutation.
Drive it from an AI agent (MCP + skill)
Janosik lets AI agents and people work on shared boards. The MCP server provides the tools; the skill describes a consistent workflow for using them:
@janosik/mcp— the tools. An MCP server (71 tools across 13 groups) for boards, columns, cards, labels, checklists, links, comments, activity and attachments. Optional toolsets add members, invitations, share links and account actions. Any compatible MCP client can connect with a personal API key (jnk_…). Writes use the same command log as the UI, so they can be undone and stream live to other board members.skills/janosik— workflow guidance. It tells the agent to read before writing, claim a card under a time-limited lease, keep its description, checklist and comments structured, use reservedagent:*labels, and return blocked work with evidence instead of marking it Done.
1. Get an API key
In the app: Account → API keys → create (starts with jnk_). Give each
agent its own user account and key, so the activity feed shows who did what
and revoking one key stops one agent. A key can be scoped when you create it:
restrict it to a single board, make it read-only (writes answer 403 pat_read_only) and give it its own requests-per-minute budget (over budget
answers 429) — a board-scoped, read-only key is the least-privilege choice for
an agent.
2. Add the MCP server
Works in Claude Desktop/Code, Cursor, VS Code, opencode and Codex.
JANOSIK_APP_BASE is only needed when the app is not at the site root (e.g.
/app). By default the server registers the board-work tools; member,
invitation, share and account tools are opt-in (JANOSIK_MCP_TOOLSETS), and
attachment upload/download stays off until you set JANOSIK_MCP_ALLOW_FS=1.
3. Add the skill
Drop skills/janosik/ into your harness's skills directory — Claude Code:
~/.claude/skills/, opencode: ~/.config/opencode/skills/, agent-compatible
harnesses: ~/.agents/skills/. Details in
skills/janosik/README.md. The skill needs no
configuration; it provides Janosik-specific guidance for working with cards.
What the agent does with it
The agent claims a card under an atomic lease (janosik_claim_card, released with
janosik_release_card): the server refuses a claim while another member still
holds a live lease, and the lease expires automatically if an agent stops
responding. It comments as it goes, fills the description and checklist, moves
it In Progress → Review → Done, and on a bug moves it back (to Bugs /
In Progress) with a comment describing the defect — so a reviewer sees the card
travel forward, back and forward again, with a reason at every turn. That
backward move plus the comment is the audit trail.
The skill asks the agent to leave a card another agent can continue without
prior context: description
sections (Why / Scope / Acceptance criteria / Out of scope / Verify),
a Definition of Done checklist, and typed comments (a structured kind:
status / question / blocker / evidence / handoff) so the thread is
machine-readable and filterable. It can also write the card's task contract
(janosik_set_card_task_spec sets acceptanceCriteria + definitionOfDone,
each rendered read-only in the card dialog) and tag cards with the reserved
agent:blocked / agent:needs-human / agent:verified labels. Every command
records whether a person or an agent caused it, so an agent's entries carry an
"Agent" badge in the card history.
Full guide in-repo: mcp/README.md and skills/janosik/SKILL.md.
Scripts
Root scripts cover the seven npm workspaces:
Workspace-specific extras worth knowing:
Project structure (UI workspace in detail)
Architecture (30 seconds)
- Normalized data model — a
Boardholds orderedColumn[], aRecord<string, Card>andLabel[]. Reordering = reordering id arrays. Archived cards stay in the map witharchivedAtand are dropped fromcolumn.cardIdsuntil restored. - Pure reducer in
shared—boardReducer(30+ actions) is a pure function; every action returns a new board, which makes undo/redo, coalescing and testing trivial. The backend executes the identical reducer when a command reaches the command log, so UI and server can never diverge. - One provider, three contexts —
BoardProviderowns state, debounced persistence (400 ms), per-board history, hotkeys and auto-backups. It publishes the board data, the actions (assembled once, so write-only components never re-render) and undo availability separately. Components only call typed convenience actions (addCard,moveCard, …). - Persistence is swappable — and was swapped — the
DebouncedPersistenceinterface wrapslocalStoragefor the local mode; server mode adds a fetch adapter (ui/src/api/client.ts+ui/src/store/server-sync.ts) that ships the same actions to the command log without touching the reducer or the UI (optimistic updates on top of the same actions). In server mode board data is deliberately not mirrored intolocalStorage(accounts on a shared browser must not see each other's boards). - Performance — the MDXEditor description editor and the calendar are lazy-loaded on first use; vendor libraries are split into stable chunks that the service worker caches; columns, cards, insert zones and table rows are memoized, so typing in one card re-renders only its own column (or table row) — the cost per keystroke no longer grows with the board.
See ROADMAP.md for project priorities, architecture decisions and task status.
Contributing
-
Work happens in feature branches off
main—feat/<slug>,fix/<slug>orchore/<slug>; never commit tomaindirectly. Open a PR and let CI run. -
Before pushing, make sure everything is green:
-
UI unit and component tests use Vitest + React Testing Library. Backend end-to-end tests use Jest + Supertest against PostgreSQL. Browser-level Playwright coverage is tracked in ROADMAP.md under TASK-41; it is not part of the current CI workflow yet.
-
New UI strings land in both
src/locales/enandsrc/locales/rusynchronously; colors come only from the design tokens insrc/index.css. -
Change the data model, a board operation, validation or an API contract in
@janosik/sharedfirst — bothuiandbackendcompile against it. -
The backend follows the fixed stack in
ROADMAP.md§7 (NestJS/Prisma/PostgreSQL/JWT) and its iteration order. -
By submitting a pull request you agree that your contribution is licensed under the AGPL-3.0 License, the same terms as the rest of the project.
See CONTRIBUTING.md for the full guide — dev setup, the gate commands, and the required DCO sign-off (git commit -s).
License
AGPL-3.0 © 2026 Vitali Toustsik
You may use, self-host, fork and modify the code, including commercially. See LICENSE for the full AGPL-3.0 terms. In particular, if you run a modified version as a network service, the license requires you to offer its source code to the people using that service.
Trademarks. The license covers the code, not the name. "Janosik" and the feather mark identify this project; forks are welcome but must not present themselves as the official Janosik or its hosted service — see TRADEMARK.md.
Source: README.md at commit 480786a
Tools
0Version history
5- v0.5.1LatestNov 4, 2026
- v0.5.0Nov 1, 2026
- v0.4.0Oct 31, 2026
- v0.3.0Oct 30, 2026
- v0.1.3Oct 29, 2026
Score
50% of the applicable checks met
How complete this listing is, computed from the registry entry, the endpoint and public sources. Not a rating of the server and not a statement that it is safe or working today: reachability is a dated check, and no installs or reviews go into the score.
- Reached in the last 30 days25 pts
Keep the endpoint answering the MCP handshake; SourceWeft probes it every 30 days.
- Auth declared10 pts
Declare the credential headers in the registry entry, or keep the endpoint answering the probe so its auth can be classified.
- Tools listed15 pts
Answer tools/list without a credential, or ship a package that starts in a sandbox without one.
- DescriptionRequired15 pts
- Logo10 pts
- Documentation15 pts
- License10 pts