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

@bosun-sh/logbook

v2.2.0

Published

File-system kanban board CLI and MCP server for AI agents

Readme

logbook — kanban for ai agents

CI npm License

logbook is a file-system kanban board for autonomous AI agents. It tracks epics, stories, tasks, and context entries across a structured lifecycle so agents and humans share a single source of truth without context bloat.

→ new here? see quickstart.md to get running in 5 minutes.

why logbook

autonomous agents work in parallel, forget context across sessions, and have no shared task state. logbook solves three problems:

  • human visibility — agents record every task they touch in a file the whole team can read and diff
  • agent coordination — task.current resolves FIFO per-session, so multiple agents can't claim the same task
  • context budget — structured JSONL with a DuckDB optional query layer lets agents find relevant records without loading the whole store

v2 adds: epics → stories → tasks hierarchy, reusable context entries (knowledge that survives across tasks), and Linear two-way sync as a first-class plugin.

quickstart

npm install -g @bosun-sh/logbook     # install the CLI
logbook init                         # scaffold .logbook/, configure MCP, optionally set up Linear
logbook task:create \
  --title "Implement login endpoint" \
  --description "JWT auth, see docs/auth.md" \
  --definition-of-done "Tests pass and endpoint is documented" \
  --project myapp --milestone v1
logbook task:list --status "*"

see quickstart.md for the full walkthrough including Linear sync.

for one-off local use, run commands through your package manager, for example npx @bosun-sh/logbook --help or bunx @bosun-sh/logbook --help.

workspace layout

logbook init creates the following structure through workspace.init:

.logbook/
├── config.json           # workspace config (Linear credentials, hook overrides)
├── workspace.json        # workspace metadata
├── hooks/
│   ├── review-spawn/     # spawns a reviewer agent on pending_review
│   │   ├── config.json
│   │   └── script.mjs
│   └── need-info-notify/ # notifies user when a task needs info
│       ├── config.json
│       └── script.mjs
└── storage/
    ├── epics.jsonl
    ├── stories.jsonl
    ├── tasks.jsonl
    ├── context-entries.jsonl
    ├── external-links.jsonl
    ├── sync-events.jsonl
    └── sync-conflicts.jsonl

add .logbook/storage/ to .gitignore to keep runtime data out of version control:

.logbook/storage/

mcp tools by plugin

connect logbook mcp as an MCP server and call any of the 38 tools below.

task plugin

| Tool ID | Purpose | |---------|---------| | task.create | Create a task in backlog | | task.get | Load one task by id | | task.list | List tasks (default status: in_progress) | | task.current | Claim and return the highest-priority in-progress task for this session | | task.update | Transition task status, add comments, reply to need_info | | task.edit | Edit mutable fields without status change | | task.assign.session | Assign a session to a task | | task.assign.model | Assign a model to a task | | task.assign.phase-model | Set a per-phase model override | | task.estimate | Compute or re-compute a Fibonacci estimation |

task.current priority chain: session-owned in_progress → unassigned in_progress → orphaned in_progress (dead session) → highest-priority todo (auto-transitions) → no_current_task error.

epic plugin

| Tool ID | Purpose | |---------|---------| | epic.create | Create an epic | | epic.get | Load one epic | | epic.list | List epics | | epic.update | Update an epic | | epic.delete | Tombstone an epic |

story plugin

| Tool ID | Purpose | |---------|---------| | story.create | Create a story within an epic | | story.get | Load one story | | story.list | List stories | | story.update | Update a story | | story.delete | Tombstone a story |

context plugin

| Tool ID | Purpose | |---------|---------| | context.create | Create a reusable context entry | | context.get | Load one context entry | | context.list | List context entries | | context.update | Update a context entry | | context.delete | Tombstone a context entry | | context.attach | Attach a context entry to an epic, story, or task | | context.detach | Remove an attachment | | context.search | Full-text search over context entries |

sync plugin (Linear)

| Tool ID | Purpose | |---------|---------| | sync.linear.pull | Pull issues from Linear into logbook (since-cursor pagination) | | sync.linear.push | Push logbook tasks to Linear | | sync.linear.setup | Configure Linear sync from a team URL or explicit ids | | sync.linear.status | Check Linear configuration and connectivity | | sync.conflicts.list | List unresolved sync conflicts | | sync.conflicts.resolve | Resolve a conflict (use_local, use_remote, or manual) |

workspace plugin

| Tool ID | Purpose | |---------|---------| | workspace.init | Initialize or re-scaffold the .logbook/ workspace | | workspace.status | Report workspace health and provider status |

hook plugin

| Tool ID | Purpose | |---------|---------| | hook.list | List registered hooks | | hook.run | Run a hook manually |

plugin plugin

| Tool ID | Purpose | |---------|---------| | plugin.list | List all registered plugins and their tool IDs |

cli

every tool is available as logbook <tool-id-with-colons>:

# preferred onboarding
logbook init
logbook init --mcp-client claude --no-linear
logbook init --mcp-client codex --no-linear

# workspace
logbook workspace:init
logbook workspace:status

# tasks
logbook task:create --title "x" --description "y" --definition-of-done "z" --project p --milestone m
logbook task:list --status "*"
logbook task:list --status in_progress
logbook task:current
logbook task:update --id <uuid> --new-status pending_review
logbook task:edit --id <uuid> --title "New title"

# epics and stories
logbook epic:create --title "Auth" --description "Login and session management" --outcome "Users can log in"
logbook story:create --epic-id <uuid> --title "JWT login" --description "..." --user-value "Users can authenticate"

