Built-in agent
greppy is a pure coding agent. Every task runs in its own temporary copy-on-write worktree and always ends as a pull request: a proposal commit on refs/greppy/agent/<run-id>. As soon as the proposal is saved, greppy removes the worktree again. Your checkout, its HEAD and its Git index stay unchanged.
You start the agent straight from the shell or let it work as a subagent of another agent, one-shot with greppy -p or remote-controlled through greppy agent serve.
How a task runs
| Step | What happens |
|---|---|
| Start | greppy creates a copy-on-write snapshot of your repository: the pinned commit plus your staged, unstaged and untracked changes. Ignored files such as node_modules, .venv or target stay out. The worktree is indexed before the model takes its first turn. |
| Work | The agent has exactly one tool: greppy. With it, the agent searches, navigates, reads and edits. Shell commands run as bash-smart -- CMD. It writes to the worktree and its scratch directory and nowhere else. |
| End | The changes in the worktree become a commit on refs/greppy/agent/<run-id>. Its parent is your baseline including uncommitted work, so the proposal contains the agent's changes and nothing else. Then greppy deletes the worktree. |
The commit message is the agent's final answer and the description of the pull request: a one-line title, Status: (done, partial or blocked), what changed and why (with file:line), how it was verified and what is open. An explicit Title: line becomes the subject, otherwise the line before Status:; the answer is the body.
--keep-worktree keeps the worktree. If a run ends with an error before a proposal exists, the worktree stays for 24 hours for debugging. If a run reaches a limit (exit 5), the proposal is still saved and the worktree removed.
Requirement: a local model gateway
greppy ships no chat model. The agent speaks the Anthropic Messages API over plain HTTP to a local, Anthropic-compatible gateway. The standard gateway is CLIProxyAPI; it translates the common chat formats and providers into this wire format.
export GREPPY_ENDPOINT=http://127.0.0.1:8317 # the default; or --endpoint URL
export GREPPY_MODEL=MODEL # a model ID your gateway offers; or --model
export GREPPY_API_KEY=YOUR_GATEWAY_KEY # only if the gateway requires a key
The client has no TLS stack, so it reaches plain-HTTP endpoints such as a gateway on localhost. The model ID goes to the gateway unchanged. greppy sends the key as x-api-key and as Authorization: Bearer. There is deliberately no key flag: keys do not belong on the command line. greppy -p --help describes the full setup.
One-shot: greppy -p
greppy -p "add tests for clamp_value" --model MODEL
greppy -p "keep going" --continue
greppy -p "TASK" is the headless mode for scripts and for tasks another agent hands off. The first line on stderr reads session: <session_id>.
Usage:
greppy agent ["INITIAL TASK"]
greppy agent stdio [--model M] [--endpoint URL]
greppy -p "TASK" [--model M] [--endpoint URL] [--max-turns N]
[--deadline-secs N] [--apply] [--diff] [--keep-worktree]
[--no-sandbox] [--skip-selfcheck]
[--continue | --resume ID] [--json]
greppy -p --help
| Flag | Effect |
|---|---|
--model M |
model ID, passed to the gateway unchanged (or GREPPY_MODEL); greppy agent saves it through /setup |
--endpoint URL |
base URL of the gateway (or GREPPY_ENDPOINT, otherwise http://127.0.0.1:8317) |
--max-turns N |
optional cap on action turns, followed by a report turn without tools; without the flag there is no cap |
--deadline-secs N |
time budget in seconds (or GREPPY_DEADLINE_SECS); the loop stops between turns, and tool calls already started run at most 30 s past the deadline |
--apply |
applies the agent's changes, and nothing else, to the exactly captured baseline; your Git index stays byte-identical |
--diff |
prints the full patch of the proposal after the stat |
--keep-worktree |
keeps the isolated worktree and its private changes |
--no-sandbox |
turns off the write confinement (or GREPPY_NO_SANDBOX=1) |
--skip-selfcheck |
skips the capability self-check at startup (or GREPPY_SKIP_SELFCHECK=1) |
--continue, --resume ID |
continues this project's latest session, or a specific one |
--json |
streams events as JSON, one per line, on stdout (in -p mode) |
There are no fixed limits: no default cap on turns and no fixed tool timeouts. The run's deadline bounds both. greppy folds large tool output behind expand agent-output-ID instead of cutting it off.
A leading -p is reserved for the agent. To search for the pattern -p with grep, use greppy -e -p ….
As a subagent
Another agent hands greppy a self-contained task with greppy -p and gets the pull request back. In -p mode, the prompt tells the agent that a person, a script or another agent reads the final answer and the pull request and nothing else. Nobody answers questions, so the agent decides details itself and names them.
External agents find the instructions for this in the AGENTS.md that ships with greppy.
AGENT:
greppy -p "TASK" [--model M] isolated coding task, delivered as refs/greppy/agent/<id>
The task does not edit the working checkout. Review with git show <ref>, apply with
git cherry-pick -n <ref>. greppy -p --help describes gateway setup.
For longer collaboration, you host a session with greppy agent serve and control it remotely, see Remote control.
Review and apply the pull request
git show refs/greppy/agent/<run-id>
greppy agent apply refs/greppy/agent/<run-id>
The proposal is built against a captured baseline: the pinned commit plus your visible staged, unstaged and untracked changes. greppy agent apply REF checks exactly this baseline, applies the agent's changes and nothing else, and leaves your Git index byte-identical. --apply on greppy -p does the same at the end of the run. For proposals on uncommitted work, greppy agent apply is the way. External agents that have nothing but Git use git cherry-pick -n REF, as the AGENTS.md describes.
greppy agent apply with a ref that does not exist exits with code 64.
Interactive: greppy agent
greppy agent
greppy agent "TASK" --model MODEL
greppy agent --continue
greppy agent opens a full-screen terminal UI with the same worktree, the same sandbox and the same proposal as greppy -p. The transcript keeps context across several prompts and shows streamed replies, tool activity and token usage. /setup configures the gateway, the model and the remaining settings and saves them.
| Key | Action |
|---|---|
| Enter | sends the prompt; prompts you send while the agent works land visibly in a queue |
| Shift+Enter / Alt+Enter | newline, when the terminal reports the modifier |
| PageUp / PageDown, mouse wheel | scroll; End follows the tail again |
| Tab / Shift+Tab, Esc | completions and overlay choices; Esc closes the overlay first, then the completions |
| Ctrl+C | cancels a run at a safe tool boundary (never in the middle of an edit); when idle, it exits the UI; pressed twice, it exits after the running tool |
| Slash command | Effect |
|---|---|
/help |
commands and key bindings |
/setup |
all agent settings: gateway, model, language, storage, sandbox, acceleration, self-check, workspace backend |
/clear |
clears the visible transcript |
/model |
picks a model from the gateway |
/endpoint |
sets and checks the gateway URL |
/usage |
the session's token usage |
/tools |
this session's tool calls |
/copy |
copies the agent's last answer |
/sessions |
resumes a saved session |
/name TITLE |
renames the current session |
/compact |
summarizes older messages, keeps newer ones |
/exit (also /quit, /q) |
exits, restores the terminal, publishes the proposal |
Sessions
Sessions live as append-only JSONL under the greppy data directory (agent-sessions/<project>/<id>.jsonl; on macOS that is ~/Library/Application Support/greppy). greppy restores a truncated tail up to the last valid entry. Secrets and authorization headers are redacted on screen and in the file. Every session has a copyable handle, greppy://sessions/<id>, that works wherever a session ID is expected.
greppy agent sessions list [--json] [--all-projects]
greppy agent sessions show ID [--json] [--full]
greppy agent sessions tail ID [--json] [--follow] [--lines N]
greppy agent sessions path ID
Without --lines, tail shows the last 40 lines, and --follow polls until SIGINT. These commands never write to the store. IDs can be unique prefixes; an unknown or ambiguous ID exits with code 2.
$ greppy agent sessions list
no sessions for project serde
$ greppy agent sessions show nope
no session nope in project serde
The second command exits with code 2.
JSON events
greppy -p --json streams one JSON event per line on stdout: session, text, tool_start, tool_finish, turn_complete, error and result. result is always the last line. Human-readable diagnostics stay on stderr.
The first SIGINT or SIGTERM cancels at the next safe boundary and still delivers result with status: "cancelled" and exit_code: 130. A second signal exits immediately.
Remote control
greppy agent serve [TASK] hosts a headless session on a per-user Unix socket. An optional TASK is queued as the first task after setup. Every message continues the same task in the same worktree; the controlling agent can send follow-up tasks or interrupt a turn.
agent serve flag |
Effect |
|---|---|
--model M |
model ID (or GREPPY_MODEL) |
--endpoint URL |
gateway (or GREPPY_ENDPOINT, default http://127.0.0.1:8317) |
--continue, --resume SESSION_ID |
continues the latest or a specific session |
--idle-timeout-secs N |
exits the host after N seconds idle |
--no-sandbox, --skip-selfcheck |
as with greppy -p |
greppy agent sessions list --json reports the socket path for each session. Another shell or another agent then controls the session like this:
greppy agent serve --model MODEL
greppy agent status ID [--json]
greppy agent send ID TEXT [--wait] [--json] [--source LABEL]
greppy agent attach ID [--json] [--since-start]
greppy agent interrupt ID [--json]
greppy agent quit ID [--json]
ID is a session ID, a unique prefix or the handle greppy://sessions/<id>.
| Command | Effect |
|---|---|
status |
describes the running session |
send |
queues a prompt; TEXT can be - for stdin; --wait streams events until this turn is done; --source sets the turn's label (default remote) |
attach |
streams events of the running session; --since-start first replays the latest log lines |
interrupt |
cancels the running turn |
quit |
asks the host to exit |
A session without a live socket exits with code 3 and names the command greppy agent serve --resume ID that restarts it.
ACP hosts: greppy agent stdio
greppy agent stdio --endpoint http://127.0.0.1:8317 --model MODEL
greppy agent stdio speaks the Agent Client Protocol (JSON-RPC, one message per line) on stdin and stdout for a host application; diagnostics go to stderr. The host supplies the working folder when it creates or loads a session, and every tool call waits for the client's approval. In this mode, the agent edits the client's folder directly: it creates no worktree and produces no proposal under refs/greppy/agent/. Its prompt therefore promises neither a worktree nor a pull request. Sessions use the same store as greppy -p and greppy agent.
Speak the Agent Client Protocol on stdin/stdout.
Usage: greppy agent stdio [OPTIONS]
Options:
--model <MODEL> Initial model id. `session/set_model` can replace it [env: GREPPY_MODEL=]
--endpoint <ENDPOINT> Anthropic-Messages gateway base URL [env: GREPPY_ENDPOINT=] [default: http://127.0.0.1:8317]
--max-turns <N> Maximum assistant turns for one prompt [default: 0]
-h, --help Print help
--max-turns 0, the default, means no cap. The agent process reads the gateway key from GREPPY_API_KEY; ACP clients do not send it. You find the supported operations in docs/acp.md.
One prompt, four modes
All modes render their system prompt from the same source. greppy prompt --mode one-shot|interactive|serve|acp|external prints the matching version, and with --json its SHA-256 as well.
$ greppy prompt --mode one-shot | head -2
prompt-sha256: 12bb2db4bce1ab2603279913aeb676f7b68115143a42170091f5842a6cf0d84f
You are greppy, a coding agent. You never work in the user's checkout: every task runs in its own temporary worktree and ends as a pull request.
| Mode | Version | rendered_sha256 (prefix) |
|---|---|---|
one-shot |
greppy -p |
edeaa1c109065b42 |
interactive |
terminal UI | 7cd2ccd0d083eebd |
serve |
greppy agent serve |
dd480def31ddda46 |
acp |
greppy agent stdio |
3683b8542fc14de0 |
external |
AGENTS.md for external agents |
5834ca668bf9025c |
The versions differ in one line about the role: with -p, someone reads the answer and the pull request and nothing else; with serve, another agent steers; in the terminal UI, a person can answer questions.
Worktree and sandbox
greppy creates the isolated worktree before the model gets its first request. Ignored files and build caches are not captured. The worktree has a private Git state: it reads the base commit's objects read-only, and its index, its refs, new objects and commits stay private until the verified proposal is imported.
A copy-on-write filesystem adapter (FSKit on macOS) speeds up creation when it is active. Without it, the agent uses ordinary private directories with the same proposal and apply flow.
greppy workspace setup # optional: install and activate the platform's adapter
greppy workspace doctor --json # optional: check it
greppy index --agent-worktree # optional: warm up the agent's worktree and Base ahead of time
Tool processes write to the worktree, a per-run scratch directory (TMPDIR), the worktree's greppy store and ~/.cargo/{registry,git}, and nowhere else. Reads and network stay open. Seatbelt enforces the confinement on macOS, Landlock on Linux. Credential environment variables are stripped from tool processes, and agent runs do not nest. --no-sandbox or GREPPY_NO_SANDBOX=1 turns the confinement off.
The agent rejects repositories with submodules, repositories in the middle of a merge, rebase, cherry-pick, revert or bisect, and repositories with checkout filters such as Git LFS before the model starts (exit 2).
Exit codes
| Code | Meaning |
|---|---|
| 0 | ok: clean, proposal saved or applied |
| 2 | no gateway, wrong usage, missing model or unsupported repository |
| 3 | agent or loop error; the unsaved worktree is kept for up to 24 hours |
| 4 | --apply refused (target not clean) or cherry-pick conflict; the ref stays available |
| 5 | incomplete: explicit turn cap or deadline reached; the proposal is saved |
| 130 | cancelled |
Upgrade from v0.3.3
v0.3.3 has the one-shot greppy -p and nothing else. The terminal UI, sessions, --continue, --resume, --json, greppy agent apply, agent serve, remote control and agent stdio come with 0.4.1. The flags --workspace-backend and --fresh from v0.3.3 no longer exist in 0.4.1.