Skip to main content

Headless & CI

byteask with no arguments opens the interactive TUI, which needs a terminal. For scripts, pipelines and CI, use byteask exec - it runs one task to completion and exits.

byteask exec "explain what src/parser.rs does"
byteask exec - # read the prompt from stdin
echo "review this diff" | byteask exec -

You do not need script -q /dev/null or a pty wrapper. If you find yourself reaching for one, you are running the TUI; add exec.


The sandbox - read this first​

Shell commands the agent runs are sandboxed read-only by default. That is the single most important thing to know about headless runs, because a read-only sandbox means the agent cannot compile anything: cc cannot write its object files, and it cannot even write to TMPDIR. You will see errors like:

clang++: error: unable to make temporary file: Read-only file system

That is the sandbox working as designed, not a broken toolchain.

ModeFlagWhat the agent's shell commands can do
read-only(default)Read files, run analysis. No writes anywhere, including TMPDIR.
workspace-write--sandbox workspace-writeRead anywhere; write inside the working directory. Builds, test runs and generated files work.
danger-full-access--sandbox danger-full-accessNo sandbox at all. Only for throwaway containers.

If you want the agent to build, test, or write files, pass --sandbox workspace-write.

byteask exec --sandbox workspace-write "build the project and fix any compile errors"

-s is the short form. Approvals are non-interactive in exec, so there is no prompt to escalate with - the mode you pass on the command line is the mode you get for the whole run.

Tools that are not affected by the sandbox​

The sandbox governs the agent's shell tool. ByteAsk's built-in native tools run as direct children of the engine and are not subject to it, so they work even under the default read-only mode - including the ones that compile and execute code:

FamilyTools
Build / analyse / run C and C++cpp_sanitize (ASan, UBSan, Valgrind), cpp_check, cpp_tidy, cpp_format, cpp_compile_db, cpp_nav, cpp_layout
Performancecpp_perf, cpp_bench
Binaries and debuggingcpp_binary, cpp_symbolize, cpp_decompile, debug, debug_session, debug_attach, debug_record
Online servicescpp_godbolt, cpp_insights, cpp_intrinsic
Grounded documentation searchautosar_ref, mcu_ref, fpga_ref, hft_ref, grid_ref, scpi_ref, x86_ref

So "the sandbox is read-only" does not mean "ByteAsk can only do static analysis". A read-only run can still build your program under AddressSanitizer and run it. What a read-only run cannot do is let the model hand-roll its own clang++ -fsanitize=address ... through the shell.

Known limitation

In the current release, byteask exec does not print these native tool calls - neither in human output nor in --json. The tool runs and its result reaches the model, but you do not see it happen, which makes a successful sanitizer run look like nothing happened. A fix is in progress. Until it ships, add a line like "name each tool you call and quote its key output" to your prompt; the agent's narration is rendered.


Machine-readable output​

--json​

Streams the session as JSON Lines on stdout - one event per line. Use it when a pipeline needs to consume the run rather than a human reading it.

byteask exec --json "list every TODO in src/ with its file and line" > run.jsonl

-o / --output-last-message​

Writes just the agent's final message to a file. Usually what you want when the rest of the transcript is noise.

byteask exec -o review.md "review src/parser.rs and list defects with file:line"
cat review.md

--output-schema - structured output​

Point at a JSON Schema file and the model's final response conforms to it, so you can parse the result instead of scraping prose.

byteask exec --output-schema schema.json -o result.json "…"
jq . result.json

The schema is sent in strict mode, which imposes two rules your schema must satisfy:

  • every object must set "additionalProperties": false;
  • every property must be listed in that object's "required" array - there are no optional fields.

If you want a field to be omittable, model it as an empty string or an empty array instead.


Recipe: read-only review that proposes fix diffs​

A common CI shape is "review this code, do not touch it, and tell me exactly what to change". Under the default read-only sandbox the agent cannot write files or apply patches - so ask it to return the diffs as data.

Download the ready-made schema:

curl -fsSLO https://code.byteask.ai/patches.schema.json

It describes:

{
"summary": "…",
"patches": [
{ "file": "src/pool.hpp", "unified_diff": "--- a/…\n+++ b/…\n@@ …", "rationale": "…" }
]
}

Run it:

byteask exec \
--sandbox read-only \
--output-schema patches.schema.json \
-o patches.json \
"Review include/pool.hpp for memory-safety defects. Use cpp_sanitize to confirm each finding
at runtime before reporting it. Do not modify any file. Return one patch per file that needs
changing, as a unified diff I can pass to 'git apply'. If a finding has no safe fix, return no
patch for it and explain why in the summary."

Then apply what you agree with:

jq -r '.patches[].unified_diff' patches.json | git apply --check - # dry run
jq -r '.patches[].unified_diff' patches.json | git apply -

Two honest caveats​

1. A schema pulls the model toward answering immediately. This is the important one, and it is true on every model, not just some. Once a response schema is attached, the model is biased to produce a conforming answer now rather than to spend turns calling tools first - we have observed a model return {"patches": [], "summary": ""} without opening the file at all.

So --output-schema works best on a final-answer turn, not spread across a long agentic run. If the task needs real investigation, split it:

# 1. investigate, no schema - let the agent use its tools freely
byteask exec --sandbox workspace-write -o findings.md \
"Find and confirm memory-safety bugs in include/. Use cpp_sanitize. Write up what you proved."

# 2. convert the findings into structured patches, with the schema
byteask exec --output-schema patches.schema.json -o patches.json \
"Turn these confirmed findings into unified diffs. $(cat findings.md)"

The instruction "use cpp_sanitize to confirm each finding before reporting it" in the single-command form above is doing real work - without it, a schema-constrained run will often skip straight to an answer.

2. --output-schema currently reaches OpenAI models only. On Claude, Gemini and self-hosted models the flag is accepted and then discarded, so you get ordinary prose back. The fix is written and tested but not yet deployed. Until it is, use -m gpt-5.4 (or another OpenAI model) for schema-constrained runs, and check the changelog before assuming otherwise.


Other flags worth knowing headless​

FlagWhy it matters in CI
--skip-git-repo-checkRequired when the working directory is not a Git repository.
--ephemeralWrites no session files to disk. Good for ephemeral runners.
--ignore-user-configIgnores ~/.byteask/config.toml so a runner's behaviour does not depend on a stray local file.
--color neverSuppresses ANSI escapes in captured logs.
-m MODELPins the model. Do this in CI - the default can change between releases.

See the CLI Reference for the full flag list.