The review inbox for agent work
Before your agent acts,
it asks.
Pinrail is a desktop inbox for the moments your agent needs you: review comments about to be posted, emails about to be sent, an illustration or a voice-over still taking shape.
Free and open source · macOS and Linux, Windows soon · every download · in early development
Inbox Retry failed webhook deliveries with exponential backoff
Pendingcode-review v1northwind/api / pr-review #482claude41m ago

Inbox Empty inbox illustration — round 1
Pendingimage v1tern/web / illustrationgemini34m ago

Inbox Pagination for the orders API: a few decisions first
Pendingfeedback v1northwind/api / planning ENG-1142claude27m ago

Inbox Field Notes intro — voice takes
Pendingaudio v1fieldnotes/episodes / voiceoveropencode19m ago

Inbox Dependency upgrades for web-app
Pendinglist v1northwind/web-app / depsrenovate-agent12m ago

Inbox Pinrail promo — the opening
Pendingvideo v1pinrail/promo / videocodex6m ago

Works with any agent that can run a command
Claude Code
Codex
Cursor
Gemini CLI
OpenCode
Kimi
- yours
01 · How it works
One command in, one decision out.
You tell the agent when to stop for you, in whatever instructions it follows. When it gets there, it asks through Pinrail and waits.
02 · Views
A diff deserves a diff. A picture deserves a pen.
Each kind of request is a plugin, with a view made for deciding it: the diff for a code review, the draft itself for an email, the image for a picture, the waveform for a voice take. What you say goes back with what it points at, down to the line, the pixel or the millisecond.
pinrail plugins new my_pluginThe next one is yours. A plugin is a manifest, two JSON schemas and a web page, built with any web framework you like, or none at all. Storyboards, floor plans, moodboards, a map with a no-go zone scribbled on it: if your agent can make it, you can put it in front of your eyes and mark it up. The only limits are your imagination and your agent's.
Write a plugin →03 · Rounds
A no comes with a reason, and the reason comes back.
Send something back and the agent answers with a new round, submitted with --revises. It lands beside your earlier verdicts and comments, so you see what changed and why, and a view can set the two rounds side by side to check each fix. Every round and every decision is kept, and can be opened again later.
04 · Stop
“Stop” is a real answer.
Discard a review with a reason and the waiting command exits 5. The agent stops the work the review was gating, reports why, and doesn't try again. Every ending has its code:
| 0 | Decided. The decision is on stdout, and in --decision-out if given. |
| 3 | Withdrawn by the agent, or expired, before anyone decided. |
| 4 | --timeout ran out. The review is still pending. |
| 5 | Discarded: stop the work this review was gating. |
05 · The CLI
For an agent, and for a script.
An agent reads the decision as markdown. A script keeps the JSON and branches on the exit code, and --decision-out writes the decision to a file for a workflow that already reads one.
# submit the proposed comments and wait for a person $ pinrail submit code-review --title "Dedup tickets on save" \ --origin repo=acme/api,workflow=pr-review,ref=42 \ --data proposals.json --wait pinrail: review r_01K5Q8 submitted; waiting for a decision r_01K5Q8 · decided · Dedup tickets on save review · acme/api · pr-review · 42 · decided by maya at 2026-09-23 10:14 ## Proposals - **#18 accepted** `lib/acme/tickets.ex:149` — reversing twice is a no-op (major) - **#19 accepted** `priv/repo/add_hash.exs:6` — missing index on tickets.hash (minor) > mention the COALESCE - **#20 rejected** `lib/acme/tickets.ex:151` — prefer Enum.uniq_by/2 (nit) > fine as it is - **#21 accepted** `test/acme/tickets_test.exs:40` — test for the empty list (minor) $ echo $? 0
06 · Questions
Before you ask.
Who decides what a decision looks like?
The plugin. Each one declares what the agent sends and what comes back, as JSON Schema. JSON is the transport, HTML is the view.
- agent
- JSON
- HTML · you
- JSON
- agent
list/
├ manifest.json
├ schemas/payload.schema.json in
├ schemas/decision.schema.json out
└ view/index.html the viewCan I make one for my own work?
Yes, or have your agent make it. A deploy to approve, alerts to triage, three designs to pick from: whatever needs a person.
$ pinrail plugins new my_pluginWrite a plugin →
Which agents work with it?
Any that can run a command: Claude Code, Codex, Cursor, a CI job, a shell script. Its own instructions say when to stop and ask.
Does anything leave my machine?
No. The app runs its server on loopback, and reviews and decisions stay on your computer. There's no account. A plugin's view is sandboxed: it can draw and talk to the app, and nothing else.
What if I'm away when it asks?
A notification tells you when a review arrives, and the menu bar shows how many are waiting. The app keeps listening with its window closed.
The agent waits, even through an app restart. With --timeout it stops waiting (exit 4) and the review stays in your inbox.
Decide when you're back. The agent picks up your decision with the CLI whenever it next looks:
$ pinrail wait <id> # your decision $ pinrail show <id> # where it stands
What does it cost?
Nothing. Pinrail is free and open source under the Apache License 2.0. It runs on macOS and Linux and is in early development.
your move
Put a pinrail
in front of your agents.
macOS and Linux today, Windows soon.
Or skip the reading: review this page instead →