Features

Hand off tasks, get commits back

What you get

Your main agent plans and delegates, and greppy implements. greppy -p "TASK" starts a coding agent that works in its own copy of your repository and ends with a commit: the pull request. Your checkout stays untouched, and so do your uncommitted changes. Several tasks run in parallel, each in its own worktree. You review every commit and apply what fits.

How a task runs

  1. greppy creates a temporary copy-on-write worktree: the current commit plus your uncommitted changes, staged, unstaged and untracked. Ignored files such as node_modules or target stay out. A shared index covers the unchanged code and follows the agent's changes.
  2. The agent has one tool: greppy. It navigates through the graph, reads definitions, changes symbols and runs build and tests as bash-smart -- CMD. It can write in its worktree. Reading and the network stay open.
  3. The agent works until the task is done. There is no fixed turn limit. --max-turns N sets one if you want it, followed by a report turn without tools. Tools have no fixed timeouts; --deadline-secs N bounds the whole run.
  4. The changes in the worktree become a commit on refs/greppy/agent/<run-id>, the pull request. Its parent is your starting state including uncommitted changes, so the commit contains exactly the agent's work. The commit message is the agent's final answer: title, Status: (done, partial or blocked), what changed, how it was verified, what is open.
  5. Once the pull request is saved, greppy deletes the worktree. That also holds when the deadline ends the run: exit 5, and the pull request is there all the same. With --keep-worktree the worktree stays; after a failure without a pull request, greppy keeps it for 24 hours.
  6. git show REF shows the commit, and greppy agent apply REF applies exactly the agent's changes. Your Git index stays byte-identical.

An acceptance test checks this flow with real runs: 13 of 13 clauses passed.

How it works

Called by your main agent

Your main agent starts the task in its shell, waits for it to finish and reads the result:

greppy -p "Fix the bug in clamp: values above the range must return the upper bound. Add a test." \
  --deadline-secs 1800 --json > run.jsonl
tail -n 1 run.jsonl                             # the result event: status, exit_code, proposal_ref
git show refs/greppy/agent/<run-id>             # review the pull request
greppy agent apply refs/greppy/agent/<run-id>   # apply it

With --json, greppy writes one JSON event per line to stdout: session, text, tool_start, tool_finish, turn_complete, error and, as the last line, result. The result event carries status, exit_code and proposal_ref, so your main agent knows where the pull request is. An aborted run ends with a result event as well, exit 130. With --continue or --resume ID, a follow-up task continues the session.

$ greppy -p --help
…
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

Flags:
…
  --max-turns N       Optional cap on action turns, followed by one tool-free
                      report turn (unlimited by default)
  --deadline-secs N   Wall-clock budget in seconds (env GREPPY_DEADLINE_SECS);
                      the loop stops between turns; tool calls already issued
                      run for at most 30 s past the deadline
…
  --json              Stream newline-delimited JSON events on stdout (`greppy -p` only)
…
Exit codes:
  0  ok (clean, proposal saved, or applied)
  2  no gateway / bad usage / missing model / unsupported repository
  3  agent or loop error (unsaved workspace retained for up to 24 hours)
  4  --apply refused (dirty target) or cherry-pick conflict (ref still available)
  5  incomplete (explicit turn limit or deadline reached; proposal saved)

What the subagent is told

Every mode has its own system prompt. greppy prompt --mode one-shot prints the one for -p exactly, and with --json it adds the SHA-256 of this version. The prompt tells the agent that its result is a pull request and that nobody answers questions.

$ greppy prompt --mode one-shot
…
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.
…
DONE means the pull request can be merged as it is: the task is fully implemented, the relevant tests pass, new behaviour has a test, and the diff contains nothing else (smallest change, in the style of the surrounding code). Do not stop at an analysis. If you are blocked, name the missing dependency; never claim a result you have not seen.

FINAL ANSWER is the pull request's description: a one-line title; Status: done, partial or blocked; what changed and why (file:line); how it was verified (commands and results); what is open.

-p: a person, a script or another agent reads only your final answer and the pull request; nobody can answer questions, so decide details yourself and name them.
…

Remote control

greppy agent serve holds a session headless on a Unix socket. Other shells and other agents control it through its session ID or a unique prefix:

greppy agent serve --model MODEL
greppy agent send ID "Add a test for empty ranges" --wait --json
greppy agent attach ID --json      # follow events live
greppy agent interrupt ID          # abort the running turn
greppy agent quit ID               # end the session

The control socket belongs to your user account: every process under your account can control the session, other agents included. greppy agent opens the same agent as a terminal UI, with the same flow of worktree, sandbox and pull request.

The model comes through your gateway

You choose the model. greppy speaks the Anthropic Messages API to a local gateway; the default is http://127.0.0.1:8317. CLIProxyAPI is the standard gateway for this and translates the major providers. The model ID passes through unchanged, and the key sits in an environment variable, never on the command line.

export GREPPY_ENDPOINT=http://127.0.0.1:8317   # default
export GREPPY_MODEL=MODEL                      # a model ID your gateway offers
export GREPPY_API_KEY=…                        # if your gateway requires a key

The commands

Command what it does
greppy -p "TASK" starts a task headless; the result is a commit on refs/greppy/agent/<run-id>
greppy -p "…" --json one JSON event per line, last the result event with proposal_ref
greppy -p "…" --deadline-secs N time budget for the whole run; the pull request is created even when the budget runs out
greppy -p "…" --apply applies the changes directly to your checkout at the end
greppy -p "…" --continue, --resume ID continues the last session or a specific one
greppy agent the same agent as a terminal UI
greppy agent serve holds a session headless on a Unix socket
greppy agent send ID TEXT sends a task to a running session; --wait streams its events until the end of the turn
greppy agent attach ID follows the events of a running session live
greppy agent interrupt ID, greppy agent quit ID aborts the running turn, ends the session
greppy agent apply REF applies a pull request onto exactly the starting state it was built on
greppy prompt --mode one-shot prints the agent's system prompt for -p exactly; --json names its SHA-256

More in the docs