npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@intelligent-tank/kanban-plugin

v0.1.60

Published

Loop Board for OpenCode tasks, workflow revisions, routine loops, feedback, verification, recovery, and session awareness

Readme

OpenCode Kanban Board

Loop Board is a local control plane for OpenCode tasks, workflows, session routing, verification, routine loops, and self-iteration.

Quick Start

New to the board? Start with $ask-board in a coding agent. It routes you to the smallest safe next step and never guesses a board URL, execution identity, Workspace, project, or Session.

  1. Install and start the board host:

    npm install -g @intelligent-tank/[email protected]
    kanban-board --directory /path/to/workspace
  2. On an agent machine, create or reuse one execution identity, owned Workspace, and normal coding Session. Interactive setup asks for the board URL, six-digit user ID, name, and an optional Session title before changing anything:

    kanban-board-cli setup
  3. Synchronize the bundled skills, then restart the target agent:

    kanban-board-cli skills sync --agents codex,claude-code
  4. Turn a confirmed Spec into an artifact-backed Workflow with $to-cards. Review its explicit Session and dependency graph in the board, approve it, then start it. A Workflow never silently switches to a different Session.

  5. For routine operation use kanban-board-cli status and kanban-board-cli doctor; resolve permission and question waits before retrying a card. Card details, execution audit, and Recovery Center retain the loop history.

The concise step-by-step version is also available as docs/QUICKSTART.md. The remaining sections are the operator reference for deployment, storage migration, APIs, and IM bridging.

Install

npm install

npm install builds the TypeScript output and copies UI assets into dist/.

Start

Independent processes (recommended)

Run the board as the only owner of port 8765. OpenCode TUI must not load kanban-plugin/index.ts; the board talks to OpenCode Web on port 4096 through its API, so either process can restart without terminating the other.

npx kanban-board --directory /path/to/workspace --web-port 4096
cd /path/to/workspace && opencode

kanban-plugin/index.ts is now an optional, serverless bridge that only exposes the board address inside OpenCode. It never owns port 8765; omitting it leaves the TUI completely unaware of the board.

Use an existing OpenCode Web service on port 4096:

npm start -- --directory /path/to/workspace

Start OpenCode Web and the Kanban board together:

npm run start:all -- --directory /path/to/workspace

Defaults:

  • Kanban board: http://127.0.0.1:8765
  • OpenCode Web: http://127.0.0.1:4096

Useful overrides:

npm start -- --directory /path/to/workspace --kanban-port 8765 --web-port 4096
npm run start:all -- --directory /path/to/workspace --opencode-bin opencode

The connection settings modal persists the public Kanban and OpenCode Web base URLs in the board's persistent store, so other browsers and users use the same links. Environment variables remain valid startup defaults: KANBAN_PUBLIC_BASE_URL and OPENCODE_WEB_PUBLIC_BASE_URL.

The packaged browser UI can connect to a remote board before it loads API data: open kanban-plugin/ui/index.html?baseUrl=https://kanban.example.com or use ?kanbanBaseUrl=...; use ?opencodeBaseUrl=... when OpenCode Web is on another host. The same values may be injected before app.js as window.KANBAN_BASE_URL and window.OPENCODE_WEB_BASE_URL.

Storage and compatibility

Node 22.5+ uses SQLite by default at .kanban/store.sqlite. The board keeps the existing store.json format as an import and rollback source: on the first SQLite startup it is copied to .kanban/store.json.bak before import, then the records are committed in one SQLite transaction. The original JSON is never deleted. If the transaction fails, startup fails closed and the JSON remains available for a retry.

Startup migration is automatic. It is also available as an explicit, idempotent upgrade command:

npx kanban-board-migrate --directory /path/to/workspace
npx kanban-board-upgrade --directory /path/to/workspace

kanban-board-migrate only imports .kanban/store.json; kanban-board-upgrade is the operator-facing wrapper that reports the installed package version and the migration result. Both preserve store.json and store.json.bak, and both refuse to overwrite a non-empty SQLite database. The JSON result is useful for deployment logs:

npx kanban-board-upgrade --directory /path/to/workspace --json

Existing JSON-only environments remain supported with:

KANBAN_STORAGE=json npx kanban-board --directory /path/to/workspace