# context
logbook context:create --title "Auth spec" --body "Use JWT RS256. See docs/auth.md."
logbook context:attach --context-entry-id <uuid> --task-id <uuid>

# Linear sync
logbook sync:linear:setup --team-url https://linear.app/<workspace>/team/<team>
logbook sync:linear:pull
logbook sync:linear:push --dry-run
logbook sync:linear:status

# v1 aliases (still work, emit a compatibility warning)
logbook create-task --title "..." --definition-of-done "..." --predicted-k-tokens 3
logbook list-tasks --status in_progress

logbook init --mcp-client codex writes project-local Codex MCP config to .codex/config.toml, preserving existing local TOML sections. Older global ~/.codex/config.toml Logbook entries may need manual removal.

all commands write a single-line JSON envelope to stdout:

{"ok":true,"data":{"task":{...}}}
{"ok":false,"error":{"code":"not_found","message":"task abc was not found"}}

linear integration

setup

The preferred setup path is logbook init, which prompts for Linear sync setup. To configure Linear separately:

  1. create a Linear API key at Linear → Settings → API → Personal API keys
  2. add it to .env or export it in your shell:
    echo "LINEAR_API_KEY=lin_api_..." >> .env
  3. configure Logbook from your Linear team URL:
    logbook sync:linear:setup --team-url https://linear.app/bosun/team/BOSUN

The setup command resolves the workspace and team ids and writes the public config to .logbook/config.json. It never writes the API key there. To let setup write .env for you, pass the token once:

logbook sync:linear:setup \
  --team-url https://linear.app/bosun/team/BOSUN \
  --api-token lin_api_... \
  --write-env

Manual setup is also supported:

logbook sync:linear:setup \
  --workspace-id <workspace-id> \
  --team-id <team-id>

This produces a linear block like:

{
  "linear": {
    "apiTokenEnv": "LINEAR_API_KEY",
    "workspaceId": "your-workspace-id",
    "defaultTeamId": "your-team-id"
  }
}

pull / push

when Logbook runs through MCP, task-facing tools automatically pull before the call and push successful task writes back to Linear. the explicit commands below are still available for manual refreshes, dry runs, and targeted syncs.

# pull issues from Linear since the last cursor
logbook sync:linear:pull

# pull with options
logbook sync:linear:pull --dry-run --team-id <id>

# push logbook tasks to Linear
logbook sync:linear:push

# push only specific tasks
logbook sync:linear:push --task-ids '["task_abc","task_xyz"]' --dry-run

# check status (connectivity + cursor position)
logbook sync:linear:status --check-provider

conflicts

when the same record is modified in both logbook and Linear, a conflict entry is written to sync-conflicts.jsonl:

logbook sync:conflicts:list
logbook sync:conflicts:resolve --id <conflict-uuid> --resolution use_local
# resolutions: use_local | use_remote | manual

conflict states: open → resolved or ignored.

external links

bidirectional linear:<id> mappings are stored in external-links.jsonl and updated automatically by pull/push.

hooks

hooks execute shell commands on task lifecycle events. configuration lives in .logbook/hooks/<id>/config.json:

{
  "id": "need-info-notify",
  "event": "task.status_changed",
  "condition": { "status": "need_info" },
  "command": ["node", ".logbook/hooks/need-info-notify/script.mjs"],
  "timeoutMs": 5000
}

two hooks are materialized by workspace.init:

  • need-info-notify — prints the blocking comment when a task moves to need_info
  • review-spawn — creates a review task and spawns a reviewer agent when a task moves to pending_review

hooks are stateless — execute and forget. the command field is an argv array; no shell expansion is performed.

environment variables

| Variable | Default | Description | |----------|---------|-------------| | LOGBOOK_WORKSPACE_ROOT | process.cwd() | workspace root used by the compiled binaries | | LOGBOOK_LOG_LEVEL | warn | log level: debug, info, warn, error | | LINEAR_API_KEY | — | Linear API token (or the env var named in linear.apiTokenEnv) |

optional duckdb index

logbook uses @duckdb/node-api to run ad-hoc SQL over the canonical JSONL files. the index is in-memory — no separate index file is written or maintained:

-- example: find all in_progress tasks for a specific project
SELECT id, title, status FROM read_json_auto('.logbook/storage/tasks.jsonl', format='newline_delimited')
WHERE status = 'in_progress' AND project = 'myapp'

the DuckDB path is opt-in via workspace.status and is non-canonical — the JSONL files remain the source of truth.

migrating from v1

if your project has a tasks.jsonl at the repository root, workspace.init detects it and migrates all records to .logbook/storage/tasks.jsonl automatically:

  • field names renamed from snake_case to camelCase
  • kind: "task" injected on every record
  • v1 comment shape converted to v2 shape

v1 CLI commands (create-task, list-tasks, current-task, update-task, edit-task, init) remain registered and emit a compatibility_mapping_applied warning. remove the deprecated commands from your scripts when ready.

see CHANGELOG.md for the full v2.0.0 breaking-change list.

stack

  • runtime: Node.js / TypeScript
  • effect system: Effect.ts — all async operations and errors modeled as Effect<A, E, R>
  • architecture: ohtools plugin registry, hexagonal adapters (CLI + MCP), vertical slices per entity
  • persistence: JSONL — append-only, one record per line, full-scan reads; DuckDB for optional ad-hoc queries
  • validation: Zod at every public boundary (MCP input, CLI flags, filesystem reads)

contributing

See CONTRIBUTING.md for setup instructions, the CI gate to run before a PR, and the Conventional Commits message format required.

license

Apache-2.0

For retries after a lost mutation response, see durable operation identities, including receipt lookup and recovery limits.