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

task-pigeon

v0.2.63

Published

Small local task queue CLI backed by SQLite.

Downloads

8,038

Readme

Pigeon 🐦

Pigeon is a small local task queue CLI for coordinating work across people and coding agents.

It stores tasks in a project-local SQLite database, so everyone running Pigeon from the same repo can share a queue without a server, account, daemon, or hosted project tracker.

CLI -> small command functions -> Drizzle -> SQLite

Pigeon is intentionally boring: tasks, claims, notes, blockers, done.

Why Pigeon? ✨

Agent coordination usually fails in small, annoying ways: two agents claim the same work, blocked tasks disappear from view, context lives in chat scrollback, or each checkout quietly creates a separate queue.

Pigeon keeps the coordination surface tiny:

  • 🗂️ project-local SQLite by default.
  • 🙋 explicit task claiming with optional owner requirements.
  • 💬 tiny message board for cross-agent coordination.
  • 🔗 URLs and notes built into the happy path.
  • 🚧 blocked work stays visible in the default queue.
  • 🧾 readable responsive output for terminals of different sizes.
  • 🛠️ config when you need policy, defaults when you do not.

Install 🚀

Pigeon requires Bun >=1.3.14.

Run it without installing:

bunx --bun task-pigeon@latest status

Install it globally for repeated use:

bun add --global task-pigeon
pigeon status

Update a global install:

bun update --global task-pigeon

Direct bunx installs from Git URLs are not supported. Use the npm package.

Quick Start ⚡

Run Pigeon from the project directory that should own the queue:

cd ~/Code/my-project
pigeon init
pigeon config --by andrew
pigeon doctor
pigeon whoami
pigeon status

Add work with enough context for the next person or agent:

pigeon add "Fix failing publish" \
  --url https://github.com/andrew-bierman/pigeon/issues/3 \
  --note "trusted publishing failure" \
  --priority high \
  --labels release,npm

List and claim work:

pigeon list
pigeon claim --by codex
pigeon claim 8 --by claude

Update task state:

pigeon update 8 --note "OIDC configured; waiting on npm" --priority urgent
pigeon block 8 --note "waiting on npm account setting" --blocked-by npm
pigeon release 8
pigeon done 8

Watch the queue:

pigeon watch
pigeon monitor --by codex
pigeon monitor --by codex --once # one-shot output for scripts
pigeon monitor --by codex --mentions-only
pigeon monitor --by codex --messages unread
pigeon monitor --by codex --messages all --all-messages
pigeon monitor --by codex --hide-status --hide-tasks
pigeon monitor --by codex --compact
pigeon monitor --by codex --output table
pigeon wait --by codex
pigeon wait --by codex --mentions-only
pigeon wait --by codex --timeout 300000
pigeon watch --all
pigeon watch --status pending --interval 500
pigeon list --status pending,blocked
pigeon list --status active

Monitor interactivity:

Monitor runs as a tiny interactive dashboard in TTY terminals.
In non-interactive sessions it stays in plain text and auto-refreshes like before.

[↑/k] move          [tab] switch pane
[enter] detail      [esc/backspace/left] back from detail
[c] claim            [d] done         [r] release
[a] ack message      [z] resolve message
[e] reply message
[n] new message
[g] jump to top       [h] toggle help overlay
[t] task section     [m] message section  [s] status section
[p] pause refresh    [f] force refresh    [q] quit

While the monitor is open, press n to write and send a coordination message inline. Messages accept normal @mentions, so you can keep the conversation on the same screen without dropping back to a separate command. Press e on a selected message to reply directly to the original author.

The monitor keeps a visible control bar near the top so it is obvious whether you are browsing, in detail, or composing. Detail mode backs out with Esc, Backspace, or left arrow, and the expanded help overlay stays available with h.

By default, list and watch show active tasks: pending, claimed, and blocked. Use --all to include done, --status done to inspect completed work, or CSV filters like --status pending,blocked. --status active is shorthand for pending,claimed,blocked.

monitor hides resolved messages by default. Add --all-messages when you explicitly want resolved message history on the screen.

Use monitor visibility flags when you want a focused screen:

pigeon monitor --compact
pigeon monitor --hide-status
pigeon monitor --hide-tasks
pigeon monitor --hide-messages

Use wait when an agent is idle, blocked, or waiting for another counterpart. It exits when visible tasks or watched messages change, then the agent should re-run status, list, and unread messages.

pigeon wait --by codex
pigeon wait --by codex --messages unread --timeout 300000