On Node 20, the board automatically falls back to JSON because node:sqlite is not available. The active backend and migration state are exposed in /api/config.storage. To migrate, run the command after upgrading to Node 22.5+; do not set KANBAN_STORAGE=json for that command. Trace bodies and uploaded assets remain file-backed under .kanban/traces and .kanban/artifacts; SQLite stores their metadata and task/workflow records.

Remote Board Clients

The command that starts a board (kanban-board) is local to the machine that hosts it. Commands that operate an existing board (kanban-board-cli, kanban-board-publish, kanban-board-delivery, and kanban-board-verify) can run from any agent machine. Point them at the remote board with one shared environment variable or an explicit override:

export KANBAN_BASE_URL=https://kanban.example.com
kanban-board-cli status
kanban-board-cli doctor --json
kanban-board-publish --type task --file task.json --session ses_xxx
kanban-board-delivery /absolute/path/to/SPEC.md --base-ref main --project core --workspace workspace-id --assignee agent --session ses_xxx
kanban-board-verify --base-url https://kanban.example.com

For first-time execution setup, run the CLI once with the human-provided six-digit user ID. The board host creates the default /root/<userId> directory, registers it as an owned workspace, and creates one reusable idle coding Session. This works against remote boards too, so the directory is never accidentally created on the agent's local machine:

kanban-board-cli --base-url https://kanban.example.com \
  setup --id 323017 --name 'Chen Zhongbing'

The first non-interactive setup requires --base-url; interactive setup asks for the board URL, user ID, name, and optional Session title, then requires a final confirmation. It does not invent those values. On success, it persists KANBAN_BASE_URL to ~/.config/loop-board/env (or $XDG_CONFIG_HOME/loop-board/env) for later kanban-board-cli calls. Source that file when other local tools need the same environment variable.

Use --workspace-dir /absolute/path only when the board host does not use /root. Repeating the command reuses the same bootstrap session after an SDK validation.

For a board protected by trusted-proxy identity, also set KANBAN_AUTH_USER and KANBAN_AUTH_ROLE; all four client commands forward them using the configured header names. KANBAN_PUBLIC_BASE_URL is different: it belongs on the board host and controls links rendered for browsers.

Verify

After changing the board, run the static and unit checks:

npm run typecheck
npm test -- --runInBand
npm run build

With Kanban on 8765 and OpenCode Web on 4096, verify the live self-iteration prerequisites:

npm run supervisor:dry-run
npm run verify:self-iteration -- --mutate

verify:self-iteration checks runtime config, model list, scheduler status, OpenCode Web health, self-iteration readiness, UI shell/tabs/columns, task/session/workflow API readability, active task session binding, and with --mutate creates then deletes one planned smoke task with verification criteria.

On installed npm packages, use:

npx kanban-board-verify
npx kanban-board-verify --autoinject-smoke --autoinject-timeout-ms 60000

--autoinject-smoke creates one real pending task and waits for it to be injected into OpenCode.

Package

Release notes and operational upgrade steps are packaged with the module:

Create a distributable tarball:

npm run pack:local

The generated .tgz is written to dist/.

Agent Skill

For a concise install, setup, delivery, and recovery guide, read docs/QUICKSTART.md.

The distributable includes the newcomer router ask-board, board-integrated kanban-board-agent, interactive kanban-board-cli, and to-cards skills plus the current Matt-style engineering skill set. See skills/MATT_SKILLS_MANIFEST.md for the bundled list and install order.

The helper script can publish JSON payloads:

node skills/kanban-board-agent/scripts/publish-kanban.mjs --type task --file task.json --session ses_xxx
node skills/kanban-board-agent/scripts/publish-kanban.mjs --type workflow --file workflow.json --session ses_xxx

For a Spec produced by to-cards, use the artifact-backed delivery bridge:

npx kanban-board-delivery /absolute/path/to/SPEC.md \
  --base-ref <commit> --project <project-id> --workspace <workspace-id> --assignee <user-id> \
  --session ses_xxx
npx kanban-board-delivery /absolute/path/to/SPEC.md \
  --base-ref <commit> --project <project-id> --workspace <workspace-id> --assignee <user-id> --dry-run

