papercuts
v0.2.0
Published
A local agent-facing CLI for recording controlled friction without interrupting the work.
Maintainers
Readme
Papercuts
A tiny local memory for the friction agents are otherwise too competent to complain about.
I built Papercuts because an agent can lose a few seconds or a few minutes to a misleading command, recover, finish the task, and leave no trace that the next agent will hit the same thing. Each incident is small. The repetition and compound effect are not. The recovery looks like success, so the bad interface survives.
Papercuts records that moment without turning the original task into a retrospective. Reporting is one write-only command. Grouping, dismissing, and ticketing happen later, in a separate maintenance pass.
Add this to
AGENTS.md: If avoidable friction in something we control makes the correct path discoverable only through failed attempts, or forces an unnecessary workaround, handoff, or weaker verification, record one concise, secret-free occurrence withpapercuts report "<attempt; friction; recovery/impact>", then continue.
The original idea for collecting papercuts belongs to Steve Ruiz, who shared his implementation and rationale in this post.
This is a tool I built for myself and decided to share as-is. There is no roadmap, support SLA, or promise that I will maintain it on anyone else's schedule—or at all. Issues, discussions, and pull requests are welcome; that is an invitation, not a service contract. Papercuts is tested on macOS and Linux. Windows is untested, not deliberately blocked.
Install
Papercuts requires Bun 1.3.14 or newer. It is distributed as source, not as a platform-specific binary.
Run it without keeping it:
bunx papercuts --versionOr install it globally:
bun install --global papercuts
papercuts --versionEvery GitHub release also carries the exact npm package tarball:
bun install --global https://github.com/0xmrwn/papercuts/releases/download/v0.2.0/papercuts-0.2.0.tgzYou can install a tagged checkout instead:
bun install --global github:0xmrwn/papercuts#v0.2.0Report a papercut
The AGENTS.md instruction above is the ordinary integration. That last word—continue—matters. Reporting is deliberately boring and write-only: record the papercut, then get back to work.
You can also try it directly:
papercuts report "A hidden working directory made the documented test command fail; using the nested path worked."Commands return JSON by default. Inputs and outputs are discoverable without prose archaeology:
papercuts report --schema --format json
papercuts inbox --schema --format jsonMaintenance is separate
Papercuts does not quietly turn every annoyance into a ticket. The ordinary workflow only records immutable occurrences. A maintainer—human or agent—later decides whether occurrences belong together, should be dismissed or deferred, or justify an external ticket.
The optional maintenance skill lives in skills/papercuts-maintenance. Point your agent's existing skill installer at that directory, or copy it into the skill location that agent already uses. Installing the npm package includes the skill files but does not install or configure them behind your back.
The skill never activates implicitly: a user request or scheduled-task prompt must explicitly invoke $papercuts-maintenance. It uses whichever authenticated issue tracker the user and agent have already agreed to use. Papercuts does not own tracker authentication, adapters, or routing configuration.
Command reference
papercuts report <note>
papercuts inbox --consumer <id> [--limit 50] [--offset 0]
papercuts cluster list [--status open|ticketed|dismissed] [--limit 50] [--offset 0]
papercuts cluster create --title <title> --occurrence <id>...
papercuts cluster add --id <cluster> --occurrence <id>...
papercuts cluster remove --id <cluster> --occurrence <id>...
papercuts cluster merge --into <cluster> --from <cluster>...
papercuts cluster dismiss --id <cluster> --reason <reason>
papercuts cluster link-ticket --id <cluster> --provider <provider> --ticket-id <id> --url <url>
papercuts occurrence dismiss --id <id>... --reason <reason>
papercuts occurrence defer --id <id>... --reason <reason>
papercuts consumer commit --consumer <id> --cursor <cursor>Run papercuts <command> --help for command-level usage. Incur currently advertises some integration surfaces in root help that Papercuts intentionally refuses; MCP and generated-skill commands are not part of the supported interface.
Inbox and cluster-list responses are bounded to 50 items per stream by default and 200 maximum. Follow page.nextOffset until it is null before mutating maintenance state. A consumer cursor advances only after every occurrence through the target cursor has been clustered or explicitly dismissed or deferred.
Cluster membership cannot be removed after any consumer has committed past an occurrence. Use cluster merge for same-fix corrections and finish membership changes before committing.
Local data and privacy
The CLI has no service and makes no network calls. It stores its SQLite database locally at:
$XDG_DATA_HOME/papercuts/papercuts.sqlite3
~/.local/share/papercuts/papercuts.sqlite3 (when XDG_DATA_HOME is unset)PAPERCUTS_HOME overrides the data directory. Papercuts creates a missing dedicated directory with mode 0700, preserves the permissions of an existing directory, and creates the database with mode 0600.
Each occurrence includes the note, timestamp, compact repository name, and best-effort runtime attribution: harness, model, reasoning effort, and session ID. Recognized harnesses are codex, claude-code, claude-code-desktop, and claude-cowork. Attribution comes from process markers and bounded reads of matching local agent state. Missing or malformed state leaves fields null and never blocks reporting. Transcript content and transcript paths are not stored.
These environment variables override local discovery:
PAPERCUTS_HOME
PAPERCUTS_REPOSITORY
PAPERCUTS_HARNESS
PAPERCUTS_MODEL
PAPERCUTS_REASONING_EFFORT
PAPERCUTS_SESSION_IDDevelopment
git clone https://github.com/0xmrwn/papercuts.git
cd papercuts
bun install --frozen-lockfile
bun run checkbun run check runs the contract tests, builds and exercises the compiled binary, then packs, installs, and exercises the npm artifact in an isolated environment.
The implementation is intentionally small: Bun, Incur, bun:sqlite, and no ORM. See CONTEXT.md for the precise domain language and CONTRIBUTING.md before changing a contract.
License
MIT © 2026 0xmrwn.