Leave a message for other agents:

pigeon message add "@claude Codex is checking release automation" --by codex
pigeon message add "Please review the release notes" --by codex --to claude
pigeon message list --mentioned claude
pigeon message list --by claude --unread
pigeon message ack 1 --by claude
pigeon message resolve 1

Shared Queues 🤝

By default, Pigeon stores data at .pigeon/pigeon.db under the shared project root for the current checkout. Nested worktrees join that same queue unless you explicitly opt into worktree-local mode.

Pigeon discovers the project root from Git metadata, so this works from any Git repository and from any nested directory. Linked worktrees resolve their shared Git root automatically; no package.json or Pigeon-specific project setup is required.

Always check the active queue before claiming:

pigeon status

To find stale queues in the current project or linked worktrees:

pigeon db list

This reports each discovered database with task and message counts. It does not scan unrelated directories or the whole disk.

To combine an old worktree queue into the active queue, preview first and then apply:

pigeon db merge --from .worktrees/pr-1116/.pigeon/pigeon.db
pigeon db merge --from .worktrees/pr-1116/.pigeon/pigeon.db --apply

The source database is never modified. New tasks and messages carry a short stable key, so merges match the same record even when mutable fields change. Older databases and snapshots fall back to exact-content matching, while conflicting local IDs are remapped and message read state is preserved.

Numeric IDs remain local SQLite keys for simple commands. Show the stable task keys when you need to compare or document records across databases:

pigeon list --columns id,uid,status,title

To share a queue across directories or machines with a synced path, set PIGEON_DB:

PIGEON_DB=~/tasks/my-project.pigeon.db pigeon status
PIGEON_DB=~/tasks/my-project.pigeon.db pigeon list

Agents should use the same project directory or the same PIGEON_DB; otherwise they will create separate queues.

Snapshots 📦

Need a quick backup or a way to move a queue to another machine? Use a JSON snapshot of the current local database:

pigeon snapshot export --file pigeon.snapshot.json
pigeon snapshot import --file pigeon.snapshot.json

Snapshot commands act on the local SQLite queue. If you have remote mode configured in your shell, set PIGEON_LOCAL_ONLY=1 first so the command stays on the local database.

Why is remote mode unexpectedly enabled?

pigeon uses this precedence for remote settings:

  • PIGEON_URL / PIGEON_TOKEN environment variables
  • project config (.pigeon/config.json in the current directory)
  • user config ($XDG_CONFIG_HOME/pigeon/config.json)
  • package defaults

If a command unexpectedly calls a remote server, check the resolved value:

pigeon whoami
pigeon config --show
env | rg '^PIGEON_'

To clear a stale remote configuration quickly:

pigeon config --clear-remote-url --clear-remote-token

For a clean local session, isolate both DB and config:

TMP_CONFIG=$(mktemp -d)
PIGEON_DB=.tmp/pigeon.db XDG_CONFIG_HOME=$TMP_CONFIG pigeon status

Private Remote 🌐

When another computer needs the same queue, the boring option is to run one Pigeon server next to the SQLite file and connect over a private network such as Tailscale.

Server:

PIGEON_TOKEN=secret pigeon serve \
  --host 100.x.y.z \
  --port 8787 \
  --db /data/pigeon/my-project.db

Client:

pigeon config --remote-url http://100.x.y.z:8787 --remote-token secret
pigeon status
pigeon list
pigeon claim --by andrew

Environment overrides work well for temporary sessions:

PIGEON_URL=http://100.x.y.z:8787 PIGEON_TOKEN=secret pigeon monitor --by codex

Remote mode is command-level HTTP, not SQL-over-HTTP. The client sends fixed Pigeon operations such as listTasks or claimTask; the server owns Drizzle, SQLite, migrations, and locking. The private API is implemented with Elysia and Eden Treaty for a typed client/server contract. That keeps the system as one SQLite writer without introducing sync conflict rules.

Use pigeon remote for examples. Use pigeon whoami to see whether the current shell is pointed at a remote server.

Clear remote config:

pigeon config --clear-remote-url --clear-remote-token

Messages 💬

Messages are for coordination context that should not become a task: “I am editing the README,” “Claude is handling issue #12,” “do not publish until CI is green.”

pigeon message add "@codex Claude is reviewing the table output" --by claude
pigeon message add "Please check the package metadata" --by claude --to codex
pigeon message reply 3 "I checked it" --by codex
pigeon message list
pigeon message list --mentioned codex
pigeon message list --by codex --unread
pigeon message ack 3 --by codex
pigeon message resolve 3
pigeon message list --all

