CLI
fp — headless, scriptable, capture-first, with an exit-code contract you can rely on.
What it is
A real headless CLI, not a remote control for a running window. It works on a server, in CI and in a container with no display.
The exit code is a published API surface, as stable as the JSON output. Changing what a code means is a breaking change.
fp login
fp capture "the thing I will otherwise forget"
fp query "meeting notes" --ndjson | jq .titleCommands
| Command | Does |
|---|---|
fp capture [TEXT…] | capture to the inbox from arguments, a file or stdin |
fp add --last | capture the previous shell command, its output, exit code and timing |
fp ask "QUESTION" | an answer with block-level citations you can fetch |
fp query TEXT | text search, one page; --ndjson streams. Structured filters are MCP-only (fastpad_query) |
fp watch | the workspace change feed, as a pipe |
fp turns | proposals waiting for review |
fp diff TURN_ID | one proposal as a per-block diff |
fp turn-abandon TURN_ID | drop a proposal; accepting one needs a grant (below) |
fp pull / fp push | the Markdown mirror, out and back |
fp mcp | a local stdio MCP bridge and keychain credential broker |
fp agents | agent principals, scopes, autonomy, last seen |
fp commands --json | the command table, as data |
--json, --ndjson, --quiet, --dry-run, --profile and --timeout work on every command. Prose never touches stdout in either JSON mode.
Exit codes
| Code | Means |
|---|---|
0 | the requested effect happened |
1 | unclassified failure |
2 | usage error — unknown command, bad flag, missing stdin |
3 | not authenticated, or the credential was rejected |
4 | the target does not exist, or is no longer visible |
5 | conflict — stale state, idempotency, ambiguity |
6 | rate limited; retry_after_ms is on the problem document |
7 | accepted locally and spooled for replay. Not a failure |
8 | policy denied, including every attempt to approve a proposal |
fp --exit-codes # prints the contractCapture never fails
fp capture does not fail on a network error. It writes to a durable local spool with an idempotency key and exits 7, and the next successful command drains it. Capture is the interaction that decides whether you keep using a notes app, so it has to work on a plane.
fp capture --status # pending / delivered / failed
fp capture --flush # drain now; safe from cron or a shell hookfp accept needs a grant
It accepts a turn your credential opened, and only if that credential carries turns:accept — which a plain fp login never asks for. Log in with fp login --scope turns:accept to get it, and the approval page names it. Without the scope, fp accept exits 8 with approve-not-permitted; run fp diff to read the proposal and hand the URL it ends with to a person.
Every accept from the terminal is recorded like any other agent accept: attributed to the credential, marked agent_accepted, and listed on the Agent activity page for someone to review or revert.