Janosik

io.github.VitalyTolstik由 GitHub 账号 VitalyTolstik 发布v0.5.1更新于 Nov 4, 2026

Drive a Janosik Kanban board from any MCP client: ready work, leases and task specs.

已验证STDIO仅桌面效率与工作流开发者工具

概览

AI 生成的概览

让 AI 客户端连接自托管的 Janosik 看板,读取并修改看板、列、卡片、检查清单和评论。

可以做什么
  • 处理看板、列和卡片:创建、编辑、移动、归档和搜索
  • 管理标签、检查清单、卡片链接、评论、活动记录和附件
  • 可选工具集提供成员、邀请、分享链接和账户操作
  • 写入与网页界面共用同一命令日志,因此可撤销,并实时同步给其他看板成员
适用场景
适合团队把工作放在自托管 Janosik 看板上,并希望由智能体领取待办任务、以限时租约认领卡片、维护任务说明与检查清单,或在受阻时报告而不是直接标记完成。
运行要求
需要以服务器模式运行的 Janosik 实例,以及在应用内创建的个人 API 密钥(JANOSIK_TOKEN,以 jnk_ 开头)。需设置 JANOSIK_URL 为实例地址;仅当应用不在站点根路径时才需 JANOSIK_APP_BASE。通过 npx 本地运行,需要 Node.js。
安装前请注意
该 API 密钥可访问其授权范围内的看板数据;建议为每个智能体单独创建账户和密钥,便于单独吊销。不需要写入时应优先使用限定单个看板且只读的密钥。这些工具可创建、编辑、移动、归档和删除看板内容,改动对其他成员可见。

安装

在 SourceWeft 中

  1. 打开 控制台中的 Janosik,将其添加到工作区。
  2. 为需要使用其工具的对话启用该服务。

Desktop only,通过 STDIO。 STDIO 服务会启动本地进程,因此需要 SourceWeft 桌面宿主。

其他 MCP 客户端

参照 仓库 中的启动说明。

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 same boardReducer. 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.