Mentions can come from @name in the message body or from --to name. Use comma-separated names for multiple counterparts: --to codex,claude.

Read state is per agent name. If Codex acknowledges a message, it is still unread for Claude until Claude acknowledges it too.

The sender should usually clean up the message. If you post a message for Claude, check Claude's view with pigeon message list --by claude; once Claude has acknowledged or acted on it, resolve the message so it leaves everyone's monitor.

Resolved messages are hidden from normal message lists and monitors for everyone. Use ack for “I read this”; use resolve for “this no longer belongs on the live board.” Use pigeon message list --all to inspect resolved message history.

pigeon status --by codex includes Codex's unread message count.

Identity 🪪

Pigeon identity is casual local config, not real sign-in. It is just the default value for commands that accept --by, which keeps repeated agent commands shorter and makes monitors easier to read.

pigeon config --by andrew
pigeon config --user --by codex
pigeon whoami
pigeon status
pigeon claim
pigeon message add "@claude I am taking the npm publish task"

Clear it when you want commands to require explicit names again:

pigeon config --clear-by

Environment overrides are useful for one-off agent sessions:

PIGEON_BY=claude pigeon monitor --mentions-only

Agent Workflow 🤖

Recommended loop:

pigeon status
pigeon list --output normal
pigeon claim --by codex
pigeon update 12 --note "Investigating failing publish workflow"
pigeon block 12 --note "waiting on npm trusted publishing"
pigeon wait --by codex
pigeon done 12

Use release when you claimed the wrong task or need to put work back in pending.

Input validation is deliberately strict where it prevents coordination mess:

  • add requires a non-empty title.
  • provided URLs must be valid URLs.
  • priority must be low, normal, high, or urgent.
  • labels are stored as trimmed, deduped CSV.
  • block requires a non-empty note.
  • blank optional url, note, or labels values clear that field.

Output 📋

list and watch use responsive auto output by default. When URLs or notes are visible, auto uses a readable list so links stay intact while titles and notes wrap with the terminal.

Default columns:

id,status,title,url,claimedBy,updatedAt

Use uid as an optional stable task key. It is intentionally not in the default columns so normal output stays compact.

Optional task metadata:

pigeon add "Polish release docs" --priority high --labels docs,release
pigeon update 12 --priority urgent --labels ci,npm
pigeon block 12 --note "waiting on package access" --blocked-by npm

For full readable links and notes, you can force normal list output:

pigeon list --output normal
pigeon watch --output normal

Choose columns for one run:

pigeon columns
pigeon list --columns id,status,priority,title,url,labels,blockedBy,note,claimedBy,updatedAt
pigeon watch --columns id,status,priority,title,url,labels,blockedBy,note,claimedBy,updatedAt

Force a compact grid:

pigeon list --output table

Valid columns:

id,status,priority,title,url,claimedBy,blockedBy,labels,note,createdAt,updatedAt,claimedAt,blockedAt,doneAt

Valid output modes:

auto,table,normal

Configuration ⚙️

Configuration precedence:

defaults < user config < project config < PIGEON_BY/PIGEON_URL/PIGEON_TOKEN/PIGEON_LOCAL_ONLY/PIGEON_WORKTREE_LOCAL/PIGEON_COLUMNS/PIGEON_OUTPUT/PIGEON_REQUIRE < CLI flags

PIGEON_LOCAL_ONLY=1 disables remote mode for that shell and forces local DB/queue behavior, even if user/project config already has a remote URL. PIGEON_WORKTREE_LOCAL=1 opts into per-worktree queue isolation when you intentionally want a separate board in each checkout.

Project config lives next to the active database at .pigeon/config.json. User config lives at $XDG_CONFIG_HOME/pigeon/config.json, or ~/.config/pigeon/config.json when XDG_CONFIG_HOME is not set.

Config files are JSON with a top-level "version": 1. Older unversioned config files are treated as v1, and Pigeon writes the version on the next config save. Pigeon intentionally does not use executable TypeScript config.

Show effective config, paths, and sources:

pigeon config --show

Set project defaults:

pigeon config --by codex
pigeon config --columns id,status,priority,title,url,labels,note,claimedBy,updatedAt --output normal

Set user defaults:

pigeon config --user --by andrew
pigeon config --user --columns id,status,priority,title,url,labels,note,claimedBy,updatedAt --output normal

Use environment overrides:

