Add a CLI agent
Build an adapter that starts your agent CLI and reads its output as Outpost events.
Write a minimal adapter
Section titled “Write a minimal adapter”Implement an AgentAdapter to describe how your CLI starts and how its output becomes events: request() builds the command and events() reads its output lines. A CliHarness binds that adapter to the selected model, and createAgent() makes it usable in a dispatch.
Outpost runs mycli --json --model mycli-pro in the sandbox with the brief on stdin, passes each stdout line to events() and returns the collected text in result.text. Install the CLI in your agent image first.
Build the command
Section titled “Build the command”request() receives an AgentInput and returns a Command: executable, arguments, stdin, variables. Outpost adds the deadline and the cancellation signal.
API reference: AgentInput.
Decode the output
Section titled “Decode the output”events() receives each stdout line and returns zero, one or several events. Stderr never reaches it: Outpost reports stderr lines as stderr events.
API reference: AgentEvent.
Other kinds, such as tool, tool-result, reasoning, file-change and warning, reach only observers. A nonzero exit status fails the turn. Without text or result events, result.text holds the end of stdout.
Declare optional capabilities
Section titled “Declare optional capabilities”Each optional member enables one feature. Declare only what the CLI really does.
API reference: AgentAdapter.
Report token usage
Section titled “Report token usage”usage tells Outpost where the counters come from. Incomplete usage is a lower bound that budgets treat separately.
API reference: Usage.
Spread sessionUsage into the adapter. The command has five seconds and is skipped when a cumulative usage event already gave the totals. On a continued conversation, Outpost measures a baseline first and keeps the difference; a fork has no baseline, so its usage is incomplete.
With storage, transcriptUsage(text) can instead read the totals from the captured transcript.
Steer a running turn
Section titled “Steer a running turn”A steered dispatch reaches your CLI in one of two ways.
| Adapter | Delivery | What happens |
|---|---|---|
With liveInput | injected | Outpost writes each instruction to the running process’s stdin. |
resumable: true, no liveInput | resumed | Outpost stops the process once its conversation is known, then resumes it with the text. |
| Neither | ― | The dispatch is rejected before it starts. |
encode() turns one instruction into stdin text. read() sees every stdout line and returns the number of messages the CLI confirmed, plus protocol replies to write, such as answers to permission requests.
The prompt counts as the first message to confirm. Outpost keeps stdin open and closes it after a finished event once every message was consumed.
Injection also needs a SandboxLease with liveInput: true, which every built-in provider returns. On a custom provider without it, a resumable adapter falls back to resumed.
What Outpost handles for you
Section titled “What Outpost handles for you”- ProcessDeadlines, idle timeouts and cancellation stop the whole process group.
- Sandbox and workspaceAllocation, the worktree, commits and cleanup work as for built-in agents.
- Agent homeThe plans from
credentials()andconfiguration()are installed in the private sandbox home. - AnswersTyped responses, repairs and completion markers apply to your decoded text.
- UsageCounters add up across turns, retries and workflows, and feed budgets.
- ObservationDecoded events, raw lines and stderr reach
observe, reporters and journals.
Test the adapter
Section titled “Test the adapter”Record real output lines of the CLI once, then replay them through events(). diagnoseAgentProtocol() checks the built-in agents the same way.
Add fixtures for failures, and check that quota() matches only terminal limit messages, not retry notices. Then run one real dispatch in a container: fixtures do not test installation, sign-in, exit status or capture.
Limits
Section titled “Limits”- Remote bootstrap installs only built-in CLIs. Install yours in the image of every provider you use.
outpost init,outpost doctoranddiagnoseAgentProtocol()know only the built-in agents.- One stdout line holds at most 16 MiB; a longer line fails the turn.
API: createAgent · CliHarness · AgentAdapter · AgentInput · AgentEvent · AgentLiveInput · Usage · diagnoseAgentProtocol.