CLI reference
Every command and flag of pinrail, from the same definition pinrail --help prints. For the commands in use, see The CLI.
Global flags
Section titled “Global flags”Every command accepts these.
| Argument | Description |
|---|---|
--url <URL> | The server’s URL [default: PINRAIL_URL, then the address in the running server’s server.json, then http://127.0.0.1:4747]. Env: PINRAIL_URL. |
--pretty | Indent the JSON output. Requires --json. |
--json | Print JSON instead of Markdown, for a script or tool that processes the result. PINRAIL_JSON=1 sets this for a whole session. Env: PINRAIL_JSON. |
--verbose | Also report each step on stderr, such as the origin read from git, the server started, the files uploaded and where files were written. Env: PINRAIL_VERBOSE. |
Commands
Section titled “Commands”pinrail submit
Section titled “pinrail submit”Submit a review, and with --wait, wait for the decision and print it.
The options build the review: the plugin, --title, and the payload from --data. Alternatively, give the whole request as one JSON file with --request, in the form the API takes:
{ "plugin": "list", "title": "Sentry triage", "origin": {"repo": "acme"}, "payload": {"groups": []}}The keys are plugin, title, payload, origin, revises, expires_at and requested_by. Options override the file’s keys, and --data replaces its payload, so you can send a new round with the same file, --revises and the id of the earlier round. You can leave out the plugin argument when the file names one.
To send files with the payload, use --attach, for a plugin that accepts files (pinrail plugins shows which plugins do). The payload refers to each file as {“$attachment”: "
pinrail submit model --data models.json \ --attach out/pivot.glb --attach out/v2.glb=column.glbIn a --request file, list the files under “attachments”, such as {“pivot.glb”: “out/pivot.glb”}, with paths relative to the file. An entry can also be {“path”: …, “media_type”: …}, as in a plugin’s fixtures, so you can send a fixture unchanged. Pinrail checks the submission before it uploads anything, and it does not upload a file that the app already has.
pinrail submit [PLUGIN] [OPTIONS]| Argument | Description |
|---|---|
<PLUGIN> | The plugin that defines this kind of review, such as review. |
--title <TITLE> | The title the inbox shows for the review. |
--request <JSON|FILE|-> | The whole request as JSON, given inline, as a file path, or as - for stdin. Other options override its keys. |
--origin <ORIGIN> | Where the review comes from, as comma-separated key=value pairs. The keys are repo (the project, as owner/name), ref (a branch or pull request), workflow and run_id (what asked for the review), and url (a link back, which may contain commas). In a git checkout, repo defaults to the remote, and ref defaults to the branch when the repo is the checkout’s own. For example: repo=acme/api,ref=42,url=…. |
--data <JSON|FILE|-> | The payload as JSON, given inline, as a file path, or as - for stdin. |
--attach <PATH[=NAME]> | A file to send with the payload. The payload refers to it as {“$attachment”: " |
--revises <REVISES> | The id of the review that this one is a new round of. |
--expires-at <EXPIRES_AT> | The time after which the review expires, as an ISO 8601 timestamp. |
--requested-by <REQUESTED_BY> | Who is asking, shown on the review as its requester, with the agent’s icon when the app knows the agent [default: the coding agent the command runs under, detected from the variables it sets (claude-code, codex, cursor, antigravity, grok, opencode, kimi), or else pinrail-cli]. Env: PINRAIL_REQUESTED_BY. |
--sample <NAME> | Send one of the plugin’s sample reviews, which show what the plugin looks like, instead of a payload: the one named, or else its first. --title and --origin still apply. |
--wait | Wait until the review ends, whether or not it is decided (see wait). |
--dry-run | Run every check on the submission without creating a review. The command exits with 0 if the review would be accepted, and with 2 and the violations if not. |
--timeout <TIMEOUT> | With --wait, stop waiting after this many seconds and exit with 4. 0 waits indefinitely. PINRAIL_TIMEOUT sets this for every wait. |
--decision-out <FILE> | With --wait, also write decision.data to this file as JSON once the review is decided. pinrail show |
--no-start | Do not start the server when it is not running. |
pinrail wait
Section titled “pinrail wait”Wait until a review ends, then print its decision as Markdown, or the whole review as JSON with --json.
pinrail wait <ID> [OPTIONS]| Argument | Description |
|---|---|
<ID> | The review’s id. |
--timeout <TIMEOUT> | Stop waiting after this many seconds and exit with 4. 0 waits indefinitely. PINRAIL_TIMEOUT sets this for every wait. |
--decision-out <FILE> | Also write decision.data to this file as JSON once the review is decided. pinrail show |
pinrail show
Section titled “pinrail show”Print a review as Markdown, or the whole review as JSON with --json, including its payload and decision.
pinrail show <ID>| Argument | Description |
|---|---|
<ID> | The review’s id. |
pinrail rounds
Section titled “pinrail rounds”List every round of a review, oldest first, without payloads.
pinrail rounds <ID>| Argument | Description |
|---|---|
<ID> | The review’s id. |
pinrail events
Section titled “pinrail events”Print a review’s event log.
pinrail events <ID>| Argument | Description |
|---|---|
<ID> | The review’s id. |
pinrail list
Section titled “pinrail list”List reviews, newest first, without payloads.
By default, the command lists only pending reviews and, in a git checkout, only those of its project. The project is named the way submit names it: the remote’s owner/name, or the folder’s name when there is no remote. Outside a git checkout, the command lists the pending reviews of every project. Use --status and --repo to choose other reviews, and --all to list every review.
pinrail list [OPTIONS]| Argument | Description |
|---|---|
--status <STATUS> | The status to list: pending, decided, withdrawn, discarded or expired. Separate several with commas [default: pending, unless --all]. |
--repo <REPO> | The project, as the origin’s repo. Use - for reviews that name no project [default: the git checkout’s project, unless --all]. |
--workflow <WORKFLOW> | The workflow that asked for the review, as the origin’s workflow. |
--ref <REFERENCE> | The branch, pull request or other ref, as the origin’s ref. |
--run-id <RUN_ID> | The run that asked for the review, as the origin’s run_id. |
--plugin <PLUGIN> | List only reviews of this plugin. |
--search <WORDS> | Words that must all appear in the title, payload, plugin, requester, origin or the name of the person who decided. |
--cursor <CURSOR> | List only reviews older than this id. |
--limit <LIMIT> | The most reviews to list. Use --cursor to list the next page. |
--all | List every review, of any status and project unless --status or --repo limits them, and every page unless --limit caps the number. |
--include-revised | Include rounds that a later round revises. |
pinrail decide
Section titled “pinrail decide”Record a decision on behalf of the person, from a test or a tool.
An agent never decides a review that it submitted. Only the person does.
pinrail decide <ID> --data <JSON|FILE|-> [OPTIONS]| Argument | Description |
|---|---|
<ID> | The review’s id. |
--data <JSON|FILE|-> | The decision as JSON, given inline, as a file path, or as - for stdin. Required. |
--note <NOTE> | A note to the agent that requested the review. |
pinrail withdraw
Section titled “pinrail withdraw”Withdraw a pending review. A command that is waiting on it exits with 3.
pinrail withdraw <ID> [OPTIONS]| Argument | Description |
|---|---|
<ID> | The review’s id. |
--reason <REASON> | Why the review is no longer needed. |
pinrail discard
Section titled “pinrail discard”Discard a pending review on behalf of the person.
This does what discarding does in the app. A command that is waiting on the review exits with 5 and tells the agent to stop. An agent never discards a review that it submitted.
pinrail discard <ID> [OPTIONS]| Argument | Description |
|---|---|
<ID> | The review’s id. |
--reason <REASON> | The reason, which the agent receives. |
--by <BY> | Who discards the review [default: the server’s user]. |
pinrail plugins
Section titled “pinrail plugins”List the installed plugins and when to use each one.
The listing includes each plugin’s install record and settings. pinrail plugins describe <name> shows one plugin in full.
pinrail plugins [COMMAND]pinrail plugins install
Section titled “pinrail plugins install”Install an official plugin by name, or a plugin from a folder or a zip.
An official plugin, such as list, is installed from the plugins the app carries, at the newest version it has. A name is taken as a folder when a folder of that name exists here. Installing again, from the same place or another, replaces the installed plugin: this is how a plugin is upgraded.
pinrail plugins install <SOURCE> [OPTIONS]| Argument | Description |
|---|---|
<SOURCE> | An official plugin’s name, such as list, or a plugin’s folder, or a zip of it. |
--link | Serve the folder directly instead of copying it, while you develop the plugin. |
pinrail plugins remove
Section titled “pinrail plugins remove”Remove an installed plugin. The versions that existing reviews render with are kept.
pinrail plugins remove <NAME>| Argument | Description |
|---|---|
<NAME> | The plugin’s name. |
pinrail plugins describe
Section titled “pinrail plugins describe”Show what an agent needs to submit a review with a plugin.
The description includes the payload schema, an example payload and the files the plugin accepts. With --json, it also includes the decision schema. pinrail plugins lists the plugins and says when to use each one.
pinrail plugins describe <NAME> [OPTIONS]| Argument | Description |
|---|---|
<NAME> | The plugin’s name. |
--payload-schema | Print only the payload’s JSON schema, for a tool that checks or builds payloads. |
--example | Print only the example payload, as a starting point for your own. |
--decision-schema | Print only the decision’s JSON schema, which describes decision.data, for processing the decision with --json. Without --json, the decision is printed as Markdown. |
pinrail plugins new
Section titled “pinrail plugins new”Create a new plugin.
The new folder contains a manifest, schemas, a sample review, a view, and the SDK’s types. The plain template’s view needs no build. The typescript template, or ts, and the react template write the view in src/, which npm run build turns into view/. --playwright adds a first test of the view, run with Playwright under the SDK’s harness. --link installs the plugin as a link right away, which needs a view, so it takes the plain template only.
pinrail plugins new <NAME> [OPTIONS]| Argument | Description |
|---|---|
<NAME> | The plugin’s name, which starts with a lowercase letter followed by letters, digits, _ or -. |
--dir <DIR> | The folder to write the plugin to [default: ./ |
--template <TEMPLATE> | How the view is written. One of plain, typescript, react. Default: plain. |
--playwright | Add a first test of the view, with package.json and Playwright’s configuration. |
--link | Install the plugin as a link after writing it, so the app serves the folder directly. |
pinrail plugins schema
Section titled “pinrail plugins schema”Print one of the plugin SDK’s JSON Schemas.
The manifest’s schema, which every plugin’s manifest.json is checked against, or the attachment schema, which a payload schema copies to describe a field that names an attached file. They are the schemas this command was built with, and need no app.
pinrail plugins schema [WHICH]| Argument | Description |
|---|---|
<WHICH> | Which schema to print. One of manifest, attachment. Default: manifest. |
pinrail plugins check
Section titled “pinrail plugins check”Check a plugin folder without installing it.
The command reports why the app would refuse the folder, and each feature the app would drop. It also checks the plugin’s recorded decisions, fixtures/
pinrail plugins check [DIR] [OPTIONS]| Argument | Description |
|---|---|
<DIR> | The plugin’s folder. Default: .. |
--since <DIR> | The release before this one, as a folder: also report what this release’s schemas no longer accept of what that one took, which semantic versioning allows only in a version that announces it. |
--update-fixtures | Write each recorded decision’s |
pinrail attachments
Section titled “pinrail attachments”List the files a review carries, or save one of them.
pinrail attachments <COMMAND>pinrail attachments list
Section titled “pinrail attachments list”List the files a review carries, with their names, sizes, media types and hashes.
pinrail attachments list <ID>| Argument | Description |
|---|---|
<ID> | The review’s id. |
pinrail attachments get
Section titled “pinrail attachments get”Save a file that a review carries.
pinrail attachments get <ID> <NAME> [OPTIONS]| Argument | Description |
|---|---|
<ID> | The review’s id. |
<NAME> | The file’s name on the review. |
--output <PATH|-> | The path to write the file to, or - for stdout [default: the file’s name, in the current directory]. |
--force | Replace an existing file. |
pinrail export
Section titled “pinrail export”Write every review as a JSON file in a directory.
pinrail export <DIR>| Argument | Description |
|---|---|
<DIR> | The directory to write to. It is created if it does not exist. |
pinrail serve
Section titled “pinrail serve”Start the server if it is not running, and print its URL.
pinrail servepinrail docs
Section titled “pinrail docs”Print the briefs on using Pinrail as an agent.
Without a path, the command prints the main brief, which is Pinrail’s agent skill, and a menu of the other briefs. With a path, such as pinrail docs building, it prints that brief.
pinrail docs [PATH] [OPTIONS]| Argument | Description |
|---|---|
<PATH> | The brief to print, as the menu names it [default: the main brief]. |
--tree | Print the path and subject of every brief, as a tree. |
pinrail open
Section titled “pinrail open”Open a review in the app, or its preview in a browser with --browser.
The command opens the link pinrail://reviews/
--browser opens
pinrail open <ID> [OPTIONS]| Argument | Description |
|---|---|
<ID> | The review’s id. |
--browser | Open the preview in the default browser, to try a view while building a plugin. |
Exit codes
Section titled “Exit codes”| Code | Meaning |
|---|---|
0 | Done. For wait and submit --wait, the review was decided. |
1 | Error: bad arguments, the app could not be reached, a file could not be read or written, or the app failed on its side. wait and submit --wait keep waiting through an error inside the app until it answers again. |
2 | The app refused the request, for example a payload the plugin’s schema rejects, or a folder that plugins check would not install. Why is on stderr. |
3 | The review was withdrawn by the agent, or expired, before anyone decided. |
4 | --timeout ran out. The review is still pending. |
5 | The person discarded the review: stop the work it was gating, and do not ask again. |
Environment
Section titled “Environment”| Variable | Used for |
|---|---|
PINRAIL_DATA_DIR | Where the running server’s server.json is, to find it; also where a server the CLI starts keeps its data. |
PINRAIL_JSON | --json. Print JSON instead of Markdown, for a script or tool that processes the result. PINRAIL_JSON=1 sets this for a whole session. |
PINRAIL_PORT | The port to try when no server advertises itself. Defaults to 4747. |
PINRAIL_REQUESTED_BY | --requested-by <REQUESTED_BY>. Who is asking, shown on the review as its requester, with the agent’s icon when the app knows the agent [default: the coding agent the command runs under, detected from the variables it sets (claude-code, codex, cursor, antigravity, grok, opencode, kimi), or else pinrail-cli]. |
PINRAIL_SERVER_CMD | How to start a server when none is running, run through sh -c. submit, serve, plugins, plugins describe, plugins check and plugins new --link use it. |
PINRAIL_TIMEOUT | How many seconds wait and submit --wait wait before they give up with exit 4, when --timeout is not given. Unset or 0 waits without a limit. |
PINRAIL_URL | --url <URL>. The server’s URL [default: PINRAIL_URL, then the address in the running server’s server.json, then http://127.0.0.1:4747]. |
PINRAIL_VERBOSE | --verbose. Also report each step on stderr, such as the origin read from git, the server started, the files uploaded and where files were written. |