PIGEON_BY=claude pigeon status
PIGEON_URL=http://100.x.y.z:8787 PIGEON_TOKEN=secret pigeon status
PIGEON_COLUMNS=id,status,title,url PIGEON_OUTPUT=normal pigeon list

Required Fields ✅

Pigeon can require selected command fields from config. Defaults are intentionally loose; project teams can tighten only the fields they care about.

Show the available required-field keys:

pigeon requirements

Require owners on claims for the current project:

pigeon config --require claim.by
pigeon claim --by codex

Require richer task intake too:

pigeon config --require claim.by,add.url,add.note

Clear requirements:

pigeon config --clear-requirements

Use an environment override:

PIGEON_REQUIRE=claim.by pigeon claim --by codex

Agent Skill 🧠

Pigeon ships a TanStack Intent skill in the npm package.

Agents that understand Intent can load package guidance for project-local queues, claiming, releasing, blocking, readable output, and config:

npx @tanstack/intent@latest load task-pigeon#pigeon

Intent discovers package skills from installed project dependencies. Install task-pigeon in the project first when using intent load from a project workspace.

Command Tour 🧭

| Command | Purpose | | --- | --- | | pigeon init | Create or verify the active SQLite queue. | | pigeon status | Show the active database path and status counts. | | pigeon add | Add pending work with optional URL, note, priority, and labels. | | pigeon list | Show active work by default. | | pigeon message | Add, list, ack, and resolve coordination messages. | | pigeon claim | Claim the oldest pending task, or a specific ID. | | pigeon release | Move a claimed task back to pending. | | pigeon update | Edit title, URL, note, priority, or labels. | | pigeon block | Mark work blocked with a required note and optional dependency. | | pigeon done | Mark work complete. | | pigeon watch | Re-render the queue as it changes. | | pigeon monitor | Watch status, tasks, and messages together. | | pigeon wait | Block until visible tasks or messages change. | | pigeon serve | Serve one SQLite queue over private HTTP. | | pigeon config | Show or update project/user defaults. | | pigeon columns | Show output column names and examples. | | pigeon requirements | Show configurable required-field keys. | | pigeon identity | Show local actor examples. | | pigeon remote | Show private remote server examples. | | pigeon whoami | Show the active actor, source, and queue path. |

Common commands:

pigeon init
pigeon status
pigeon config --show
pigeon whoami
pigeon identity
pigeon remote
pigeon columns
pigeon requirements

pigeon message add "@claude Heads up for other agents" --by codex
pigeon message list --mentioned claude
pigeon message list --by claude --unread
pigeon message ack 1 --by claude
pigeon message resolve 1
pigeon message list --all

pigeon add "Task title" --url https://example.com --note "context"
pigeon list
pigeon list --all
pigeon list --status claimed
pigeon list --status pending,blocked
pigeon list --status active

pigeon claim --by codex
pigeon claim 8 --by codex
pigeon release 8

pigeon update 8 --title "New title" --url https://example.com --note "context"
pigeon block 8 --note "why work is blocked"
pigeon done 8

pigeon watch
pigeon monitor --by codex
pigeon monitor --by codex --mentions-only
pigeon wait --by codex
pigeon wait --by codex --mentions-only
pigeon wait --by codex --timeout 300000

Roadmap 🗺️

Pigeon’s goal is still: modern tooling, minimal architecture, useful coordination. Everything should stay boring in practice: clear, local-first, and easy to reason about.

What Works Today

  • ✅ Project-local SQLite queues with no server required.
  • ✅ Typed Drizzle schema and migrations.
  • ✅ Strict validation for task titles, URLs, blockers, and configurable required fields.
  • ✅ Atomic claiming so agents do not grab the same pending task.
  • ✅ Active-by-default lists: pending, claimed, and blocked.
  • ✅ Task metadata for priority, labels, and blocking dependency.
  • ✅ CSV status filters and --status active.
  • ✅ Responsive readable output that preserves links.
  • ✅ User/project config for columns, output, and required fields.
  • ✅ Casual local identity config for default --by values.
  • ✅ Private HTTP remote mode for sharing one SQLite queue across machines.
  • ✅ Cross-agent messages with per-agent read state and global resolve.
  • ✅ Direct message replies that auto-target the original author.
  • ✅ Message mentions plus mention-focused monitor/wait filters.
  • ✅ Interactive monitor dashboard with detail panes, inline compose, and quick actions.
  • ✅ Blocking wait command for agents that need to wake on board changes.
  • ✅ TanStack Intent skill packaged with npm.
  • ✅ Trusted npm publishing through GitHub Actions.
  • ✅ Lightweight JSON snapshots for backup/recovery.