Workspacenpm nameWhat it isHow it runs
ui/@janosik/uiThe frontend: the whole single-page app — board/calendar/table/watch views, drag & drop, card dialog, search, settings, i18n, PWA service worker, the login screen and the /admin master panel. It talks to the backend over fetch.Vite dev server (npm run dev) or is served as static files from ui/dist
shared/@janosik/sharedA TypeScript library with no build step and no runtime of its own: the domain model (Board/Column/Card/Label), the pure boardReducer (the single implementation of every board operation), its inverse for undo, command validation, export/import serialization, storage keys — plus the typed API contracts (user and admin DTOs).Nothing to run. ui and backend import its .ts sources directly through aliases, so client and server literally share the same types and the same reducer logic
backend/@janosik/backendThe server: a NestJS API on PostgreSQL — auth (JWT + refresh rotation + argon2id), boards/members, the command log that persists UI actions, comments/activity, and the isolated master-admin contour (/api/v1/admin/*).Node process (npm run build:backend + npm run start -w backend); dev DB via Docker Compose
brand/@janosik/brandShared brand assets and design tokens.Imported by the UI and site; has its own tests and lint script.
site/@janosik/siteAstro marketing site and Starlight documentation, with English and Russian content.npm run dev:site or npm run build:site.
video/@janosik/videoRemotion scenes and scripts for recording and rendering product clips.npm run studio -w video or npm run render -w video.
mcp/@janosik/mcpMCP server that lets compatible AI clients work with Janosik through scoped API keys.npm run dev -w mcp, or use the published @janosik/mcp package.

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.

text
janosik/                        # npm workspaces root (one package-lock.json)├─ ui/                          # @janosik/ui — the React PWA (see tree below)├─ shared/                      # @janosik/shared — the domain library│  └─ src/│     ├─ types/kanban.ts        # Board / Column / Card / Label + LIMITS│     ├─ store/│     │  ├─ board-reducer.ts    # the pure reducer — every board action│     │  ├─ invert.ts           # inverse actions for undo/redo│     │  ├─ validate.ts         # strict command validator (both sides)│     │  ├─ migrate.ts          # persisted-state migrations│     │  └─ seed-data.ts        # demo "Product Launch" board│     ├─ utils/                 # export/import envelope, limits, text, storage keys│     ├─ api.ts                 # user API DTOs (auth, boards, commands…)│     └─ admin.ts               # admin API DTOs (users, boards, cards, masters…)├─ backend/                     # @janosik/backend — the NestJS API│  ├─ prisma/                   # schema.prisma + versioned migrations│  ├─ src/                      # auth/ boards/ commands/ comments/ activity/│  │                            # admin/ users/ health/ config/ (+ shared → ../../shared/src)│  ├─ test/                     # Jest + Supertest e2e specs (real test DB)│  ├─ scripts/                  # admin-cli.cjs, migrate-test-db.cjs│  ├─ docker-compose.yml        # dev PostgreSQL 16 (janosik + janosik_test)│  └─ .env.example├─ brand/                       # @janosik/brand — shared brand assets and tokens├─ site/                        # @janosik/site — marketing site and documentation├─ video/                       # @janosik/video — product demo clips├─ mcp/                         # @janosik/mcp — the MCP server: the board as agent tools│  ├─ src/                      # client + 13 tool groups (71 tools), toolset gating│  ├─ server.json               # MCP Registry metadata (published as io.github.vitalytolstik/janosik)│  └─ scripts/smoke.mjs         # live smoke test against a running instance├─ skills/janosik/              # workflow guidance for AI agents using the MCP tools│  ├─ SKILL.md                  #   the instructions a harness loads│  └─ references/               #   card/comment templates + lifecycle recipes├─ deploy/nginx.conf            # optional SPA fallback + /api proxy (single-image serving is built in)├─ Dockerfile                   # multi-stage: builds UI + API into one self-host image├─ docker-compose.yml           # self-host stack: app + postgres + redis├─ docker-entrypoint.sh         # runs `prisma migrate deploy`, then the API├─ .env.example                 # annotated environment for docker compose├─ SECURITY.md / CHANGELOG.md   # disclosure policy, release history├─ LICENSE / TRADEMARK.md       # AGPL-3.0 terms + brand/trademark policy├─ docs/SELF-HOSTING.md         # full self-hosting guide (TLS, backups, ops)├─ docs/INSTALL-BY-OS.md        # running it on macOS / Windows 11 / Linux├─ ROADMAP.md                   # project priorities, architecture decisions and task status├─ ROADMAP-DONE.md              # archive of closed tasks└─ AGENT.md                     # working agreement for AI agents/contributors

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 design toggle 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 / and Ctrl/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/k cursor navigation, n/c composers, e/Enter edit.
  • 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/events SSE 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 a VIEWER gets 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 /admin area 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); OWNER can add more masters, OPERATOR cannot. 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/mcp gives compatible clients (Claude, Cursor, VS Code, opencode and Codex) access to board tools through a personal API key. The janosik skill 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

LayerChoice
UIReact 18, TypeScript 5.9 (strict)
BuildVite 8 (Rolldown), Tailwind CSS v4 (CSS-first, @theme inline)
Componentsshadcn/ui + Radix primitives (dialog, dropdown, popover, tooltip, slot)
Rich text@mdxeditor/editor (WYSIWYG description, hardened import pipeline)
Drag & drop@dnd-kit/core + @dnd-kit/sortable (board), native HTML5 DnD (calendar)
Calendarreact-day-picker (lazy-loaded, locale on demand), date-fns
StateReact useReducer (pure reducer in shared, 30+ actions) + context
Routerreact-router-dom (BrowserRouter, /board/:id, ?card= deep links; SPA-fallback: deploy/nginx.conf)
PWAHand-rolled service worker + web manifest (zero extra deps)
i18ni18next, react-i18next, i18next-browser-languagedetector
Fonts@fontsource/space-grotesk (self-hosted, no CDN)
Shared@janosik/shared — domain model, reducer + inverse, validation, DTO contracts (imported as TS source, no build step)
BackendNestJS 11, Prisma 6, PostgreSQL 16, JWT (@nestjs/jwt) + refresh rotation, argon2id, helmet, rate limiting
TestsVitest + React Testing Library (UI, shared, brand, site and MCP); Jest + Supertest (backend unit and API end-to-end tests against PostgreSQL)

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:

bash
# 1. Configure the API FIRST — the dev compose file reads POSTGRES_* from#    backend/.env, so it must exist before `docker compose up`.cp backend/.env.example backend/.env#    set JWT_SECRET (openssl rand -hex 32); DATABASE_URL/TEST_DATABASE_URL#    already point at the container.
# 2. Start the dev database (container `janosik-postgres`, port 5433)docker compose -f backend/docker-compose.yml up -d
# 3. Apply migrations and build + start the API (port 3000)npm run prisma:deploy -w backendnpm run build:backendnpm run start -w backend
# 4. In a second terminal, start the UI; Vite proxies /api to :3000npm run dev

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 in localStorage. The npm run dev / npm run build builds 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:

bash
npm run dev:site                 # Astro dev server, default port 4321

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:

bash
PUBLIC_APP_URL=http://localhost:5173 npm run dev:site

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):

bash
VITE_SITE_URL=http://localhost:4321/ npm run dev

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 apikey as 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:

bash
docker run -d --name janosik-mailpit --restart unless-stopped -p 1025:1025 -p 8025:8025 axllent/mailpit# open http://localhost:8025, or click "Open the inbox" in the panel

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.

bash
# 1. Grab the compose file and the env templatecurl -O https://raw.githubusercontent.com/VitalyTolstik/janosik/main/docker-compose.ymlcurl -o .env https://raw.githubusercontent.com/VitalyTolstik/janosik/main/.env.example
# 2. Edit .env — at minimum JWT_SECRET and PUBLIC_ORIGIN:#    JWT_SECRET=$(openssl rand -hex 32)#    For this plain-HTTP quickstart also set COOKIE_SECURE=false (the safe#    default is true; over HTTP the API refuses to boot rather than drop the#    refresh cookie). Behind HTTPS keep it true.
# 3. Bring it up (migrations run automatically on boot)docker compose up -d
# 4. Open PUBLIC_ORIGIN (default http://localhost:3000), create the first#    account, then set ALLOW_REGISTRATION=false in .env and `docker compose up -d`

Create a master (platform admin) account for the /admin panel — the CLI is the only door, there is deliberately no HTTP endpoint for it:

bash
docker compose exec app node backend/scripts/admin-cli.cjs create --email [email protected]# (hidden password prompt; the first master becomes OWNER)docker compose exec app node backend/scripts/admin-cli.cjs list# then sign in at PUBLIC_ORIGIN/admin

Upgrade and back up:

bash
docker compose pull && docker compose up -d          # new image, schema migrated on bootdocker compose exec postgres pg_dump -U janosik janosik > backup.sql# restore: docker compose exec -T postgres psql -U janosik janosik < backup.sql

Environment variables (see .env.example for the full annotated list):

VariableDefaultMeaning
JWT_SECRET— (required)Access-token signing secret; openssl rand -hex 32
PUBLIC_ORIGINhttp://localhost:3000Public URL users open; builds OAuth callbacks
POSTGRES_USER / POSTGRES_PASSWORD / POSTGRES_DBjanosik / — / janosikDatabase credentials
COOKIE_SECUREtrueSecure cookie flag. Keep true behind HTTPS (the API refuses to boot on HTTP in production); set false only for a plain-HTTP trial.
ALLOW_REGISTRATIONtrueOpen sign-up; turn off after creating your account
TRUST_PROXY0Reverse-proxy hops (set 1 behind nginx/Caddy/Traefik)
SMTP_*unsetOutgoing email. Unset = log mode; in production codes are withheld from the log, so configure SMTP to deliver them.
PURGE_AFTER_DAYS30Retention for the hourly soft-delete sweep
AUDIT_RETENTION_DAYS365Retention for the master audit trail (separate, longer window)
DB_CONNECTION_LIMIT10Prisma pool size per API process (keeps replicas under max_connections)
SLOW_QUERY_MS200Log Prisma queries slower than this (0 = off)
POSTGRES_SHARED_BUFFERS256MBPostgres shared_buffers for the bundled container
POSTGRES_WORK_MEM8MBPostgres work_mem for the bundled container
POSTGRES_MAX_CONNECTIONS100Postgres max_connections for the bundled container

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).

bash
# 1. Interactive (recommended) — the password is typed at a hidden prompt#    twice (it must match), nothing lands in the shell history.npm run admin:create -w backend -- --email [email protected]# Password: ********# Repeat password: ********# Master account created: [email protected] (owner)   ← first master ⇒ OWNER
# 2. Non-interactive (CI/automation) — password via environment, never argv.#    `read -s` keeps it out of the shell history too.read -s ADMIN_PASSWORD && export ADMIN_PASSWORDnpm run admin:create -w backend -- --email [email protected]unset ADMIN_PASSWORD
# 3. Explicit role and display name: --owner makes this master an OWNER#    (without it a second master is created as OPERATOR).npm run admin:create -w backend -- --email [email protected] \  --display-name "Ops" --owner
# 4. Re-key an existing master: sets a new password, revokes every session#    of that master and clears any lockout. Same password rules.npm run admin:passwd -w backend -- --email [email protected]
# 5. Who exists: email, role, display name, last login, disabled/locked#    flags. No secrets are ever printed.npm run admin:list -w backend# [email protected]  owner  -  never logged in
# Full reference, straight from the CLI:npm run admin:create -w backend -- --help

Rules worth knowing:

  • Password: 8–100 characters. There is deliberately no --password flag — a password in argv leaks into ps output and shell history. Without a TTY and without ADMIN_PASSWORD the CLI refuses to run.
  • Role: the first master in an empty database becomes OWNER automatically; every later CLI master is OPERATOR unless --owner is 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 AdminAuditLog row (via: "cli"), visible on the panel's Audit page.
  • Sign in at http://localhost:5173/admin (dev) or https://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 reserved agent:* 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

json
{  "mcpServers": {    "janosik": {      "command": "npx",      "args": ["-y", "@janosik/mcp"],      "env": {        "JANOSIK_URL": "https://boards.example.com",        "JANOSIK_TOKEN": "jnk_…"      }    }  }}

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:

CommandWhat it does
npm run devUI dev server (npm run dev -w ui; default port 5173, proxies /api to :3000)
npm run dev:siteMarketing site + docs dev server (npm run dev -w site; Astro, default port 4321)
npm run build:siteBuild the Astro site (site/dist)
npm run build:mcpBuild the MCP server (mcp/dist)
npm run buildType-check + build the UI (ui/dist)
npm run build:backendPrisma generate + compile the API (backend/dist)
npm run previewServe the built UI locally
npm testVitest suites for UI, shared, brand, site and MCP (not backend)
npm run test:backendBackend Jest unit + e2e (e2e creates/migrates janosik_test first)
npm run test:coverageVitest coverage for UI, shared and brand
npm run lintESLint in all seven workspaces
npm run format / format:checkPrettier write / verify (repo-wide)
npm run sizesize-limit budgets for the UI bundle (entry, lazy chunks, admin chunk)

Workspace-specific extras worth knowing:

CommandWhat it does
npm run start -w backendRun the built API (node backend/dist/main.js); applies pending migrations first
npm run prisma:deploy -w backendApply Prisma migrations to DATABASE_URL (without starting)
npm run admin:create -w backend / npm run admin:passwd -w backend / npm run admin:list -w backendMaster-account CLI (see above)
npm run test:watch -w uiVitest in watch mode

Project structure (UI workspace in detail)

text
ui/├─ public/                  # PWA: manifest, icons├─ src/│  ├─ admin/                # master panel (/admin): pages, admin-client, i18n, fake API│  ├─ api/                  # fetch client (tokens, auth-lost callback, keepalive commands)│  ├─ auth/                 # AuthContext (session, login/register/logout)│  ├─ components/│  │  ├─ board/             # Columns, cards, card dialog, filters, views (board/calendar/table/watch)│  │  ├─ auth/              # LoginPage, logout confirmation│  │  ├─ account/           # personal panel: profile, password, API keys, preferences│  │  ├─ editor/            # MDXEditor description editor (plugins, code blocks, i18n)│  │  └─ ui/                # shadcn/ui + Radix primitives│  ├─ hooks/                # theme, board background, column glass, card labels│  ├─ i18n/                 # i18next setup (keys typed from the EN catalog), time format│  ├─ locales/              # en/ru translation.json│  ├─ pwa/                  # service worker + its registration (production only)│  ├─ store/                # BoardContext, history, server-sync, persistence adapters│  ├─ types/                # UI-only types (domain model lives in @janosik/shared)│  ├─ utils/                # storage, persistence, backups, serialization, dnd, filter, due dates│  ├─ App.tsx               # Provider tree + layout (+ lazy /admin route)│  ├─ main.tsx              # Theme preflight + SW registration + entry point│  └─ index.css             # Design tokens (Tailwind v4 @theme)├─ vite/                    # Build plugins (service worker emit + cache version)├─ index.html├─ vite.config.ts├─ vitest.config.ts└─ package.json

Architecture (30 seconds)

  • Normalized data model — a Board holds ordered Column[], a Record<string, Card> and Label[]. Reordering = reordering id arrays. Archived cards stay in the map with archivedAt and are dropped from column.cardIds until 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 — BoardProvider owns 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 DebouncedPersistence interface wraps localStorage for 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 into localStorage (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

  1. Work happens in feature branches off main — feat/<slug>, fix/<slug> or chore/<slug>; never commit to main directly. Open a PR and let CI run.

  2. Before pushing, make sure everything is green:

    bash
    npm run lintnpm run format:checknpm testnpm run test:backend   # needs the PostgreSQL test database runningnpm run buildnpm run size
  3. 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.

  4. New UI strings land in both src/locales/en and src/locales/ru synchronously; colors come only from the design tokens in src/index.css.

  5. Change the data model, a board operation, validation or an API contract in @janosik/shared first — both ui and backend compile against it.

  6. The backend follows the fixed stack in ROADMAP.md §7 (NestJS/Prisma/PostgreSQL/JWT) and its iteration order.

  7. 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.

来源:README.md,提交 480786a

工具

0
SourceWeft 曾在隔离沙箱中以无凭据方式启动该软件包一次,以列出其工具,但未能完成:服务器未能启动。

版本历史

5
  1. v0.5.1最新Nov 4, 2026
  2. v0.5.0Nov 1, 2026
  3. v0.4.0Oct 31, 2026
  4. v0.3.0Oct 30, 2026
  5. v0.1.3Oct 29, 2026

评分

已满足适用检查项的 50%

该评分衡量此收录条目的完整程度,依据注册中心条目、端点与公开来源计算得出。它不是对服务器本身的评价,也不表示服务器安全或当前可用:可连通性是带日期的检查结果,评分也不包含安装量或用户评价。

  • 近 30 天内可连通25 分

    请保持端点能够响应 MCP 握手;SourceWeft 每 30 天探测一次。

  • 已声明认证方式10 分

    请在注册中心条目中声明凭据请求头,或保持端点能够响应探测,以便判定其认证方式。

  • 已列出工具15 分

    请让服务器在无凭据时响应 tools/list,或发布可在沙箱中无凭据启动的软件包。

  • 描述必需15 分
  • 图标10 分
  • 文档15 分
  • 许可证10 分