Scripting & CI
Add -p (--print) and Syntic Code runs one task without the interactive screen, prints the result and exits. That makes it a building block for shell scripts, git hooks, CI jobs and your own tools.
syntic -p "explain what src/queue/retry.ts does in five bullet points"Feed it input
The prompt comes from the arguments. Anything piped on standard input is added after it, or is the whole prompt when there are no arguments:
git diff --staged | syntic -p "write a conventional commit message for this diff"
cat build.log | syntic -p "why did this build fail? one paragraph"
syntic -p < task.mdFlags can go before or after the prompt.
Choose the output
--output-format | You get |
|---|---|
text (default) | The final answer as plain text. |
json | One JSON object with the answer and run details. |
stream-json | One JSON message per line as the run happens. Needs --verbose. |
A json result looks like this:
{
"type": "result",
"subtype": "success",
"is_error": false,
"result": "The retry helper backs off exponentially…",
"session_id": "4fb72789-…",
"num_turns": 1,
"duration_ms": 577,
"stop_reason": "end_turn",
"total_cost_usd": 0.0478,
"cost_basis": "retail_estimate",
"cost_note": "Retail-price estimate. Usage covered by your plan isn't charged.",
"usage": { "input_tokens": 17274, "output_tokens": 42, "cache_read_input_tokens": 0 }
}syntic -p "count the TODOs in src" --output-format json | jq -r .resultWhen the run has a check result, the result also has a verification object: verified (true or false) and line (the turn’s Checked: or Verified: line), plus the checker’s verdict, summary, evidence, trigger, files, checks and duration_ms when the end-of-turn check ran. A script can fail a CI step on .verification.verified == false.
Nobody can answer a permission question in a -p run. By default the question goes to the host program (or the background approver); --permission-prompts none refuses every question at once so the run never waits.
Streaming
--output-format stream-json --verbose prints, one per line: an init record (model, tools, slash commands, MCP servers, permission mode, session id), status records, each assistant message, and a final result. Extra switches:
| Flag | Adds |
|---|---|
--include-partial-messages | Text and reasoning as they stream, token by token. |
--include-hook-events | A record for each hook that runs. |
--replay-user-messages | Echoes each user message before the reply. |
--forward-subagent-text | Subagents’ text and reasoning (their tool calls are always included). |
--input-format stream-json reads the prompt from standard input as the same kind of JSON messages, so a program can drive Syntic Code in its own wire format.
Structured answers
Ask for JSON that matches a schema, and Syntic Code checks it for you:
syntic -p "list the public functions in src/lib.rs" \
--json-schema '{"type":"object","properties":{"functions":{"type":"array","items":{"type":"string"}}},"required":["functions"]}'The schema can be inline or a file path. The answer is validated, retried once on a mismatch, and printed as JSON. If it still does not match, the run exits non-zero.
Permissions in scripts
Nobody is there to answer a prompt, so anything that would ask is refused instead, and the agent is told why. Decide up front what the run may do:
# allow the test runner and file edits, nothing else that asks
syntic -p "fix the failing unit tests" \
--permission-mode acceptEdits \
--allowed-tools "Bash(npm test:*)"| Option | Use it to |
|---|---|
--allowed-tools, --disallowed-tools | Allow or block specific tools and commands for this run. |
--permission-mode | plan for read-only reports, acceptEdits to let edits through, dontAsk to run only what allow rules cover. |
--tools "Read,Grep,Glob" | Offer only these built-in tools ("" for none). |
--permission-prompt-tool <mcp tool> | Let your own MCP tool answer approval questions. |
--dangerously-skip-permissions | Skip prompts entirely. Only in throwaway environments such as containers. Deny rules still apply. |
Inside an untrusted folder, -p runs in restricted mode (no project settings, hooks, MCP servers or agents) and prints a note when the folder has project configuration.
Keep runs bounded
| Option | Effect |
|---|---|
--max-turns <n> | Stop after n agent turns. |
--max-budget-usd <amount> | Stop when the run’s estimated cost passes this amount; the result says error_max_budget_usd. |
--task-budget <amount> | A per-task cap, applied with --max-budget-usd (the tighter wins). |
--model, --fallback-model | Pick the model, and one to use if it is unavailable. |
--effort low | Less reasoning for simple jobs. |
Continue a conversation
syntic -p "find where we validate email addresses" --session-id 11111111-2222-4333-8444-555555555555
syntic -p --resume 11111111-2222-4333-8444-555555555555 "now add a check for plus-addressing"
syntic -p -c "and update the changelog" # latest session in this folder--no-session-persistence keeps a run from being saved at all.
Make runs repeatable
| Option | Effect |
|---|---|
--bare | No settings hooks, plugins, skill discovery, auto-memory or background work; only MCP servers you pass with --mcp-config. |
--setting-sources user,local | Read only these settings files. |
--settings '{"model":"Syntic Code Fast"}' | Layer extra settings (inline JSON or a file) for this run. |
--mcp-config servers.json --strict-mcp-config | Use exactly these MCP servers. |
--system-prompt-file, --append-system-prompt-file | Replace or add to the system prompt from a file. |
--exclude-dynamic-system-prompt-sections | Keep machine-specific details out of the system prompt so caching works across machines. |
--dump-system-prompt | Print the system prompt your settings produce, and exit. |
MCP_CONNECTION_NONBLOCKING=true | Do not wait for slow MCP servers: give them a short window (5 s, or MCP_CONNECT_TIMEOUT_MS) and leave out any that are not ready (MCP servers). |
Exit codes
| Code | Meaning |
|---|---|
0 | The run finished. |
1 | The run failed: an API error, not signed in, a budget limit, or a --json-schema mismatch. With json output, is_error is true. |
2 | Bad usage, such as an unknown flag value. |
Run in CI
Any CI system that can run a shell command can run Syntic Code. Make the syntic binary available on the runner (on its PATH, or cached between jobs), and sign in with a refresh token stored as a CI secret (Sign in):
# GitHub Actions example
- name: Review the change
env:
SYNTIC_OAUTH_REFRESH_TOKEN: ${{ secrets.SYNTIC_TOKEN }}
run: |
syntic -p "review the diff against main for bugs; reply LGTM if none" \
--permission-mode plan --output-format json > review.json# GitLab CI example
review:
script:
- syntic -p "summarize the changes in this merge request" --permission-mode plan
variables:
SYNTIC_OAUTH_REFRESH_TOKEN: $SYNTIC_TOKENComplete pipelines for both, with review comments, scheduled jobs and cost limits, are in Run in CI pipelines.
Commands that only make sense on the interactive screen, such as /compact and /rename, are refused in -p runs with a short message. Background helpers and update checks stay quiet when CI is set. Commands left running in the background are stopped when the run ends.
Slash commands in -p runs
A prompt that starts with / is handled before anything reaches the model:
| The prompt is | What happens |
|---|---|
/goal <condition> | The run works toward the goal, checking after each round. |
A built-in command that stands for a request, such as /review, /code-review, /security-review or /commit | Expanded into that request and run. |
A custom command from .syntic/commands/ or ~/.syntic/commands/ | Its body is expanded with your arguments and sent as the prompt. |
| The name of a skill | The prompt is sent as is, and the agent loads the skill with its Skill tool. |
| A command that needs the interactive screen | Refused with a short message; nothing is sent. |
| Anything else | Reported as an unknown command; nothing is sent, and the run exits with 2 (or 1 with a JSON result in json and stream-json modes). |
--disable-slash-commands turns this off, so a leading / is just text.
Drive it from code
syntic mcp serve exposes Syntic Code’s built-in tools to any MCP client over standard input and output. See MCP servers.