Launch Gates (Before public)

  • ✅ Finalize release/upgrade docs (bunx, global install, version bump flow).
  • ✅ Publish a short “fresh machine” validation flow for whoami, config, status, and monitor.
  • ✅ Add a CHANGELOG.md and keep release notes current.
  • ✅ Add explicit local-only remote fallback guidance in docs:
    • PIGEON_LOCAL_ONLY=1
    • whoami + doctor checks
  • ✅ Make .pigeon + DB path behavior explicit for avoiding queue forks across machines.

Near-Term (Post-Launch, if still boring)

  • Better message ergonomics: message list --resolved, message ack --all --by <name>.
  • Monitor polish for longer sessions (sectioned defaults and clearer visibility hints).
  • Optional shell completion if it stays clean with CitTY and doesn’t add complexity.
  • More flexible required fields only if usage proves the defaults are insufficient.

Maybe Later

These are interesting, but only if they stay boring:

  • Due dates if they are just metadata.
  • Dependency polish if blockedBy needs more than plain text.
  • message reply only if flat messages become hard to scan.
  • A compact TUI only if the plain CLI remains first-class.
  • Optional GitHub issue helpers for URLs, without becoming a GitHub client.
  • Direct Cloudflare D1 support if the implementation can stay small and local SQLite remains the default.
  • Hosted SQLite experiments, likely Turso/libSQL first, only if private remote is not enough.

Production Checklist 📦

Before publish from a clean clone:

  • bun install
  • bun run ci
  • bun run smoke
  • bun run build
  • bun run build:binary
  • npm pack --dry-run

Fresh-machine verification:

bunx --bun task-pigeon@latest status
bunx --bun task-pigeon@latest whoami
bunx --bun task-pigeon@latest config --show
PIGEON_LOCAL_ONLY=1 bunx --bun task-pigeon@latest status

Release flow (when you’re ready):

bun run release:patch   # or bun run release:minor
git push
git push --tags

Publishing is executed by GitHub Actions using npm trusted publishing. Do not run npm publish locally for normal releases. If you need to trigger a publish manually, use the Publish GitHub Actions workflow dispatch or the GitHub UI.

Non-Goals

These are how Pigeon avoids becoming the thing it was built to avoid:

  • No hosted service.
  • No daemon required.
  • No plugin system.
  • No workflow engine, event bus, or automation framework.
  • No repository/service/adapter layers just for architecture theater.
  • No multi-user permissions model beyond private network access plus optional bearer token.
  • No attempt to replace Linear, GitHub Issues, Slack, or project management tools.

The bar for new features: can two agents use it immediately, does it make coordination clearer, and can the code still be explained as CLI -> small command functions -> Drizzle -> SQLite?

Development 🧪

bun install
bun run ci

Useful scripts:

bun test
bun run test:coverage
bun run check
bun run typecheck
bun run smoke
bun run build
bun run build:binary

bun run check runs Biome, the project policy checker, and TanStack Intent validation.

The policy checker enforces the intentionally flat architecture:

  • CitTY for CLI parsing.
  • Drizzle-centered database access.
  • centralized PIGEON_DB reads.
  • single options object params for command functions.

For local CLI development:

bun install
bun run build
bun link
pigeon --help

For code work where you want to avoid touching your active queue/config (same machine, same user), use the dev runner:

bun run dev
bun run dev -- status
bun run dev -- add "Try command in isolation"
bun run dev -- monitor --once

bun run dev always uses:

  • a temporary database path
  • a temporary user config directory
  • PIGEON_LOCAL_ONLY=1 (no remote calls)

This lets you iterate from any project without changing what other agent sessions are using.

If you are shipping this for others, pigeon doctor is the quality default you can suggest to every support request:

pigeon doctor

It prints the resolved DB path, config sources, and remote state so people can self-diagnose in 10 seconds.

For the installed package (or bunx) while developing:

PIGEON_LOCAL_ONLY=1 \
PIGEON_DB="$(mktemp)/pigeon-dev.db" \
XDG_CONFIG_HOME="$(mktemp -d)/xconfig" \
bunx --bun task-pigeon@latest status

Release 📦

See CHANGELOG.md for release notes.

Patch release:

bun run release:patch
git push
git push --tags

Minor release:

bun run release:minor
git push
git push --tags

Publishing runs from GitHub Actions on v* tags using npm Trusted Publishing. Use the GitHub Actions publish workflow rather than local npm publish commands.