* feat(loadouts): Opus 5.5 lite loadout with explicit model detection (GSTA-161)
modules/loadouts.json gains the lite loadout (eleven coaching preamble
pieces dropped; upgrade-check and brain-sync kept) and a models map that
sends only claude-opus-5-5 (and its dated snapshots) to it. Detection is
explicit: Capy passes --model to the installer, Claude Code opts in with
./setup --loadout lite; anything unmapped, invalid or unreadable serves full.
The checkout always stays the full render.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(loadouts): Opus 5.5 lite, detection order, Capy SKILL_ROOT, setup --loadout; troubleshooting anchors; changelog fragment (GSTA-161)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(loadouts): claude_loadout read through CONFIG_BIN; capy skill context ceiling for the --model line (GSTA-161)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (prune keeps a reused loadout folder, GSTACK_LOADOUT_SKILL_ROOT, claude_loadout guard test) (GSTA-161)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (Capy skill passes the model as GSTACK_MODEL so an older installer ignores it) (GSTA-161)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (prune only owned, unused folders; full root from the canonical Claude install; fallback reason and source) (GSTA-161)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: loadout source example, install and resolve commands, Capy launch-file note (GSTA-161)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(autoplan): --ceo-only runs the CEO review alone with zero questions (GST-537)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: classify autoplan-ceo-only in the Codex host metadata
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: select autoplan-ceo-only on the skills it runs; say it needs Claude Code
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: run autoplan-ceo-only in the marathon lane
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: changelog entry for /autoplan --ceo-only
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: count the autoplan-ceo-only paid file in the shard inventory
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat: gstack-autoplan next --ceo-only runs the CEO review alone and ends reviewed (GST-537)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: budget and close recover a budget-stopped CEO-only run; reviewed is at rest for checkpoints
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: CEO-only finish leaves owner-only cap items undecided, refuses marker phase flags and a plan at the report path, and replaces ceo-review.md atomically
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: the CEO-only report-path guard compares real paths and refuses at the finish when the report file is the plan
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: CEO_ONLY_CONFLICT covers a plan linked to the report path
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(browse): failing-first device and touch tests (GSTA-227 F3, #3058)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: the report-path guard keeps the lexical check, skips safe hard links and compares bigint file ids
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* browse: per-session tabs for parallel agents; tab pins stop moving the shared active tab (#1961)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* browse: keep the server.ts tab-pin anchor comment for source guards
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat(browse): per-tab phone emulation and touch input ($B device, tap, swipe, pinch, touch; #3058, GSTA-227 F3)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: copy lib/result-codes-autoplan.ts into the fixtures that copy the result-code tables, and keep it out of derived closures
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(qa, aside): touch pointer in /qa, Aside touch recipe verified on Aside 1.26, report Phones row (GSTA-227 F3, #3058)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* browse: drop the sessions paragraph from /browse to stay inside the parity cap
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* changelog: F3 phone emulation and touch entry
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* browse: hide the ps window in the session harness walk
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: the decisions.jsonl status list names auto_kept
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(browse): session cap, LRU eviction, headed release and scoped auto-session rows
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* browse: sessions keep tab <id> picks, sidebar claude stays on the user's tab, pinned rebuild and state load rebind the scope
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (touch cancel with no finger held is a no-op)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: Step 11 review fixes (headed tab adoption, pinned viewport reset, CLI retry keeps --session, rebuild id remap, --json notice, evicted-session reset, device kept after annotated captures, render opts out of sessions, session: client ids reserved)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: headed viewport auto keeps the user's active tab; render's closetab opts out of sessions
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: sessions, phone emulation and touch in BROWSER.md; session: client ids reserved; TODOS #1961/#3058 shipped
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test: copy lib/result-codes-browse.ts into the fixtures that copy the result-code modules
lib/result-codes.ts imports ./result-codes-browse, so fixtures with an explicit
lib list failed with 'Cannot find module'. pr-dependencies lists it with the other
reason-code modules as selection data. GSTA-227
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* feat: gstack-clean reclaims per-repo .gstack scratch and logs, dry run by default (#2627)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* browse: name the Aside touch recipe's coordinates <tap-x>/<tap-y> with a numeric grammar
The generated-bash lint (INV-3) rejected the free-text <x>/<y> placeholders. GSTA-227
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(clean): leave hard-linked and unreadable logs alone; cut through a no-follow descriptor checked against the evaluated inode
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(clean): tests that expect tmp removal see a quiet ps, so a codex elsewhere on the host cannot flake them
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(clean): an unlistable tmp/ skips its group; liveness asked once per group on apply; BROWSER.md says which logs reset at daemon start
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(clean): write output synchronously so --json reaches a pipe whole; test fixes for root, wrapper git and the ps stub
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(clean): every change rechecks the verified folder and the measured file; full writes; EPIPE ends output quietly
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(clean): the early-close test checks the bin's own exit status
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: list gstack-clean among the standalone CLIs
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(clean): copied-install fixtures and the dependency list carry lib/result-codes-clean.ts
The remote pregate failed 11 cases in gstack-doctor, plan-tune-cathedral and
timeline-stop-hook-slug: each copies an explicit list of lib/result-codes-*.ts
files into a temp install, and lib/result-codes.ts now imports
./result-codes-clean. Same lists GSTA-168 extended for result-codes-eval.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: regenerate gstack-doctor-components.sh for the gstack-clean result codes
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* qa: fold the touch pointer into the Phases sentence to fit the parity size cap after the main merge
qa's union was 95988 bytes (ratio 1.142 > maxSizeRatio 1.142, train 75). Now 95975 (1.1419). GSTA-227
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: #3058 troubleshooting 'Fixed in' lines name v1.92.10.0 after the main merge
GSTA-227
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(clean): classify gstack-tasks rows files (tasks-*) as kept, after main added the producer
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: #3058 troubleshooting 'Fixed in' lines name v1.92.20.0 after the main merge
GSTA-227
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (restore the lib/result-codes-plan.ts ratchet row the base merge dropped)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(clean): the producer scan ends a name at a colon, so prose after a path names the file (train 78)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: #3058 troubleshooting 'Fixed in' lines name v1.92.30.0 after the main merge
GSTA-227
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* outside-voice-api: caller receipts, stop_reason, OpenAI max_completion_tokens
A caller can write its own egress receipt (sink, consent, payload class);
the default stays the outside-voice receipt, so existing callers send and
record the same bytes. The result carries the provider's stop reason, and
an OpenAI request gets max_completion_tokens only when the caller sets an
output limit (GST-537 PR 3).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* autoplan gate: item classes and the owner's answer provenance
Gate items carry item_class, ruleKept() names the keep-direction pick, and
answered decision rows record owner_mode, owner_named, rec_hash and
answered_role parsed from the owner's own words (GST-537 PR 3).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* autoplan: shadow-mode decider module, frozen prompt and spend accounting
The switch (off by default, fixed at init), the lease, one model call per
gate with a page retry and a truncation retry under one deadline, the
once-per-revision record with its journaled sha256, the 10% audit mark,
and shadow-labeled ledger rows that count against the cap, show as
shadow= on GATE_SPEND and stay out of the per-voice price (GST-537 PR 3).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* gstack-autoplan: shadow every published gate, the shadow export, config and docs
Every driver command that prints a gate records the shadow first and
checkpoints after it; answer waits for a live lease and records a dead
one retrospectively; gstack-autoplan shadow exports answered revisions
for taste-replay R2 (SHADOW_BEFORE_ANSWER otherwise); gstack-config
autoplan_shadow / autoplan_shadow_model; gstack-artifact validate checks
the record's hash (GST-537 PR 3).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* changelog: shadow mode for the CEO-only decider (GST-537 PR 3)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* autoplan shadow: /ship review fixes
- register test/fixtures/shadow-fake-model.ts in FREE_FIXTURES (free-fixtures inventory failed)
- withRunLock: count dead-owner reclaims apart from waitMs iterations, so a long wait can still reclaim
- buildPage: fill the decider template in one pass, so slot names inside the plan stay plan text
- revise regate: the shared publish step prints the GATE and ESCALATE lines once
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* autoplan shadow: reply files never follow a link; the retry reserves against the current cap
- a model reply is written by temp file and rename, so a link at the reply path is replaced, not written through
- each shadow reservation reads the run's current spend cap, so a budget change during the call is not undone
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* outside-voice-api: write the egress receipt under the caller's env
callModel resolved the receipt's state root from process.env even when the caller passed env, so the shadow
tests wrote to the real ~/.gstack (the free-suite home-containment guard caught it). The receipt now uses
req.env; the shadow tests give the fake model a private HOME, GSTACK_HOME and GSTACK_STATE_ROOT, and the receipt
test no longer sets process.env to pass.
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(autoplan): CEO-only runs leave main's open Critical/High finding items to the owner (no decision row)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(autoplan): shadow pages carry main's finding items; a finding item is never ceo_eligible
After merging #3767 (main 90a170c), open Critical/High findings are gate items
(item_class finding). The shadow records one row per gate item, so its pages now
include them. A CEO-only run leaves those items to the owner, so their rows are
ceo_eligible false (rule_pick was already null). The shadow fixtures follow
main's gate (items, counts, "Do it" tokens); the two merge adapters follow
main's doNext(out, rest, price) and its per-voice reservation (--estimate-usd).
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs: #3058 troubleshooting 'Fixed in' lines name v1.92.61.0 after the main merge
GSTA-227
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(investigate): drop the five-phase step procedure (GST-938)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* changelog: GST-938 fragment wording
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix(investigate): keep the web-search sanitize guard; update BROWSER.md and docs/skills.md (review pass 1)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* changelog: GST-938 wording
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(investigate): pin the web-search guard; changelog size (adversarial review)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* test(clean): classify restamp-staging.json, the restamp producer main gained after #3779's base (wave browse)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: pre-landing review fixes (wave browse): scoped newtab keeps a concurrent tab switch; shadow validate catches a deleted record; a failed shadow publish is journaled
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: a failed shadow publish journals under the run lock and never throws (wave browse review pass 2)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* docs(unattended): shadow publish failures and the missing-record validate check (wave browse docs audit)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* changelog: wave browse integrator fixes fragment
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* fix: shadow reader dedupes by run folder, so two runs started in the same second both count (wave browse CI free-suite 16)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* chore: regenerate doctor result anchors in generator order (wave browse rebuild without #3818)
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
* changelog: name the wave fragment after the rebuilt wave
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
---------
Co-authored-by: capy-ai[bot] <230910855+capy-ai[bot]@users.noreply.github.com>
18 KiB
Standalone binaries
Beyond the slash-command skills, gstack ships standalone CLIs for workflows that don't belong inside a session:
| Command | What it does |
|---|---|
gstack-model-benchmark |
Cross-model benchmark — run the same prompt through Claude, GPT (via Codex CLI), and Gemini; compare latency, tokens, cost, and (optionally) LLM-judge quality score. Auth detected per provider, unavailable providers skip cleanly. Output as table, JSON, or markdown. --dry-run validates flags + auth without spending API calls. |
gstack-taste-update |
Design taste learning — writes approvals and rejections from /design-shotgun into a persistent per-project taste profile. Decays 5%/week. Feeds back into future variant generation so the system learns what you actually pick. |
gstack-factory-scorecard |
Factory scorecard — one window (default 7 days) of a repository's shipping numbers, read from GitHub through gh: merged PRs (crew vs outside), lead time (created → merged, first READY comment → merged), gate runs with their known cost, red-train rate, flaky events (paid reruns and free-suite retries), issues opened vs closed, releases cut. Markdown table plus CSV, every line with its counting rule and what one of the best factories would show; /retro Step 7.5 runs it. Read-only, no paid work. Guide. |
gstack-egress |
Egress receipt auditor — every gstack-initiated off-machine send writes a tamper-evident, hash-chained receipt to ~/.gstack/security/egress.jsonl before the send. list shows what gstack attempted to send and to which host, grants shows the standing consent settings plus the exact command that revokes each, verify recomputes the hash chain and exits 3 on tamper (catches edits, reordering, and mid-chain deletion; truncating or deleting the ledger itself is out of scope — it's a forensic log, not tamper-proof storage). |
gstack-context-bill |
Token bill-of-materials — read-only, offline audit of what an installed skills tree costs in tokens: always-on frontmatter every session pays vs per-invocation SKILL.md + forced references. --diff compares two trees, --budget enforces a ceiling, --exact opts into Anthropic count_tokens (sends the text of the billed .md files inside the tree, the linked gstack checkout or gstack's render folder off-machine, names and estimates anything else a symlink reaches, labels a part-estimated bill mixed; writes an egress receipt first, degrades to the offline estimate if the receipt can't be written). |
gstack-code-intelligence |
Code-intelligence provider picker — wraps GBrain, Sourcebot, and Graphify behind one interface: options/status to see what's available, select to pick one, index/search to use it, suggest to check whether the one-time indexing offer should fire here. The offer triggers on large repos (1,000+ tracked files; a decline is persisted). Non-local providers refuse to index or search until you record per-repo consent (consent <repo> yes|no — the query text is repo-derived content), the per-repo trust policy's deny and read-only tiers veto write-class operations regardless of consent, and every off-machine send writes an egress receipt. Fully optional — with nothing selected, gstack falls back to grep. |
gstack-verify-gate |
Verification stop hook (opt-in) — blocks a Claude Code turn from ending until the project's declared verify command passes (after 3 blocked re-entries it yields with a loud still-RED warning instead of looping forever). Declare it on one line in CLAUDE.md: <!-- gstack:verify: bun test -->. Hooks bypass the permission system, so a declared command never runs until you trust it once per repo (gstack-verify-gate --trust); editing the command invalidates trust until re-granted, and every grant is audit-logged. ./setup never registers it for you — opt in with gstack-settings-hook add-event --event Stop --command ~/.claude/skills/gstack/bin/gstack-verify-gate --source verify-gate, remove with gstack-settings-hook remove-source --source verify-gate. |
gstack-memorable |
Memorable recall bridge (opt-in, third party, Claude Code only) — connects Claude Code to the external Memorable CLI through gstack instead of the vendor's own installer, so the hook gets gstack's guarantees: an explicit consent key (memorable_recall, off by default, listed by gstack-egress grants), a fail-closed egress receipt for every prompt handed over (gstack-egress list --sink memorable-recall), a HIGH-tier secret pre-scan, a trust envelope and 8 KiB cap on whatever comes back, an allowlisted environment and process-group containment for the vendor process, and clean removal. enable registers the hook at the stable install with a 5 s timeout and never runs the vendor's own consent command; disable revokes the gate first and removes the entry by identity even after Claude Code strips the tag; status is read-only. gstack never installs Memorable, and what its binary sends is the vendor's claim, not gstack's. Not available on Windows yet. Full guide. |
gstack-decision-trail |
Decision trail — append one row (ts, phase, decision, why, evidence, result) to a run's TSV trail so a reviewer reads what was chosen and why without the transcript. Header once, append-only, cells flattened to one line, and a cell starting with =, +, - or @ quoted so a spreadsheet cannot run it. start <file> <run-id> opens a run's stretch of a shared trail (idempotent; start is reserved as a phase name), and --run <id> refuses an append until that start row is the newest. Ported from pstack's log.sh (MIT, NOTICE.md). Rule. |
gstack-worktree-audit |
Worktree audit — read-only table of every git worktree beside the main one, largest first: size, age, merged into the base or not, clean/clean,ignored:<n>/wip:<n>/scratch:<n>, pushed/ahead<n>/no-remote/detached, the PR on its branch through gh (fork PRs ignored), the newest Claude Code chat in it, and a bucket (prunable for an unlocked registered worktree whose directory is gone, review for a locked or broken one, hold-wip, hold-open-pr, verify-recent-chat, safe only for a clean tree that is merged into the base or whose PR is closed or merged with every commit pushed, else review). -b origin/<branch> sets the base, --no-fetch skips the best-effort fetch of the base ref (its one write). Never deletes. Ported from pstack's worktree-audit.sh (MIT, NOTICE.md). Guide. |
gstack-clean |
Per-repo .gstack/ cleanup — run inside a repository to see what it would reclaim from that repository's .gstack/ folder; --apply does it. It removes tmp/codex-* scratch files older than 7 days, cuts the browse logs (browse-console.log, browse-network.log, browse-dialog.log, browse-daemon.log, browse-startup-error.log) to their last 256 KB once they pass 1 MB, and trims browse-audit.jsonl only with --audit-days N. It never touches browse.json, session-state.json, chromium-profile/, browser-skills/ or browse-states/, skips browse files while the daemon runs and tmp/ while codex runs, and refuses (exit 3) outside git, when .gstack is a symlink, when BROWSE_STATE_FILE names another folder, and when the folder is, holds or sits inside the gstack state root. --json prints one versioned object. Exit 0 done, 1 an action failed (rerunning is safe), 2 usage, 3 refused. Error codes. |
gstack-wtree |
Working-tree fingerprint — prints a content hash of what's actually on disk (temp index seeded from the stat cache, ~40x cheaper than a full re-hash; untracked source counts, gitignored scratch doesn't). Identical content fingerprints identically through commits, rebases, amends, and squashes — it's what binds reviews and test evidence to content instead of commit SHAs. |
gstack-review-log |
Review-pass receipts — --start <skill> captures the working-tree fingerprint before a diff review; '<JSON>' --finish <token> consumes that single-use, repository/branch/skill-scoped receipt. Binding requires matching start/end content and reviewer-reported completed:true and converged:true; it is not independent proof that a model read the source. --check-shared-libs <token> reads a current finding as JSON on stdin and checks prior Skip decisions against the actual branch, capture and eligible raw source blobs. It returns reusable:false when proof is missing or unsafe, including older records without logger-versioned coverage. Final review logging computes shared-code fingerprints and coverage rather than trusting supplied proof. |
gstack-review-read |
Review freshness — emits review records with computed review_freshness.status and reason: CURRENT, STALE, or UNVERIFIED for diff reviews. /ship and /land-and-deploy use the same grade; a matching commit alone never certifies a diff review. Dashboard rules. |
gstack-evidence |
Verification-evidence ledger — run --label <lane> -- <cmd> transparently wraps any test command (the child's exit code always passes through) and records what ran against which working-tree fingerprint (tracked and untracked files that are not gitignored, minus an untracked .bun/ folder at the repo root, which Bun can create during a run); a run whose files changed while it ran is recorded without a fingerprint and with up to five of the changed paths, which check names in its STALE reason. check grades each label FRESH/STALE/MISSING with --expect-cmd, --max-age, and --allow-paths binding. /ship and /land-and-deploy cite fresh evidence instead of re-running suites. Per-run logs are 0600, capped at 2MB, pruned after 30 days; the ledger and logs stay machine-local by design. |
gstack-flaky |
Flaky-test rerun for any JUnit runner — run --junit <file.xml> -- <command> runs your test command (Playwright, bun test, jest, vitest, pytest) and, when at most --max-reruns (3) tests failed and the runner made no retries of its own, reruns the whole command once (--rerun-scope test opts in to rerunning only the failed tests). A test that fails and then passes on that rerun is a flaky pass: the run stays green and one redacted line per flaky pass or failed rerun goes on a ledger (GSTACK_FLAKE_LEDGER_JUNIT, default <state root>/flake-ledger-junit.jsonl). A missing or malformed report, a crash or a killed runner never passes. ids --junit <file> prints a report's test ids. Exit 0 pass, 1 a test failed, 2 usage, 3 no usable report. Guide. |
gstack-pr-wait |
PR event watcher — gstack-pr-wait <pr> [--repo owner/name] [--until green|ready|any-change] [--interval 20] [--timeout 60] [--exclude CHECK,...] polls one pull request through gh and prints one stdout line per real event (a check failed with its link, all checks finished, a comment or review from someone other than the author, a review bot finished on the head, the base moved and its new commits touch this PR's files, BEHIND or DIRTY, merged or closed), with progress on stderr, so a monitor wakes the agent once per event instead of on a timer. green gates on every check on the head (an advisory bot's review is never waited for, its checks gate like any other), as gstack-ci-gate does; a check the base branch requires (rulesets and classic branch protection) is pending until it appears, never green by omission; two identical polls confirm a check set is complete; --exclude leaves a named non-required check out of the verdict as gstack-ci-gate --exclude does (a required name is refused and gates). Exit 0 when the condition is met, 1 when it needs action or --timeout passes (PR_WAIT_BLOCKED), 2 on bad input, a second watcher for the same PR or a local error (PR_WAIT_REFUSED). State under <state root>/pr-wait/, baseline discarded after 6 hours. Review bots are configuration: gstack-config set pr_wait_gating_bots greptile,macroscope, pr_wait_advisory_bots coderabbit (advisory bots are reported, never waited on). /land-and-deploy Step 3 is one call of it. Design ported from tstack's pr-wait (MIT, Theo Browne; NOTICE.md). Exit codes. |
gstack-issue-guard |
Tracker-text trust envelope — fetches GitHub issue/PR text (issue <n>, pr-body, pr-comments, or --stdin) and wraps it in a labeled envelope so agents treat it as data: injection-shaped lines get labeled even through fullwidth and invisible-character evasion, and forged envelope banners are defused. Every tracker-text ingress in gstack routes through it, enforced by a CI scanner. |
gstack-ios-qa-daemon |
iOS QA daemon — Mac-side broker between an agent and a connected iPhone or iPad over USB CoreDevice. Loopback by default; --tailnet opens a Tailscale-facing listener with identity-gated capability tiers. Single-instance via flock on ~/.gstack/ios-qa-daemon.pid. See docs/howto-ios-testing-with-gstack.md. |
gstack-ios-qa-mint |
iOS allowlist manager — owner-grant CLI for the tailnet allowlist. grant/revoke/list against ~/.gstack/ios-qa-allowlist.json (mode 0600). Remote agents never auto-allowlist; this is the explicit-intent path. |
gstack-ios-qa-regen |
iOS bridge regenerator — deterministically installs the canonical DebugBridge package, generates typed state accessors, and records the installed gstack version. Safe to rerun after source changes or upgrades. |
The private paid CSO evaluation producer is a packaging contract, not an ordinary bun run build artifact. On macOS or Linux, a release operator compiles cso-eval-producer with the documented hardened Bun flags in the same clean build session as bun run build:cso, then installs it beside gstack-cso-launcher, gstack-cso-core, gstack-cso-watchdog, and the hidden .gstack-cso-generation manifest as one root-owned, nonwritable five-artifact unit. The producer rejects root execution, writable/symlinked/incomplete installations, and unreviewed provider CLI versions; each receipt binds all five artifact hashes, and collection rejects receipts from different unit identities. See the clean producer procedure. Paid producer evaluation remains unavailable on Windows because the detached watchdog has no Windows build.
Each producer gets a curated one-cell source copy with directories sealed to 0555 and files to 0444, plus pre/post content, Git, and mode checks. Claude receives no source add-directory, because an add-directory is a sandbox write root where Claude Code's bubblewrap leaves an empty .mcp.json mount point. Its Bash runs inside Claude Code's sandbox with one exception: the exact absolute launcher path that --allowed-tools names, which runs outside it as it does for users. The launcher is the boundary there. It replaces its environment with a fixed allowlist, uses only the local Docker Unix socket, and runs every target in hardened containers. The producer passes that policy through --settings (sandbox enabled, fail if unavailable, no unsandboxed fallback, no auto-allow, and excludedCommands naming only the launcher). It refuses to start the agent (CLAUDE_PRODUCER_SANDBOX_POLICY_MISMATCH) unless the generated arguments and environment carry exactly that policy. CLAUDE_CODE_SUBPROCESS_ENV_SCRUB stays unset, because it would force the launcher back into the sandbox. Every other Bash command is denied by --allowed-tools, and Write is confined to the provider work directory and cso-home. Gemini receives no source working directory or include-directory. Codex technically receives read-only filesystem access to the exact curated source root because the trusted helper inherits the Codex permission profile; its private provider work directory and exact cso-home artifact directory are the only write roots, every other root path remains denied, and the producer prompt requires source access through the helper. This is evaluation containment for an immutable public fixture, not a claim that Codex cannot directly read that fixture.
Copy each completed cell's receipt together with state/cso-home/security/cso/ to the trusted adjudication host. Receipt entries are sorted paths relative to that directory and bind every retained file's size and SHA-256 plus an aggregate inventory hash. Provider homes, settings, sessions, and credentials live under separate disposable directories and are removed after the cell; they are never part of the retained artifact tree. The adjudicator must re-hash the transported tree against the receipt before trusting reports or repair bundles.
Paid producer qualification uses this explicit host matrix:
| Producer host | Daily/static cells | Comprehensive target execution |
|---|---|---|
| Codex CLI 0.153.4 | Supported under the custom permission profile | Fails closed because Docker/socket access is not granted to the model command sandbox; report the setup gap as partial |
| Claude Code 2.1.263 | Supported under restricted safe mode | Fails closed when the restricted launcher child cannot reach Docker; report the setup gap as partial |
| Gemini CLI 0.59.0 | Supported with isolated home/settings | Private release qualification host: the exact run_shell_command(<launcher>) policy can run the trusted helper without exposing a general shell |
Every setup-blocked comprehensive cell remains a miss in release-gate denominators. The evaluator does not silently count a host or workflow as supported when its containment policy prevents required setup.