Editors, SDKs & CI
The terminal is one way to reach the agent, not the only one. The same agent runs inside an editor, inside an application you are building, inside a shell script, and inside a CI job. Whichever way you reach it, the sessions, the permission rules, and the savings accounting are the same, so work started in one place can be picked up in another.
contents
contents
In your editor
Some editors drive a coding agent over the Agent Client Protocol, and Squeezy speaks it. The editor starts squeezy acp as a child process and exchanges messages with it over that process's own input and output. Nothing installs a background service and nothing opens a network port. The command is not listed in squeezy --help, because the editor starts it rather than you.
An editor session is an ordinary session, kept in the same local store under the same id, so work started in the editor can be resumed in the terminal and handed back again. When the editor closes the agent's input, the turn in flight is cancelled and the process exits. What you get inside the editor is the whole session, not a reduced one:
- Answers stream in as they are written, with the model's reasoning beside them.
- Each tool call appears when it starts, reports progress while it runs, and shows its result.
- Permission requests arrive as prompts you answer in the editor.
- The plan updates in place, with a running token count. An estimated cost appears once the model's pricing is fully known.
- The same modes are available: Chat, Plan, Edit, and Orchestrate. Edit is the terminal's Build mode under the protocol's name for it.
- Cancel a turn, change mode, list earlier sessions, or delete one, without leaving the editor.
squeezy acp In your own application
squeezy app-server --stdio runs the agent as a local server your application owns. Your code starts the process, and the two exchange one JSON message per line over that process's input and output. The first message is a handshake where your client states which optional features it can handle, so the server does not send the optional events your code would ignore.
From there your application drives whole sessions: start one, resume one, fork it, name it, archive it, list them, delete one. Inside a turn you receive the same stream an editor receives, plus the lifecycle of every subagent the run spawns, and you can steer a turn while it is running or cancel it. Permission requests come to you, so you build the approval experience your product needs instead of inheriting a terminal's.
Clients for Rust, TypeScript, and Python ship with Squeezy. Each one starts the process, performs the handshake, keeps concurrent requests straight, and shuts the process down when it is finished. The shape stays small on purpose: a child process your application started, no background service, and nothing listening on the network, which keeps the security review short.
Ask for it in the handshake and the server will also report what a session's savings ledger recorded, so a product built on Squeezy can show its own users the accounting the terminal shows. That one is marked experimental, and its shape can still change.
squeezy app-server --stdio In a script, headless
squeezy --prompt runs one prompt without opening the terminal interface and writes the answer to stdout. Piping text in does the same thing with no flag at all. --cd DIR runs as if launched from another directory, so a Makefile recipe or a container entrypoint needs no shell wrapper around it.
A pipeline usually wants more than the answer. --format result-json returns one object once the run finishes, and --format json streams one line per event while it runs. -o FILE writes the final answer where the next step can read it. --allow-tool and --deny-tool narrow what the model may use, --max-model-steps caps how many model and tool steps the run may take, and --prompt-permission-mode fail-on-ask ends the run on any permission prompt rather than leaving one for nobody to answer.
Exit codes are a contract. 0 is success. 1 is a failure. 2 is a malformed invocation, which will fail the same way every time. 3 is a name that does not exist, such as an unknown session, provider, or config key. 75 is a connection that never came back, which is safe to run again. A wrapper branches on the number instead of parsing error text.
squeezy --prompt "summarize the failing tests in this repo"
git log -1 --format=%s | squeezy
squeezy --prompt "$TASK" --format result-json --prompt-permission-mode fail-on-ask One interface for CI
Asking why the build broke should be one question, not a guess about which CI system this repository uses. squeezy ci answers in the same shape whichever provider is behind it. status reports the current pipeline and its jobs. failures narrows to the jobs and steps that failed, each with a window of log around the failure. log fetches one job's log, cut down to the failure context and the tail. In a poll loop, --changed-only returns a short stub when nothing has moved since the identical last query.
GitHub Actions and GitLab CI have adapters. Each works through that provider's own command line tool, so gh or glab has to be installed and signed in for this repository. A repository configured for anything else gets a structured answer naming the provider and the raw command to run instead, rather than a tool that looks broken.
Reading CI and changing CI are separate authorizations. Every read above changes nothing. rerun is the one exception, and it refuses to run without --authorize-mutation, so asking a question can never restart a pipeline as a side effect. There is no cancel and no approve.
squeezy ci status
squeezy ci failures
squeezy ci log 42
squeezy ci rerun --authorize-mutation Watching a pull request
squeezy pr watch takes one snapshot of a GitHub pull request: its checks, any new review feedback, and whether it can merge. Poll again and it reports only what changed since the last poll, so an hour-long watch pays for the changes rather than for the polls. It reads through the gh command line tool, which has to be installed and signed in.
It is careful about what counts as feedback worth acting on. Unsubmitted draft reviews are left out: GitHub returns those only to their author, so they are the watcher's own notes rather than published feedback. Comments from accounts with no standing on the repository are left out too. A drive-by comment on a public repository is not a review, and an agent that treated one as an instruction could be steered by anyone with an account. Both exclusions are counted in the output rather than hidden.
Each snapshot ends with what the state mechanically implies: read the new review comments, look into a failing check, retry while the retry budget has room, or stop because the pull request is closed. The command itself changes nothing. No merge, no reply, no rerun. Acting on what it reports stays with you.
squeezy pr watch
squeezy pr watch --watch --json