Headless mode, the SDK and CI
Run non-interactive agent tasks, drive the server over HTTP from your own code, and put a constrained review step into a pipeline.
Non-interactive runs
# one task, then exit
opencode run "summarise the changes in the working tree"
# continue the previous session with a follow-up
opencode run -c "now write the changelog entry"
# constrain the run
opencode run --agent plan --model anthropic/claude-haiku-4-5 \
"list the files that import the deprecated client"
# keep the server running so several clients can attach
opencode serve --port 4096| Command | Purpose |
|---|---|
opencode run | Single non-interactive task |
opencode run -c | Continue the most recent session |
opencode serve | Headless server exposing an HTTP API |
opencode auth list | Confirm credentials are present in CI |
--print-logs | Emit diagnostic logs to stderr |
⚠️
A CI runner with a repository token and network access is a powerful place for an unconstrained agent to run. Use the plan agent for anything read-only, deny push and deploy commands, and give the job a token that cannot write to the default branch.
The HTTP API and SDKs
opencode serve --port 4096
# then, from anywhere on the same host
curl -s http://localhost:4096/session | head -c 400import { createOpencodeClient } from "@opencode-ai/sdk";
const client = createOpencodeClient({ baseUrl: "http://localhost:4096" });
const session = await client.session.create({ body: { title: "nightly review" } });
const result = await client.session.prompt({
path: { id: session.id },
body: {
agent: "plan",
parts: [{ type: "text", text: "List any handler added in the last 24h without input validation." }],
},
});
for (const part of result.parts ?? []) {
if (part.type === "text") console.log(part.text);
}- The SDK is a thin client over the same API the TUI uses, so anything the terminal can do is scriptable.
- A Python SDK exists with the same shape for teams standardised on Python tooling.
- Sessions created this way are ordinary sessions - resumable, listed, and inspectable afterwards.
- Start the server once per job and reuse it; process startup is the slow part when you run many small tasks.
A review job
name: agent-review
on: pull_request
jobs:
review:
runs-on: ubuntu-latest
permissions:
contents: read
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: actions/setup-node@v4
with:
node-version: 22
- run: npm install -g opencode-ai
- name: Review the diff
env:
ANTHROPIC_API_KEY: ${{ secrets.ANTHROPIC_API_KEY }}
run: |
opencode run --agent plan \
"Review the diff against the base branch. Report only defects that would block a merge, each as file:line and one sentence." \
> review.txt 2>&1 || true
- uses: actions/upload-artifact@v4
if: always()
with:
name: agent-review
path: review.txt- Use the plan agent: a reviewer that cannot write is a reviewer whose findings you can trust.
- Grant
contents: readonly; a review job has no business pushing. - Upload the transcript even on failure - it is the only record of what the agent saw and concluded.
- Set a job timeout and a spend limit on the API key; an unattended agent loop is an unattended bill.
# run the same job locally before trusting it in CI
docker run --rm -v "$PWD:/work" -w /work \
-e ANTHROPIC_API_KEY node:22 \
sh -c "npm install -g opencode-ai && opencode run --agent plan 'summarise the diff'"FAQ
What is the difference between running the CLI and using the SDK?
The CLI is the fastest way to get a result inside a script and needs no extra code. The SDK is for when the agent is part of a larger program: maintain a session across calls, stream events into your own interface, or coordinate several sessions. Both go through the same server.
Can OpenCode run without a network in CI?
Yes, if the runner can reach a local model server that you start first. Point the configuration at that provider's base URL and no hosted provider is involved, which keeps prompts inside the runner.
Related
Sessions, snapshots and undo Permissions, privacy and secret handling
Last refreshed 2026-09-18.