Changed artifacts require --confirm-revision on a later publication. Runtime inspection and recovery use the unified CLI:

npx kanban-board-cli status
npx kanban-board-cli doctor --json
npx kanban-board-cli progress <task-id>
npx kanban-board-cli permissions
npx kanban-board-cli questions
npx kanban-board-cli reply-question <question-id> --answers '[["Safe"]]'
npx kanban-board-cli logs --n 100 --module engine

The complete named-command/API matrix is in docs/KANBAN_CLI_REFERENCE.md. Every public board API has a named CLI command; kanban-board-cli api <METHOD> <PATH> is available for forward compatibility.

Feishu bridge

The optional Feishu bridge accepts Feishu event callbacks at POST /webhook/feishu. URL verification is supported, and incoming text that contains a task verb such as 创建, 实现, or 开发 becomes a board card. Task creation is deliberately explicit: set all of FEISHU_DEFAULT_SESSION_ID, FEISHU_DEFAULT_WORKSPACE_ID, and FEISHU_DEFAULT_PROJECT_ID. The assignee defaults to the workspace owner, or can be set with FEISHU_DEFAULT_ASSIGNEE_ID; it must still own the workspace. This prevents a chat message from silently selecting an unrelated Session.

Set FEISHU_VERIFICATION_TOKEN when registering the event URL. For targeted status and detail messages, configure the message service's direct sender:

export FEISHU_MESSAGE_QUEUE_URL=http://127.0.0.1:18080
export FEISHU_MESSAGE_SEND_URL="$FEISHU_MESSAGE_QUEUE_URL/zhaohu/send-message-userid" # optional when the base URL is set
export FEISHU_QUEUE_TOKEN="$MSG_QUEUE_TOKEN" # only when the service requires it
export FEISHU_QUEUE_REPLY_ID_TYPE=user_id

The board POSTs { userId, receiveIdType, message } to /zhaohu/send-message-userid. FEISHU_WEBHOOK_URL is optional and only supports the legacy group-bot fallback; it is not required for user-targeted Card or Workflow status notifications. Secrets are never returned by the board API. Every board-originated send request also carries the fixed caller header userId: 323017; the recipient remains in the JSON body. Inspect readiness with:

kanban-board-cli feishu-status
curl -X POST "$KANBAN_BASE_URL/webhook/feishu" \
  -H 'content-type: application/json' \
  -d '{"type":"url_verification","challenge":"test","token":"..."}'

For the conversation-aware sender, set the full new gateway URI instead. The receive/consume bridge preserves the inbound fromId and toId, then replies with them reversed, as { fromId: inbound.toId, toId: inbound.fromId, content }:

export FEISHU_MESSAGE_SEND_URL='https://<BASEURL>/zhaohu/sendTextMessage/client/<CLIENT_ID>'
export FEISHU_QUEUE_TOKEN="$MSG_QUEUE_TOKEN"

When using the bundled feishu_server.py as a local proxy, configure the board URL to its equivalent local path and set MESSAGE_GATEWAY_BASE_URL on that server to the external <BASEURL>. The proxy validates MsgQueueToken and forwards the opaque IDs unchanged.

The same facts are exposed as /api/integrations/feishu and under /api/config.feishu.

The standalone feishu_server.py can also be used as the inbound queue adapter. Configure FEISHU_VERIFICATION_TOKEN and register this URL in the Feishu event subscription:

https://<message-service-host>/zhaohu/message-queue/receive/<zhaohuId>

The endpoint accepts Feishu im.message.receive_v1 payloads, handles url_verification, normalizes text messages into Redis, and deduplicates retries by message_id. Consumers then call:

curl -X POST "$MESSAGE_SERVICE_URL/zhaohu/message-queue/consume/$ZHAOHU_ID"

Internal normalized producers can continue posting to the same receive endpoint with MsgQueueToken when MSG_QUEUE_TOKEN is configured.

To let the board own the local receive -> consume -> OpenCode session -> reply loop, configure the board process with:

