v0.2.1
Initial public release. The CLI surface, exit codes, config schema,
and --json envelope are intended to be stable across 0.2.x;
breaking changes that landed before this release (e.g. flag
renames, schema renames) are listed under Removed.
Added
Surface
- Prompt sources: positional argument,
-p, --prompt TEXT
(explicit prompt string; mutually exclusive with the positional
argument -- the escape hatch when the positional form would be
ambiguous against an optional-value flag like-cor-w, e.g.
roba -c -p "follow up"), stdin (-or piped),-f FILE,
-e(compose in$EDITOR/$VISUAL),--editor-history N
(last N responses included as reference block in the editor). - Composition:
--prepend FILEand--append FILE
(repeatable),--attach GLOB(repeatable, embeds files with
File: PATHframing),--git-diff,--git-log [N],
--git-status,--var K=Vtemplate substitution. - Output:
--json(versioned envelope on stdout),--quiet
(answer only, no metadata),--code [LANG](extract fenced
blocks),-o, --out PATH(write to file AND stdout, extension
drives format),--stream(TTY-only progress indicator),
--show-thinking(extended-thinking blocks live on stderr,
requires--stream),--trace PATH(writes spawned claude
streaming events to PATH as JSONL; observability handle for
in-flight runs),--echo(print resolved prompt),--plain
(master kill-switch: no markdown render, no color, no spinner). - Dispatch session id on stderr: when the streaming pipeline
is active (--streamor--trace), roba prints[roba] session: <id>to stderr as soon as the spawned session id
becomes known (first event). Gives orchestrators a stable handle
to the session JSONL without requiring--traceto be set
upfront. Suppressed by--quiet. - Sessions:
-c [ID](bare = continue most recent in cwd;
-c IDor-c=ID= resume specific session by id),--fork
(branch a resumed session; requires an explicit id,-c ID --fork),--pick(interactive fuzzy chooser),--fresh(force
new session, cancels env/profile continue),--agent NAME(pin a
specific Claude Code subagent for the run),-w, --worktree [NAME](run in a fresh git worktree; named or auto-generated). - Permissions:
--readonly(Read/Glob/Grep only -- the
default),--writable(adds Edit/Write),--allow-tool TOOL
(repeatable),--deny-tool TOOL(repeatable),--full-auto
(bypass everything),--permission-mode MODE(pass a specific
claude permission mode --plan,dontAsk,auto,
acceptEdits,default,bypassPermissions-- orthogonal to
the allowlist shortcuts; the shortcuts set the allowlist, this
sets the mode),--show-permissions(preview the
effective allow/deny set with per-entry provenance and exit 0
without calling claude),--no-agent-check(suppress the
agent frontmatter permission check). - Agent frontmatter permission check: when
--agent NAMEis
set, roba parses the agent'stools:field from its YAML
frontmatter and warns on stderr if any declared tools are not
covered by the resolved allowlist. GranularBash(git:*)allows
count as covering bareBash. The check is best-effort and
non-blocking -- dispatch proceeds regardless. Suppressed by
--full-auto,--quiet, and--no-agent-check; also
honoured viaROBA_NO_AGENT_CHECKenv var andno_agent_check = truein a profile. Closes the silent partial-capability trap
when a lower-layer profile doesn't grant what the agent needs. - Other dispatch flags:
-C, --cwd PATH(run as if invoked
from a different directory),--model NAME(override the model
per call),--no-retry(disable wrapper-level auto-retry on
transient failures; deterministic for orchestrator scripts),
--effort LEVEL(cost/quality tradeoff --low,medium,
high,xhigh,max),--bare(minimal-overhead mode: skip
hooks, LSP, plugin sync, CLAUDE.md auto-discovery, auto-memory,
and keychain reads -- for non-interactive dispatches),
--system-prompt TEXT(replace the default system prompt) and
--append-system-prompt TEXT(append to it; when both are set,
replace runs first),--dispatch(preset for unattended
file-mutating workers -- implies--full-auto,--worktree,
and--fresh, each individually overridable; warns when
--agentis unset). - Cost in dollars:
roba costnow reports a dollar figure
alongside tokens, computed from a bundled per-model rate table
(src/rates.toml, baked in viainclude_str!). Per-project
breakdown (--by-project) gains aCOSTcolumn and--json
gains acost_usdfield (rollup + per project) plus an
input/output/cacheusagebreakdown. Dollars also appear in
the per-call footer. Override the table with--rates-file PATH
(orROBA_RATES_FILE), or suppress dollars with--no-dollars
when the bundled rates are stale; the table carries anas_of
date surfaced on the report. Models the table doesn't cover are
listed as "rates unknown" rather than costed at a misleading $0. - Subcommands:
roba history [--paths [N]](list recent
sessions;--pathsemits the JSONL session file paths,
most-recent first, for shell composition and corpus mining),
roba last(reprint last run),roba cost [--by-project] [--project SLUG] [--json] [--rates-file PATH] [--no-dollars]
(token + dollar usage rollup),
roba profile {list,show,init,path,active},
roba alias {list,show,path}(user-defined aliases from
roba.toml). see_alsoerror-envelope field: additive v1 field on the
--jsonerror envelope (error.see_also, a list of doc URLs).
Omitted from the JSON when empty, so the v1 shape is unchanged for
errors with no doc pointer.
Config
roba.tomlconfig file with layered resolution:
CLI > env (ROBA_<PARAM>) > active profile overlay >
top-level keys > built-in default > claude default. Project
files walk up to the git root; closer-to-cwd wins per key;
lists concat across files; vars merge per key.- Profiles:
[profile.NAME]overlays in anyroba.toml;
defaultprofile auto-applies when none is named (suppressed
via--no-default-profileorROBA_PROFILE=). - User-defined aliases:
[alias.NAME]shortcuts. Each alias
is invoked asroba NAME [args]and expands to a prompt
template (with positional${1}/${@}, named${pr}via the
argsschema,$$for literal$, and$(command)shell
substitution) plus defaultflags. Aliases can pin a subagent
(agent = "NAME") and override CLI flags. Lookup order:
built-in subcommand first, then alias, then unknown-alias
suggestions (Levenshtein top-3). - Env-var override layer: every CLI knob is settable via
ROBA_<PARAM>(uppercased,-->_, prefixedROBA_).
Lists comma-separated; vars per-key viaROBA_VAR_<KEY>.
Output discipline
- stdout = the answer; stderr = metadata (cost footer, tool calls,
refusal warnings, spinner, errors). - Auto-detect: rich on a TTY, plain on a pipe.
NO_COLOR=1
honored. - Versioned JSON envelope (
--json):- Success:
{ "version": 1, "result": { QueryResult }, "refusal": bool } - Error:
{ "version": 1, "error": { kind, message, exit_code, chain } } - V1 contract: top-level
versionalways present;resultxor
error; inner fields preserved across additive changes;
breaking shape changes bump the version.
- Success:
- Refusal signal (
refusal: boolin the success envelope) for
non-TTY consumers; exit code stays 0 on refusal (the call
succeeded, the heuristic labels the body). - Structured JSON error envelope: runtime failures emit a
parseable{ "error": {...} }object on stderr instead of plain
anyhow text.kindmirrors the typed exit code.
Permissions precedence + cross-layer suppression
- CLI
--readonlyactively suppresses lower-layerwritable = trueandfull_auto = true. CLI--writablesuppresses
lower-layerfull_auto = true. Mutual-exclusion holds across
layers, not just within the CLI parse. allow_tool/deny_toollists accumulate across files;
closer-to-cwd entries concat on top of farther-from-cwd.
CLI / env replace the resolved list; profile concats.- Deny wins when the same tool appears in both lists.
Failure modes
- Typed exit codes: 0 ok, 1 generic, 2 auth (re-login needed), 3
budget exceeded, 4 timeout. - Fail-fast on interactive flags without a TTY:
-e,--pick,
and--editor-history N > 0exit 1 with a clear message
instead of hanging on input that can't arrive. --no-retryflag andROBA_NO_RETRY=1env var disable
wrapper-level auto-retry for the run.
Changed
- Permissions precedence model documented in
README.md
(## Permissions->### Precedence) anddocs/profiles.md.
Spells out the CLI > env > profile overlay > top-level >
built-in default layering, thewritable/full_auto
interaction, the concat-vs-replace behavior for tool lists, and
the deny-wins rule. --quietvs--plainhelp text disambiguated. They're
orthogonal:--quietis the metadata kill-switch (suppress
footer, spinner, tool markers);--plainis the decoration
kill-switch (no markdown render, no color, no spinner).--readonlyis now an active suppressor rather than a
no-op marker. Passing--readonlyon the CLI cancels a
writable = trueorfull_auto = truecoming from a profile
or env var.--streamdocumented as a TTY-only nicety, never
load-bearing on a pipe; the agent-ABI surface (--json, typed
exit codes, error envelope) is the contract for non-TTY
consumers.- Security audit moved off the PR critical path to a daily
scheduled job (.github/workflows/security-audit.yml) + manual
workflow_dispatch. PR CI feedback no longer waits on the
audit's full dep-tree scan. - BREAKING (pre-publish):
-c/--continueand-w/
--worktreeno longer require=for their values. The
require_equalsconstraint was dropped, so the natural
space-separated form now works (roba -c 7c3f9a21,
roba -w mybranch). The trade-off: because the value is
optional, a bare word right after the flag is consumed as that
value, soroba -c "follow up"now treatsfollow upas the
session id androba -w "do it"treatsdo itas the worktree
name (previously these were parsed as the prompt). The documented
escape is the new-p/--promptflag:
roba -c -p "follow up",roba -w mybranch -p "do it". The
=form (-c=ID,-w=NAME) still works unchanged.
Removed
These are pre-publish breaking surface changes; no published
users yet.
--head Nand--tail Nflags. Pipe mode already has
| head/| tail; TTY scrollback covers the TTY case;
source-vs-rendered semantics were never pinned.--save PATHand--tee PATHflags. Collapsed into
the new-o, --out PATH(writes to file AND stdout; extension
drives format;--jsonforces JSON regardless). File-only is
the Unix idiom-o foo.json > /dev/null.--resume IDflag. Unified into-c [ID](-cbare =
continue most recent;-c IDor-c=ID= resume specific).
--forknow requires an explicit id (-c ID --fork).ROBA_PROFILES_FILEenv var (point-at-an-extra-file).
Subsumed by the generalROBA_<PARAM>override layer + file
walk-up discovery.- BREAKING: bundled skill+agent library and the
roba skill {install,list,show}androba agent {install,list,show}subcommands. Bring your own skills
and agents via~/.claude/skills/and
~/.claude/agents/. See
joshrotenberg/agent-tools
for one curated set.
Fixed
- Fail fast when an interactive-only flag is set without a TTY
on stdin.-e/--editorand--pickpre-check
stdin.is_terminal()and exit 1 with a canonical message
instead of hanging on input that can't arrive.
Docs
docs/vs-claude-p.md: side-by-side comparison between
robaandclaude -p, with worked examples for common cases.docs/use-cases.md: cookbook-style use cases, seeded with
the multi-repo orchestration pattern (orchestration bus =
headlessrobacalls; cockpit = optional tmux for
observation).docs/examples/github-actions/pr-review.yml: example
workflow YAML for running roba as a PR auto-reviewer.docs/profiles.md: gh allow-list worked example under
## Worked examples.- Docs site: an mdbook
aggregating the README anddocs/into a navigable site, deployed
to GitHub Pages on push tomain
(joshrotenberg.github.io/roba).
The book source is generated bybook/build.sh; onlybook.toml
and the script are committed. - README slimmed: the repo
README.mdis now a tight landing
page serving both GitHub visitors and the book's Introduction. The
heaviest sections moved into dedicateddocs/pages:
docs/permissions.md,docs/scripting.md,docs/aliases.md. - Book structured into three audience-driven sections: "Getting
started", "Using roba", "Reference". New docs pages:
docs/quickstart.md(install-to-first-answer),
docs/reference.md(flags, env vars, exit codes, JSON envelope,
config schema). (refs #86)