export FEISHU_MESSAGE_QUEUE_URL=http://127.0.0.1:18080
export FEISHU_MESSAGE_QUEUE_ID=<zhaohuId>
export FEISHU_MESSAGE_QUEUE_CONSUME_URL='http://127.0.0.1:18080/zhaohu/message-queue/consume/{queueId}'
export FEISHU_QUEUE_TOKEN="$MSG_QUEUE_TOKEN"       # only when configured
export FEISHU_QUEUE_POLL_INTERVAL_MS=2000

For request-level diagnostics on the board, enable the opt-in HTTP trace in the same shell that starts kanban-board:

export FEISHU_QUEUE_DEBUG_HTTP=1
export FEISHU_QUEUE_HTTP_LOG_MAX_CHARS=12000 # optional body/response limit

This writes http.request, http.response, and http.error records to the board .kanban/engine.log. It includes the resolved URL, method, request body, response status, duration, and headers with MsgQueueToken/Authorization redacted. The standalone feishu_server.py has the equivalent MSG_QUEUE_DEBUG_HTTP=1 switch and prints the inbound queue request plus the outbound provider request/response. Keep the switches off after debugging; message text and recipients are still operational data even though credentials are masked.

The bridge starts when the queue URL and queue ID are present. It routes each message by userId to a persistent source=im OpenCode Session, creating one through the SDK when that user has no existing IM Session. The old FEISHU_QUEUE_SESSION_ID is retained only as a compatibility fallback for older deployments. readNotify messages and receipt-shaped JSON containing toId, versionId, and fromId are ignored. It checks the selected Session through the board's SDK-first runtime probe before consuming/injecting. busy, permission, question, retry, and unknown messages are retained in the board's local retry queue; the consume contract exposes no external requeue endpoint. Only an observed idle Session receives the prompt. The assistant response is then sent back to userId as the configured receiveIdType (default user_id). Use FEISHU_QUEUE_REPLY_ID and FEISHU_QUEUE_REPLY_ID_TYPE only as a fallback for internal messages without a sender.

Each complete assistant message created in that session turn is sent back as its own reply, in order, rather than waiting to merge the whole turn. Reply monitoring runs independently of consumption, so /stop or /intercept <new input> can abort an active turn immediately; the latter locally queues the new input on the same IM Session. Long individual replies are sent as ordered chunks so their tail is not silently dropped; set FEISHU_MESSAGE_MAX_CHARS to override the default 3,500-character chunk size.

Outbound messages are labeled with their source: [Kanban][IM Session], [Kanban][Card], or [Kanban][Workflow]. An IM request receives a separate start marker before the first assistant reply. FEISHU_QUEUE_TOKEN is sent as the MsgQueueToken header on consume and reply requests. The consume URL can also be edited from 系统 -> 连接配置 in the board. It is persisted as a non-secret board setting and applied without restarting the bridge; the token remains a server-only environment variable.

The same 系统 -> 连接配置 modal contains the board-wide IM notification policy: 任务状态通知 controls Card/Workflow start, complete, failed, and paused messages (and the IM-session start marker). It is enabled by default and is the only switch for those status messages. An IM Session always returns each complete assistant message in order. Card/Workflow incremental output is the per-record imNotify property, shown and editable in the Card/Workflow UI; Card detail messages are labeled [Kanban][Card][Detail] and are deduplicated by task and execution phase.

Status routing comes from the assignee's User routing (imPlatform and imChatId, falling back to imUserId and then the board userId) and is independent of the coding Session. Keep coding Sessions and conversational IM Sessions separate. The CLI/API rejects source=im execution Sessions by default; use --allow-im-session or allowImSession: true only for an explicitly conversational delivery.

New Cards and Workflows published through the API, kanban-board-cli, kanban-board-publish, or to-cards default to imNotify: false, even when bound to an IM Session. Use --im-notify or an explicit imNotify: true only after the owner has requested intermediate Card or Workflow detail pushes. --im-detail-notify and imDetailNotify remain input-only compatibility aliases for older publishers; new records do not write that property. Existing stored records are preserved.

The standalone sender accepts receiveIdType (user_id, open_id, union_id, email, or chat_id) and the queue adapter also exposes:

When the queue's userId belongs to another user system (for example 323017) rather than Feishu's receive_id, configure the mapping only in the local message service:

export FEISHU_USER_ID_MAP='{"323017":"<feishu-receive-id>"}'