neuron-explorer
Qwen3.5‑4B 전용 조향형 뉴런 탐색기, 모든 MLP 뉴런을 밀어 결과를 보관·탐색
Dippin .dip 파일 기반 DAG 워크플로를 인간 게이트·LLM·청구 인식 일시정지·자동 체크포인트로 실행하는 파이프라인 엔진
Pipeline orchestration engine that runs DAG workflows from Dippin .dip files with human gates, LLM nodes, billing-aware pauses, and automatic checkpointing.
개발 도구Go · HTMLGitHub @2389-research온라인운영자 미확인
써 보셨어요? 한 번만 눌러 주세요. 로그인은 필요 없어요.
Pipeline engine for multi-agent LLM workflows, with Dippin pipelines, parallel agents, and a terminal dashboard.
저장소 README에서 가져옴
README 전체를 불러오는 중입니다. 아래는 저장된 발췌입니다.
Pipeline orchestration engine for multi-agent LLM workflows. Define pipelines in .dip files (Dippin, our pipeline DSL), execute them with parallel agents, and watch progress in a TUI dashboard.
Built by 2389.ai. Docs, walkthroughs & the TUI in action →
Install — Homebrew (macOS/Linux) or go install:
Three steps to your first run — no .dip file needed:README 전문 보기 ↗Pipeline orchestration engine for multi-agent LLM workflows. Define pipelines in .dip files (Dippin, our pipeline DSL), execute them with parallel agents, and watch progress in a TUI dashboard.
Built by 2389.ai. Docs, walkthroughs & the TUI in action →
Install — Homebrew (macOS/Linux) or go install:
brew install 2389-research/tap/tracker
# or: go install github.com/2389-research/tracker/cmd/tracker@latest
Your first run, on your Claude subscription — no API key, no .dip file. If you already use Claude Code (claude installed and signed in), cd into any repo:
tracker explain --param question="what does this repo do?"
backend: auto → claude-code (claude 2.x at /opt/homebrew/bin/claude; no API key needed)
… Start → Answer → WriteAnswer → Done, the answer streamed in the activity log …
answer saved to .tracker/runs/<id>/explain.md
next: make a small change with
tracker quickfix --param change="<one sentence>"
explain only reads (it can't change a file). Then make one small change:
tracker quickfix --param change="fix the typo in the README"
The change is made in a separate git worktree on its own branch, tracker/quickfix/<run-id>: Tracker never changes your checkout, and the review gate warns if anything outside the worktree changed while the agent worked. Tracker runs your tests and shows the diff: approve commits it to that branch (nothing is merged or pushed), revise tries again with your feedback, reject throws it away.
No Claude Code? Install it (npm i -g @anthropic-ai/claude-code && claude /login), or add an API key with tracker setup — the same two commands then run on the key. Leave off --param to be asked instead. If something doesn't work, tracker doctor checks your setup and tracker diagnose explains the last run.
From there:
tracker init build_product scaffolds build_product.dip + a starter SPEC.md; edit the spec, then tracker build_product.--autopilot mid to replace human gates with an LLM judge (or --auto-approve for deterministic approval).4; tracker answer <run-id> approve answers it and resumes the run (below).trackerbot) or your terminal as a REPL (trackerchat).tracker workflows (list built-ins), tracker validate <wf>, tracker simulate <wf>, tracker estimate <wf>, tracker setup, tracker --help.Release history has moved out of this README — see CHANGELOG.md for what's new in each version, and the Roadmap for what's next.
Six pipelines are embedded in the binary and available via tracker workflows. Start with the first two:
explainAnswer one question about the repo you're in, read-only: tracker explain --param question="what does this repo do?". Runs on your Claude subscription when claude is installed (backend: auto, no API key needed), otherwise on an API key, and saves the answer to .tracker/runs/<id>/explain.md.
quickfixMake one small change on its own branch: tracker quickfix --param change="<one sentence>". The change happens in a separate git worktree on tracker/quickfix/<run-id>, the project's tests run, and you approve (commit to that branch; nothing is merged or pushed), revise (up to 3 times) or reject (worktree and branch removed). Tracker never changes your checkout; the agent is told to stay in its worktree, and the review gate warns if anything outside it changed.
ask_and_executeCompetitive implementation: ask the user what to build, fan out to 3 agents (Claude/Codex/Gemini) in isolated git worktrees, cross-critique the implementations, select the best one, apply it, clean up the rest.
build_productSequential milestone builder: read a SPEC.md, decompose into milestones, implement each with verification loops (opus-powered fix agent with 50 turns), cross-review the complete result, verify full spec compliance. Context-specific escalation gates let you override flaky tests or skip milestones without aborting the build.
graph LR
ReadSpec --> Decompose --> ApprovePlan
ApprovePlan -->|approve| PickNext
PickNext -->|milestone N| Implement --> Test
Test -->|pass| Verify --> MarkDone --> PickNext
Test -->|fail| Fix --> Test
Test -->|escalate| EscalateMilestone
EscalateMilestone -->|mark done| MarkDone
EscalateMilestone -->|retry| Implement
PickNext -->|all done| CrossReview --> FinalBuild --> FinalSpec --> Cleanup --> Done
Environment bootstrap and the deny-by-default test gate. Right after Setup, EnsureEnv runs the first found of build-setup.sh / .build/setup.sh / scripts/build-setup.sh — a hook the seed repo or operator ships to pin toolchains and dependencies (a .venv, npm ci, go mod download) — before any agent runs; no hook is fine, a failing hook stops the run at AbortRun with the hook's log replayed (.tracker/env-bootstrap.log / .status), so milestones never build against a partial environment. TestMilestone is then green only when a real oracle ran — a suite that executed a positive number of tests, or a project Makefile ci/check/lint/test target. In milestone mode the Go and Rust suites are scoped to what the milestone changed since its start SHA in the worktree (uncommitted edits, untracked files and deletions included): go test runs the changed packages plus their reverse dependents, and cargo test -p <crate> runs the crates owning the changed .rs files (nearest ancestor Cargo.toml with a [package]; a change that resolves to no crate, or no changed .rs at all, tests the whole workspace) — so a milestone that authored no test of its own cannot green on a prior milestone's passing suite; FinalBuild always runs the whole tree. A tree with no runnable oracle (a milestone-1 scaffold, a suite that ran zero tests, a pytest run that collected nothing) is neither green nor red: it routes to VerifyMilestone as tests-not-yet-verifiable and the verifier decides whether the milestone legitimately needs no executable verification. Language-native lint (vet, golangci-lint, tsc, eslint, ruff, mypy, clippy) always runs but is advisory — findings are printed with an ADVISORY: line and never fail a milestone; only a project-declared Makefile target blocks. A bootstrap hook that must reach a private registry needs TRACKER_PASS_ENV=1 exported in the shell that runs tracker (a project .env cannot set it — see the env trust policy): tool subprocesses (the hook included) run with *_TOKEN / *_API_KEY / *_SECRET / *_PASSWORD environment variables, DOCKER_AUTH_CONFIG and any variable whose value is a URL carrying credentials (an authenticated or ) stripped, so an or against an authenticated index fails without it.
Contract tests. Each milestone in the plan names its **Contract tests** — the exact test names that prove its done-when (Go TestX / TestX/sub, Rust module::test_name, pytest path::test_name, a JS describe/it title), or none — <reason> for a genuinely test-free milestone. PickNextMilestone writes them to .ai/milestones/contract-tests; every verify.sh run rewrites .ai/build/executed-tests.txt with every test that actually executed (Go === RUN names including subtests, cargo's per-test lines, pytest's -rA summary, jest/vitest/mocha ✓/✕ titles when the reporter prints them); and TestMilestone reconciles the two after a green run — a declared test that never executed is an ordinary red (CONTRACT-TEST-MISSING) routed to FixMilestone, so a milestone that authored no test of its own can no longer go green on the prior suite. When the runner lists no names at all (jest's default reporter, vitest's per-file lines, pytest with its summary silenced, a Makefile-only oracle) the manifest says so (# names-unavailable) and an unprovable name is a WARNING … verifier decides rather than a red. VerifyMilestone cites the manifest line for each declared test (or corroborates an unprovable one from the test source) and fails an unjustified none.
build_product)Two empty marker files under .ai/build/ let the operator (never an agent) opt a repo out of a fail-closed check. Both survive Setup's per-plan state reset, ResetReviewBudget and Cleanup, so they persist across tracker -r resumes and EscalateVerification / EscalateReview → retry re-plans; remove the file to re-arm the check.
.ai/build/allow-dirty — dirty-tree preflight opt-out. Setup refuses to start when the repository (the whole tree, not just the workdir) has uncommitted changes or untracked files, because the checkpoint commit after every milestone stages every tracked change and untracked file (only detected compiled binaries and secret-looking files such as .env / private keys are left out), so stray WIP would be swept into the build's history and reviewed as milestone output. Safe when the tree is deliberately dirty — for instance a monorepo with unrelated in-flight work you accept being checkpointed, or a scratch repo. Create it before the run: mkdir -p .ai/build && touch .ai/build/allow-dirty..ai/build/no-tests-ok — ship-gate opt-out for a product with no test stack. Without it, FinalBuild (verify.sh --final) fails when no build system is detected anywhere in the tree (no go.work / go.mod / package.json / pyproject.toml / Cargo.toml and no Makefile ci / check / lint / test target) and routes to EscalateVerification (unattended default abandon: the run ends fail at AbortRun) — a product with no test runner cannot ship green. With it, the ship gate passes with a NOTE that nothing was tested. Without it, milestone-mode TestMilestone reports such a tree as tests-not-yet-verifiable (an early scaffolding/docs milestone legitimately has no runner; VerifyMilestone confirms the milestone's done-when needs no tests); with it, the milestone gate passes with the same NOTE. The operator must create it before the run: PickNextMilestone snapshots the hatch files at the start of every milestone, and a stamp that appears mid-milestone is reported by TestMilestone / FinalBuild as agent-created (+ .ai/build/no-tests-ok) and treated as a finding. Agents are instructed never to create either stamp.build_product_with_superspecParallel stream execution for large structured specs: reads the spec's work streams and dependency graph, executes independent streams in parallel (with git worktree isolation), enforces quality gates between phases, cross-reviews with 3 specialized reviewers (architect/QA/product), and audits traceability.
build_product vs build_product_with_superspecStart with build_product — it is the default for a normal SPEC.md. It builds one milestone at a time in a single working tree, which keeps the run easy to follow and cheaper to escalate. Reach for build_product_with_superspec only when the spec is large enough to name independent work streams and a dependency graph the engine can parallelize; on a small or single-track spec its extra machinery is overhead with no payoff.
Both run the same SpecLint spec-coherence preflight before any decomposition (dangling refs, contradictory constants, contract/signature mismatch, unassignable mandated tests — fail-closed). Everything below is superspec-only:
CommitScaffold commits SPEC.md, docs/execution-plan.md, docs/traceability.yaml and .gitignore by name, so every stream worktree (forked from HEAD) sees them.build/<stream> branch, instead of a sequential milestone loop. A previous run's unmerged build/<stream> branch is renamed build/<stream>-abandoned-<sha>, never deleted.docs/traceability.yaml; it writes docs/traceability.<stream>.yaml (only the requirement IDs it covers, in the master's flat one-line-per-requirement format) and each phase merge folds the overlays into the master — no add/add conflicts on one shared file.verify.sh green-gate as build_product (every stack anywhere in the tree, Makefile target and language-native lint/vet), plus coverage and complexity as report-only evidence — between stream phases; mechanical, not LLM-judged. Because these gates are mechanical (there is no per-milestone verifier to hand the question to), verify.sh's NOT-YET-VERIFIABLE verdict (exit 3: no suite executed any test and no Makefile CI target ran) is a gate failure here — a greenfield phase that ships zero tests hard-fails at gate_verify until the phase adds a runnable suite, or the operator stamps .ai/build/no-tests-ok for a genuinely test-free project.MergeConflict gate: a phase merge that conflicts is aborted with the conflicting paths listed, worktrees and branches untouched; the gate's unattended default is abandon (the run ends failed), and retry re-enters the same phase's merge after you resolve it by hand.FinalGates + TraceabilityAudit: FinalGates fails any requirement still pending or without an impl_ref, and any implemented requirement without a test_ref unless waived in docs/traceability-waivers.txt (<ID> <reason>, one per line); the TraceabilityAudit goal gate then verifies every spec requirement maps to real implementation and test coverage and challenges each waiver.The two workflows are separate embedded files, not a base-plus-overlay; the shared SpecLint node is deliberately duplicated as a node declaration (built-in delivery cannot resolve subgraph file refs), but both declarations load the same prompts/build_product/SpecLint.md sidecar, and a parity test pins them byte-identical (issue #307).
deep_reviewInterview-driven codebase review: describe what you want reviewed, answer structured interview questions to scope the analysis, then three parallel agents analyze correctness, security, and design. A second interview presents findings for your context (is this intentional? known issue?), a third prioritizes remediation, and the pipeline produces an actionable remediation plan.
graph LR
DescribeGoal --> Explore --> ScopeInterview
ScopeInterview --> AnalyzeParallel
AnalyzeParallel --> Correctness & Security & Design
Correctness & Security & Design --> Join
Join --> Synthesize --> FindingsInterview
FindingsInterview --> PriorityInterview
PriorityInterview --> RemediationPlan --> ReviewPlan
ReviewPlan -->|approve| Finalize --> Done
ReviewPlan -->|revise| RemediationPlan
Pipelines are embedded in the binary so brew and go install users can run them without cloning the repo:
tracker workflows # List all built-in workflows (starters first)
tracker explain # Run directly by name — no files needed
tracker validate build_product # Validate works too
tracker simulate build_product # Simulate too
tracker init build_product # Copy .dip + scaffold a starter SPEC.md for editing
build_product builds from a SPEC.md in the repo root; running it without one
exits with a pointer to tracker init build_product, which scaffolds both the
.dip and a starter SPEC.md so the first run succeeds.
Local .dip files always take precedence over built-ins. After tracker init build_product, running tracker build_product uses your local copy.
Pipelines are defined in .dip files using the Dippin language:
workflow MyPipeline
goal: "Build something great"
start: Begin
exit: Done
defaults
model: claude-sonnet-5
provider: anthropic
agent Begin
label: Start
human AskUser
label: "What should we build?"
mode: freeform
agent Implement
label: "Build It"
prompt: |
The user wants: ${ctx.human_response}
Implement it following the project's conventions.
agent Done
label: Done
edges
Begin -> AskUser
AskUser -> Implement
Implement -> Done
requires: (v0.29.0)Workflows can declare what they need from the host environment with a requires: line in the header:
workflow BuildProduct
goal: "..."
requires: git
start: Start
exit: Done
Tracker checks these at startup (when you invoke tracker <workflow>). If the env doesn't satisfy them, the run fails in seconds with a copy-paste remediation instead of burning LLM spend before the first failure. Override per-run with --git=auto|off|warn|require|init (default auto respects requires:; --git=init --allow-init auto-initializes the workdir, with safety refusals for $HOME, /, and nested repos — including bare repos, linked worktrees, and submodules). v0.29.0 implements git; unrecognized entries warn and continue so workflow authors can forward-declare deps that future tracker versions will check.
| Type | Shape | Description |
|---|---|---|
agent | box | LLM agent session (codergen) |
human | hexagon | Human-in-the-loop gate (choice, freeform, or hybrid) |
tool | parallelogram | Shell command execution |
parallel | component | Fan-out to concurrent branches |
fan_in | tripleoctagon | Join parallel branches |
subgraph | tab | Execute a referenced sub-pipeline |
manager_loop | house | Managed iteration loop |
conditional | diamond | Condition-based routing |
Three namespaces for ${...} syntax in prompts:
${ctx.outcome} — runtime pipeline context (outcome, last_response, human_response, tool_stdout)${params.model} — workflow-level vars (optionally overridden by --param key=value at run time, v0.19.0) and subgraph parameters passed from a parent pipeline${graph.goal} — workflow-level attributesDeclare defaults in a top-level vars block and override them per-run:
workflow MyPipeline
vars
model: claude-sonnet-5
retries: 3
tracker --param model=claude-opus-5 --param retries=1 MyPipeline
Unknown --param keys hard-fail at startup. Dippin-lang's lint (run automatically at .dip load) flags undeclared ${params.*} references and other variable-reference mistakes — see dippin doctor for the full lint catalog.
Variables are expanded in a single pass — resolved values are never re-scanned, preventing recursive expansion.
Important: Each agent node runs a fresh LLM session. Data flows between nodes via context keys, not conversation history. Per-node scoping (${ctx.node.<nodeID>.<key>}) lets you reference a specific earlier node's output without relying on the last-writer-wins last_response key. See Pipeline Context Flow for the full model, fidelity levels, and parallel-branch patterns.
edges
Check -> Pass when ctx.outcome = success
Check -> Fail when ctx.outcome = fail
Check -> Retry when ctx.outcome = retry
Gate -> Next when ctx.tool_stdout contains all-done
Gate -> Loop when ctx.tool_stdout not contains all-done
Supported operators: =, !=, contains, not contains, startswith, not startswith, endswith, not endswith, in, not in, &&, ||, not.
ctx.tool_stdout and ctx.tool_stderr capture the tail of a tool node's output (default cap 64KB per stream, configurable per-node via output_limit: 256KB; --max-output-limit is a hard global ceiling, default 10MB, that caps how high a per-node output_limit can go). Routing markers emitted at end-of-output via printf survive truncation by construction; tracker diagnose surfaces a tool_output_truncated suggestion when a stream was clipped so you know to raise the limit if the captured tail isn't what you expected.
Conditions support the ctx. namespace prefix (dippin convention) and internal.* references for engine-managed state.
writes: / reads:Agent, tool, and mode: interview human nodes can declare the context keys they produce and consume (v0.21.0):
agent Planner
response_format: json_object
writes:
- milestone_id
- files
reads:
- spec_path
The node output must be a valid top-level JSON object; every declared key in writes: must be present or the node hard-fails. Extras are allowed (surfaced as warnings), strings are stored verbatim, non-string values are stored as compact JSON. reads: pins fidelity for upstream keys so downstream nodes see consistent data. See Pipeline Context Flow for the full contract, worked examples, and interview-mode semantics.
For git worktree isolation in parallel implementations:
agent ImplementClaude
working_dir: .ai/worktrees/claude
model: claude-sonnet-5
prompt: Implement the spec in this isolated worktree.
The working_dir attribute is validated against path traversal and shell metacharacters. A relative working_dir resolves under the run's workdir (-w), like tool nodes, not the tracker process's current directory.
Five gate modes:
mode: freeform): captures text input. If the response matches an edge label (case-insensitive), it routes to that edge. Otherwise it's stored as ctx.human_response.mode: yes_no): fixed two-option prompt. Yes maps to OutcomeSuccess, No maps to OutcomeFail — route with when ctx.outcome = success / when ctx.outcome = fail edges. Distinct from choice mode, where the outcome is always success and routing uses preferred_label.mode: interview): structured multi-field form driven by upstream agent output. An agent generates markdown questions with inline options; the handler parses them into individual form fields and presents a fullscreen interview form. Answers are stored as JSON and markdown summary.Long prompts with labels (e.g., escalation gates with agent output) automatically use a fullscreen review hybrid view: glamour-rendered scrollable viewport on top (PgUp/PgDn to scroll), radio label selection in the middle, and an "other" freeform option at the bottom for custom retry instructions. Long prompts without labels use a split-pane review: scrollable viewport on top, textarea on bottom.
human ApproveSpec
label: "Review the spec. Approve, refine, or reject."
mode: freeform
edges
ApproveSpec -> Build label: "approve"
ApproveSpec -> Revise label: "refine" restart: true
ApproveSpec -> Done label: "reject"
Interview gates let an agent generate structured questions that the user answers via a form:
human ScopeInterview
label: "Help us focus the review."
mode: interview
questions_key: interview_questions
answers_key: scope_answers
The upstream agent writes markdown questions to the questions_key context variable. The parser extracts:
? or imperative prompts ("Describe...", "List...")Auth model? (API key, OAuth, JWT) becomes a select fieldThe TUI presents a fullscreen form with per-field navigation (arrow keys), pagination (PgUp/PgDn for 10+ questions), elaboration textareas (Tab), and pre-fill from previous answers on retry. Answers are stored as JSON at answers_key and as a markdown summary at human_response. If zero questions are parsed, the gate falls back to freeform. Cancellation returns outcome=fail.
A reusable interview loop pattern is available in examples/subgraphs/interview-loop.dip — embed it via subgraph nodes with topic and focus parameters.
Submit with Ctrl+S. Enter inserts newlines. Esc cancels (empty) or submits (with content). Ctrl+C cancels and unblocks the pipeline (no deadlock).
Tracker supports four LLM providers: anthropic, openai, gemini, and openai-compat (for any OpenAI-compatible API). Set up with:
# Interactive setup wizard
tracker setup
# Verify your configuration
tracker doctor
Keys are stored in ~/.config/tracker/.env (under $XDG_CONFIG_HOME when that is an absolute path). You can also export them directly:
export ANTHROPIC_API_KEY=sk-ant-...
export OPENAI_API_KEY=sk-...
export GEMINI_API_KEY=...
A .env in the working directory may set provider *_API_KEYs only. Base URLs, the gateway and the other knobs belong in the shell or ~/.config/tracker/.env, and security switches such as TRACKER_PASS_ENV in the shell only. --env-files=all|config|none chooses which files load. See the env trust policy.
Important: Use gemini (not google) as the provider name in .dip files.
Non-retryable provider errors (quota exceeded, auth failure, model not found) immediately fail the pipeline with a clear message instead of silently retrying.
tracker setup can bill provider: openai nodes to your ChatGPT subscription instead of an API key. Check OpenAI, press tab until the cursor reaches its Auth row (the page opens on the API Key field), pick ChatGPT subscription with space, and press enter. Setup shows a link (https://auth.openai.com/codex/device) and a one-time code: open the link on any device, such as your phone, and enter the code within 15 minutes. Setup then saves the sign-in to ~/.config/tracker/chatgpt-auth.json (mode 0600; under $XDG_CONFIG_HOME when that is an absolute path) and writes TRACKER_OPENAI_AUTH=chatgpt to ~/.config/tracker/.env, which sends openai calls through that sign-in.
In this mode tracker drops a request's max output tokens, temperature, top_p and stop sequences before sending it, because the Codex backend's request has none of them, so those settings do nothing for openai nodes.
Usage bills to the plan, so tracker counts it at $0: --max-cost and every other dollar ceiling never see these calls, and a run that has both a dollar ceiling and an openai node prints a warning at start. --max-tokens still applies. When the plan's usage limit runs out, the run stops in the resumable paused_billing state; tracker -r resumes it once the limit resets. Autopilot's openai default model isn't served on a ChatGPT plan, so when autopilot lands on openai, pass --autopilot-model with a model your plan serves.
To go back to an API key, run setup again and pick API key on the Auth row; setup then writes TRACKER_OPENAI_AUTH=api-key. Unchecking OpenAI on the first page leaves the setting as it was. Deleting the token file signs you out.
The sign-in goes through Codex's OAuth client. Use it for your own ChatGPT account on your own machine, never for a bot or a hosted runner that other people use.
Tracker can route every provider through Cloudflare AI Gateway so you stop hitting rate limits (Anthropic, OpenAI, etc. cap per-account request rates; Cloudflare's gateway capacity is much higher), gain central analytics and caching, and enable model routing on the gateway side.
Set one env var or flag instead of four:
# The root URL of your Cloudflare AI Gateway:
# https://gateway.ai.cloudflare.com/v1/<account_id>/<gateway_slug>
export TRACKER_GATEWAY_URL="https://gateway.ai.cloudflare.com/v1/acc/gw"
# API keys still go to the provider — Cloudflare just proxies.
export ANTHROPIC_API_KEY=sk-ant-...
export OPENAI_API_KEY=sk-...
export GEMINI_API_KEY=...
tracker build_product
Or as a CLI flag:
tracker --gateway-url https://gateway.ai.cloudflare.com/v1/acc/gw build_product
Tracker automatically appends the per-provider suffix:
| Provider | Resolved URL |
|---|---|
anthropic | <gateway>/anthropic |
openai | <gateway>/openai |
gemini | <gateway>/google-ai-studio |
openai-compat | <gateway>/compat |
Per-provider overrides still win. If you set ANTHROPIC_BASE_URL directly, Anthropic traffic goes there, and the gateway only proxies the providers you haven't explicitly overridden. This means you can point Anthropic at a self-hosted proxy while keeping OpenAI on Cloudflare with one command.
The claude-code backend doesn't use the gateway. These base URLs and the gateway route the native backend only. --backend claude-code launches claude without the five provider *_BASE_URLs (#677), and claude never reads TRACKER_GATEWAY_URL; to send claude through a gateway on purpose, export ANTHROPIC_BASE_URL and set TRACKER_PASS_API_KEYS=1, which keeps keys and base URLs together.
Troubleshooting:
429 from Cloudflare: something bigger is wrong (account-level limits, bad gateway slug). 429s from direct provider calls are what the gateway is meant to prevent.401: check your provider API key, not the gateway — Cloudflare passes auth through.Tracker is a three-layer stack: an LLM client (provider adapters and token tracking), an agent session (turn loop, tool execution, context compaction), and a pipeline engine (graph execution, edge routing, checkpoints, decision audit, TUI). The dippin adapter converts parsed .dip IR into tracker's Graph model, and handlers implement per-node behavior.
graph TB
subgraph "Layer 3: Pipeline Engine"
Engine["Graph Execution<br/>Edge Routing<br/>Checkpoints<br/>Decision Audit"]
Handlers["Handlers: start, exit, codergen, tool,<br/>wait.human, parallel, parallel.fan_in,<br/>conditional, subgraph, stack.manager_loop"]
Adapter["Dippin Adapter<br/>IR → Graph"]
TUI["TUI: node list,<br/>activity log, modals"]
end
subgraph "Layer 2: Agent Session"
Session["Tool Execution<br/>Context Compaction<br/>Event Streaming"]
end
subgraph "Layer 1: LLM Client"
Anthropic & OpenAI & Gemini
end
Engine --> Handlers
Engine --> Adapter
Engine --> TUI
Handlers --> Session
Session --> Anthropic & OpenAI & Gemini
The core engine is UI-agnostic: the TUI, the Slack bot (trackerbot),
the terminal REPL (trackerchat), and any future
web/mobile front-end are peers on one library boundary — tracker.Config →
Engine, an Interviewer seam for human gates, the pipeline/agent event
streams, and RunManager for many concurrent runs. The Slack bot and the REPL
share one transport-neutral core (transport/chatops); each adds only its own
I/O. See docs/architecture/transport-boundary.md.
Declared inputs. A workflow can declare a typed input signature (a dippin
inputs block, requires dippin ≥ v0.51); a front-end introspects it with
tracker.DescribeInputs, validates a request with tracker.ValidateInputs
(structured per-input errors), and passes values via Config.Inputs. They are
validated + bound at run start — a missing required input fails closed before
any node runs, instead of the agent proceeding with nothing. File inputs are
staged into the run dir so a workflow reads them at a fixed, safe path
(build_product takes its spec this way). Secret inputs (SecretInput)
are staged the same way — the value goes to a 0600 file and ${inputs.<name>}
resolves to the path only, so a secret never enters a prompt, the provider wire,
the trace, or the checkpoint. See
docs/architecture/embedding.md §1a.
For subsystem-level architecture docs, see ARCHITECTURE.md and docs/architecture/.
The terminal UI shows:
FAILED:/RETRYING: messages when nodes fail or retry| Icon | Meaning |
|---|---|
| ○ | Pending — not yet reached |
| 🟡 (spinner) | Running — LLM thinking |
| ⚡ | Running — tool executing |
| ● (green) | Completed successfully |
| ✗ (red) | Failed |
| ↻ (amber) | Retrying |
| ⊘ (dim) | Skipped — pipeline took a different path |
tracker.Result.Status is one of:
| Value | Meaning | IsSuccess() |
|---|---|---|
success | Run reached the success exit; all validations passed. | true |
validation_overridden | Run reached the success exit, but a human, autopilot, or webhook accepted a failed validation along the way. See Result.ValidationOverrides. | true |
budget_exceeded | A BudgetGuard halted the run. | false |
paused_billing | Billing/quota exhaustion halted the run in a recoverable, resumable terminal (checkpoint + preserved WIP + tracker -r resume). Surfaced to embedders as RunManager.RunPaused. | false |
fail | Run halted via failure. | false |
The enum is open — future minor releases may add new values. Use IsSuccess() (or status_class in JSON output) instead of switching on the raw string.
| Key | Action |
|---|---|
| v | Cycle log verbosity (all / tools / errors / reasoning) |
| z | Toggle zen mode (full-width log, sidebar hidden) |
| / | Search the activity log (n/N next/prev, Esc exits) |
| ? | Help overlay with all shortcuts |
| Enter | Drill down into the selected node (Esc exits) |
| y | Copy the visible log to the clipboard |
| Ctrl+O | Toggle expand/collapse tool output |
| Ctrl+S | Submit human gate input |
| Esc | Cancel (empty) or submit (with content) |
| PgUp/PgDn | Scroll review viewport (plan approval) |
| q | Quit |
cmd/trackerbot is a Slack front-end built on the
transport boundary. Mention it and
it starts a pipeline in a thread, streams notifications and clarifying gate
questions there, and delivers the result — arbitrarily many runs at once, one
per thread:
@trackerbot make me a CLI that greets people
@trackerbot run build_product
@trackerbot status @trackerbot cancel @trackerbot runs
Natural-language requests are routed to a workflow by an LLM; all four gate
modes (choice / yes-no / freeform / interview) work in-thread; interrupted runs
resume after a restart. It connects via Socket Mode (no public endpoint). Setup
and configuration: cmd/trackerbot/README.md.
cmd/trackerchat is the same experience as a REPL:
type a request, answer gates inline, watch the run — no Slack required. It's the
second consumer of the transport boundary, built from the same
transport/chatops core, so it inherits every command, gate mode, cost estimate,
and steer/bump control the Slack bot has:
$ trackerchat
> run ask_and_execute
❓ Which approach should I take?
1) Minimal [default]
2) Full-featured
> 1
✅ done — success · $0.42 · 1m03s
Run tracker inside a Herdr terminal pane and it reports its
run state to the pane's agent manager automatically — no flags, no config. The
pane shows working while the pipeline runs, blocked while a human gate waits
for your answer, and idle when the run finishes.
Detection is by the environment Herdr injects (HERDR_ENV, HERDR_PANE_ID,
HERDR_BIN_PATH); outside a Herdr pane it is a complete no-op. Set
TRACKER_HERDR=0 to opt out even inside one. Reporting is best-effort — a slow
or failed Herdr call never affects your run — and blocked is reported only for
interactive runs (autopilot, --auto-approve, and --webhook-url resolve gates
with nobody waiting).
Every run produces an activity.jsonl log. Live writes go to the integrity-protected path under $XDG_STATE_HOME/tracker/runs/<id>/activity.jsonl (mode 0o600, default $HOME/.local/state/tracker/runs/<id>/, override via TRACKER_AUDIT_DIR; #213). At run-end a sentinel-stripped snapshot is mirrored back to .tracker/runs/<id>/activity.jsonl for bundle export and post-run grep/jq workflows. Captured content:
Run capture (v0.50.0). Beyond the event stream, a finished run is reconstructable: the executed spec (workflow.dip + workflow.ir.json + input files), the verbatim provider request bodies, and per-call/turn/session identity land on every activity.jsonl line and roll up into a run.json manifest (goal, terminal status, per-node kind/attempts/outcome/turns/usage, run totals). tracker run-json [runID] assembles the manifest after the fact, so a SIGKILLed or archived run gets one too. Library callers wire the same capture with Config.Capture (v0.51.0). Capture files are written 0600 with O_NOFOLLOW, and .tracker/ is excluded from exported bundles.
Reconstruct any routing decision after the fact (post-run snapshot path):
# See all edge decisions
grep 'decision_edge' .tracker/runs/<id>/activity.jsonl | python3 -m json.tool
# See condition evaluations
grep 'decision_condition' .tracker/runs/<id>/activity.jsonl | python3 -m json.tool
# See node outcomes with token counts
grep 'decision_outcome' .tracker/runs/<id>/activity.jsonl | python3 -m json.tool
Enable git artifacts from the library via the WithGitArtifacts(true) option on the engine builder; the artifact run directory becomes a git repository and each terminal node outcome creates a commit. (There is no CLI flag for this today — use the ExportBundle helper or the --export-bundle CLI flag to produce a portable bundle from any run directory.)
node(start): start outcome=success
node(middle): codergen outcome=success
node(end): exit outcome=success
Checkpoint tags (checkpoint/<runID>/<nodeID>) mark each save point.
ExportBundle packages the entire git history — commits and tags — into a single file you can copy anywhere:
// Library usage
result, _ := engine.Run(ctx)
if err := tracker.ExportBundle(result.ArtifactRunDir, "/tmp/run.bundle"); err != nil {
log.Printf("bundle export failed: %v", err)
}
# CLI usage: export bundle after the pipeline completes
tracker --export-bundle /tmp/run.bundle examples/ask_and_execute.dip
# Restore and inspect on any machine with git
git clone /tmp/run.bundle /tmp/run
cd /tmp/run && git log --oneline
The bundle is self-contained — no network access needed. Clone it on another machine, inspect the exact sequence of node outcomes, and replay from any checkpoint tag.
When a pipeline run doesn't go as expected, tracker gives you tools to understand what happened:
tracker diagnoseAnalyzes a run's failures and surfaces the information you need — tool stdout/stderr, error messages, timing anomalies — without manually grepping through JSONL files.
# Diagnose the most recent run
tracker diagnose
# Diagnose a specific run (prefix matching works)
tracker diagnose 7813b
The output shows each failed node with its output, stderr, errors, and actionable suggestions. For example, it will tell you if a tool node failed because of a stale counter file, or if a node completed suspiciously fast (suggesting a configuration issue).
tracker auditFor a broader view of a run's timeline, retries, and recommendations:
# List all runs
tracker list
# Full audit report for a specific run
tracker audit <run-id>
| Symptom | Cause | Fix |
|---|---|---|
| "no LLM providers configured" | Missing API keys | tracker setup or export env vars — or install Claude Code (npm i -g @anthropic-ai/claude-code && claude /login): backend: auto / claude-code workflows, the starters included, need no key |
claude-code nodes fail with unrecognized_model or an old-CLI error | A stale claude earlier on PATH | tracker doctor lists every claude on PATH with its version; export TRACKER_CLAUDE_BIN=/absolute/path/to/claude (shell only — a .env can't set it) |
| TestMilestone instantly escalates | Stale fix_attempts counter | rm .ai/milestones/fix_attempts |
| Node fails with no visible error | Tool stderr not surfaced | tracker diagnose shows full output |
| Pipeline loops forever | Unconditional fallback to loop target | Ensure fallbacks go to an exit node (Done, escalation gate), not back into the loop |
| Tool retries same error 5 times | Deterministic command bug | tracker diagnose flags identical retries — fix the command in the .dip file |
| Every milestone needs fixing | known_failures has comments or bad format | Ensure bare test names only, no comments — v0.11.2 strips them automatically |
| Build loop skips all milestones | Milestone headers don't match expected format | Use ## Milestone N: Title format — v0.11.2 is flexible + fails loudly |
Tool command or setup hook can't authenticate (pip install / npm ci / docker pull 401) | Tool nodes, the native agent's bash tool and verify commands get *_API_KEY / *_SECRET / *_TOKEN / *_PASSWORD, DOCKER_AUTH_CONFIG and any value carrying a credential (a URL with a password, an http(s) URL with userinfo, a Docker auths JSON blob) stripped | Export TRACKER_PASS_ENV=1 in the shell that runs tracker (a project .env can't set it) |
| claude-code node fails with "Claude Code refused N tool call(s)" |
Tracker exposes per-provider token and dollar cost from every run, and can halt pipelines that exceed configured ceilings.
Claude Code reports a notional cost on a subscription, so a run whose only
provider is claude-code shows it as ~$X.XX usage (included in your Claude plan); it still counts against --max-cost like any other cost.
Library consumers read cost via Result.Cost:
result, _ := tracker.Run(ctx, source, tracker.Config{
Budget: pipeline.BudgetLimits{
MaxTotalTokens: 100_000,
MaxCostCents: 500, // $5.00
MaxWallTime: 30 * time.Minute,
},
})
// IsSuccess() returns true for {success, validation_overridden}; classify by
// status_class for stable bucketing across future enum extensions.
if !result.Status.IsSuccess() {
log.Printf("run did not complete cleanly: status=%s, spent $%.4f",
result.Status, result.Cost.TotalUSD)
}
// To branch on overrides specifically:
if len(result.ValidationOverrides) > 0 {
log.Printf("run involved %d override(s)", len(result.ValidationOverrides))
}
for provider, pc := range result.Cost.ByProvider {
log.Printf("%s: %d tokens, $%.4f", provider, pc.Usage.InputTokens+pc.Usage.OutputTokens, pc.USD)
}
CLI users pass flags directly to tracker:
tracker --max-tokens 100000 --max-cost 500 --max-wall-time 30m \
examples/ask_and_execute.dip
A halted run prints a HALTED: budget exceeded section naming the dimension
that tripped. Run tracker diagnose to see the per-provider breakdown and
remediation guidance.
Streaming consumers subscribe to EventCostUpdated via
tracker.Config.EventHandler. Each terminal-node outcome emits a
CostSnapshot with aggregate tokens, dollar cost, per-provider totals,
and wall-clock elapsed time.
Budget ceilings can also be declared inline in the workflow's defaults: block (v0.19.0) and act as the fallback when neither Config.Budget nor the matching --max-* CLI flags are set:
workflow MyPipeline
defaults
model: claude-sonnet-5
max_total_tokens: 100000
max_cost_cents: 500
max_wall_time: 30m
Explicit library/CLI values still win over the .dip defaults.
Prices come from dippin-lang's
pricing catalog at the version pinned in go.mod (v0.83.0), so a new or
repriced model is adopted by bumping that pin; the full table is on the
models page. A model the
catalog doesn't price costs $0 with one warning. The catalog holds one price
per model, so prompts above a provider's long-context threshold (Haiku 5.5 above
100K tokens, GPT-6 above 272K) bill higher than Tracker estimates; leave
headroom in --max-cost for long-context runs (dippin-lang#329).
When nobody is at a terminal — Claude Code or another agent running tracker
through its shell, CI, a script — a human gate can't be answered on stdin.
Instead the run pauses: it stops at the gate in the resumable
paused_gate status, exits 4, and prints the gate (its question, options
and full prompt) and the command that answers it. The same happens with
--json, and with --gates pause at a terminal.
$ tracker quickfix --param change="fix the README typo" < /dev/null
…
⏸ Paused at gate ReviewDiff — Review the change — approve, revise, or reject
options: reject (default) · revise · approve · or free text
…
answer with:
tracker answer 5d82a6d50f15 reject # or: revise / approve / --text "free text"
$ tracker answer 5d82a6d50f15 approve
tracker answer lists runs that are waiting; tracker answer <run-id> shows the gate.--text "…" (or text after --) for free text, --default for the gate's declared default, or --answers-file / --cancel for interview gates. When parallel branches wait at several gates, answer them all in one call with --answer <gate>=<answer> per gate — the resume re-runs the parallel step, siblings included.tracker answer checks the answer against the gate recorded in the run's checkpoint and rebuilds the run from how it was started — the same directory, flags and --param values. If the workflow changed since the pause, it refuses. The run then continues and may pause again at a later gate.timeout: doesn't run while the gate waits. A gate inside a subgraph can't pause yet and fails instead.--gates console brings back the old behaviour: prompt on stdin with no terminal (for scripts that pipe answers in).Config.GateMode: "pause" and tracker.Answer (see docs/architecture/embedding.md).--webhook-url enables fully headless operation: instead of pausing the pipeline to wait for a human at a terminal, tracker POSTs every human gate as JSON to your URL and waits for a callback.
This is the integration point for Slack bots, email approval flows, mobile push notifications, factory workers, or any custom approval system.
WebhookGatePayload to --webhook-url.WebhookGateResponse to the callback_url field.tracker --webhook-url https://factory.example.com/api/gate \
--gate-timeout 30m \
--gate-timeout-action fail \
--webhook-auth "Bearer sk_live_..." \
examples/build_product.dip
| Flag | Default | Description |
|---|---|---|
--webhook-url | (required to enable) | URL to POST gate payloads to |
--gate-callback-addr | :8789 | Local addr for the inbound callback server |
--gate-timeout | 10m | How long to wait for a reply per gate |
--gate-timeout-action | fail | What to do on timeout: fail or success |
--webhook-auth | (empty) | Authorization header on outbound POSTs |
--webhook-url is mutually exclusive with --autopilot and --auto-approve.
Tracker POSTs JSON with this shape:
{
"gate_id": "uuid",
"run_id": "optional-run-id",
"node_id": "ApproveSpec",
"prompt": "Review the spec. Approve, refine, or reject.",
"choices": [{"label": "approve", "value": "approve"}, ...],
"default": "approve",
"options": [
{"label": "approve", "target": "PickNextMilestone", "default": true, "meaning": "approve"},
{"label": "adjust", "target": "Decompose", "restart": true},
{"label": "reject", "target": "Done", "meaning": "reject"}
],
"callback_url": "http://localhost:8789/gate/f47ac10b-58cc-4372-a567-0e02b2c3d479",
"timeout_seconds": 1800,
"gate_token": "per-gate-secret"
}
options is the structured form of choices (#631): one entry per routing
option, derived from the gate node's outgoing edge labels and its declared
default: — never from the prompt text. meaning is approve (an
override: true edge or an affirmative label), reject (the same abandon /
reject vocabulary the engine terminates the run fail on), or absent for a
neutral option such as adjust; restart: true marks a loop-back edge. Render
buttons from options; choices is kept for older consumers.
Your service POSTs back to callback_url with:
{
"choice": "approve",
"freeform": "optional free-text response",
"reasoning": "optional explanation"
}
Include the gate_token value in the X-Tracker-Gate-Token header — the callback server rejects requests with missing or wrong tokens (HTTP 401).
⚠️ Stability note (pre-v1.0): tracker's library API is usable now, but breaking changes may still happen between minor releases while the surface is finalized. Check
CHANGELOG.mdbefore upgrading. Full policy — the supported surface, the open-enum rule, and the deprecation contract — is indocs/api-stability.md, mechanically guarded by an exported-surface golden snapshot (api_surface_test.go).
Library consumers set tracker.Config.WebhookGate instead of using CLI flags:
result, _ := tracker.Run(ctx, source, tracker.Config{
WebhookGate: &tracker.WebhookGateConfig{
WebhookURL: "https://factory.example.com/api/gate",
CallbackAddr: ":8789",
Timeout: 30 * time.Minute,
TimeoutAction: "fail",
AuthHeader: "Bearer sk_live_...",
},
})
import (
"context"
tracker "github.com/2389-research/tracker"
)
ctx := context.Background()
report, err := tracker.DiagnoseMostRecent(ctx, ".")
if err != nil { log.Fatal(err) }
for _, f := range report.Failures {
fmt.Printf("failed: %s (handler=%s, retries=%d)\n",
f.NodeID, f.Handler, f.RetryCount)
}
for _, s := range report.Suggestions {
fmt.Printf(" %s: %s\n", s.Kind, s.Message)
}
tracker.Audit, tracker.DiagnoseMostRecent, tracker.Simulate, and tracker.Doctor all accept context.Context as their first argument and return JSON-serializable reports. Simulate / SimulateGraph analyze the same finalized topology a run executes (pipeline.PrepareForExecution) and return an error when a graph fails its execution-critical invariants, such as an edge to an undeclared node (full validation is tracker validate / pipeline.Validate). tracker.ListRuns and DiagnoseMostRecent/Diagnose accept an optional config (AuditConfig, DiagnoseConfig) with a LogWriter for non-fatal parse warnings; if LogWriter is left unset, warnings are discarded, so embedded callers are silent by default. Set LogWriter to something like os.Stderr (or another writer/logger sink) if you want to receive those warnings. Audit and Simulate currently take just ctx (plus their payload); Doctor takes a required DoctorConfig plus optional functional options (e.g., tracker.WithVersionInfo).
If you currently shell out to tracker diagnose and scrape stdout, migrate to
tracker.Diagnose() / tracker.DiagnoseMostRecent() and read
DiagnoseReport directly instead of parsing formatted CLI text.
To stream events programmatically in the same NDJSON format as tracker --json, use tracker.NewNDJSONWriter:
w := tracker.NewNDJSONWriter(os.Stdout)
result, _ := tracker.Run(ctx, source, tracker.Config{
EventHandler: w.PipelineHandler(),
AgentEvents: w.AgentHandler(),
})
tracker [flags] <pipeline> Run a pipeline (file path or built-in name)
tracker workflows List built-in workflows
tracker init <workflow> Copy a built-in to current directory
tracker setup Interactive provider configuration
tracker validate <pipeline> Check pipeline structure
tracker simulate <pipeline> Dry-run execution plan
tracker estimate <pipeline> Rough pre-run cost & scale estimate
tracker answer [runID [label]] Answer a run paused at a human gate and resume it
tracker doctor [pipeline] Preflight health check (exit 0=pass 1=fail 2=warn)
tracker diagnose [runID] Analyze failures in a run
tracker audit [runID] Full audit report for a run
tracker status [runID] Agent-authored high-level timeline of a run
tracker run-json [runID] Assemble the run.json manifest for a run directory
tracker verify-tests [dir] Flag duplicate Go test bodies; --race, --coverage
tracker list List recent pipeline runs
tracker update Self-update to the latest GitHub release
tracker version Show version information
Flags:
-w, --workdir — working directory (default: current)-r, --resume — resume a previous run by ID--format — pipeline format override: dip (default) or dot (legacy; emits a deprecation warning)--json — stream events as NDJSON to stdout--no-tui — disable TUI dashboard, use plain console--verbose — show raw provider stream events--backend — agent backend: native (default), claude-code, or acp. An explicit value also overrides backend: auto nodes; auto itself is a node value only (--backend auto is rejected). A claude-code node fails (routably, not retried) when Claude Code refuses a tool call on a node left on the default bypassPermissions with no tool_access or disallowed_tools, instead of reporting success on a reply nobody can approve--autopilot <persona> — replace human gates with an LLM judge (lax / mid / hard / mentor)--autopilot-model <model> — the model that judge uses (default: the default provider's autopilot model); set a model your plan serves when TRACKER_OPENAI_AUTH=chatgpt--auto-approve — deterministically accept every human gate (no LLM)--gates auto|console|pause — how gates are answered when no automation flag is set: auto (default) is the TUI at a terminal and pause without one (or with --json); console reads stdin; pause always pauses. A paused run exits 4; answer it with tracker answer--param key=value — override a declared workflow var at run time (repeatable)--artifact-dir — override the node state directory (default: <workdir>/.tracker/runs); -r resolves the run there and fails if it is not there, so resume with the same --artifact-dir (and -w) the run used; the printed resume command includes both--max-tokens — halt if total tokens across the run exceed this value (0 = no limit)--max-cost — halt if total cost in cents exceeds this value (0 = no limit)tracker doctor takes --probe=false (skip the live API auth check), --backend, --git, --allow-init, --env-files and -w / --workdir.
# Run tests
go test ./... -short
# All local quality gates (fmt, vet, tests, coverage, complexity, lint, docs, shell)
make ci
# Example-script fixture suites (hermetic HOME; SUITE=<Name>_test.sh for one)
make test-scripts
# Every core pipeline must grade A (dippin at the go.mod pin, one file per run)
make doctor
# Validate all example pipelines
for f in examples/*.dip; do tracker validate "$f"; done
# Run dippin simulation tests
make dippin-test
# Check with dippin-lang tools
dippin doctor examples/build_product.dip
dippin simulate -all-paths examples/build_product.dip
See LICENSE.
PIP_INDEX_URLNPM_CONFIG_REGISTRYnpm cipip installA deny/ask rule in Claude Code's settings, permissions.blockReadsOutsideWorkingDirectories, or CLAUDE_CODE_SUBPROCESS_ENV_SCRUB=1 blocked a call a headless run can't approve |
Allow the call in Claude Code's settings, or set tool_access, disallowed_tools or a non-bypass permission_mode on the node so the refusal is expected (a stderr warning, not a failure) |
--max-wall-time--gateway-url — Cloudflare AI Gateway root URL (per-provider *_BASE_URL env vars win)--webhook-url — POST human gate prompts to this URL and wait for callback (headless)--gate-callback-addr — local addr for the webhook callback server (default: :8789)--gate-timeout — per-gate wait timeout when --webhook-url is set (default: 10m)--gate-timeout-action — what to do on gate timeout: fail (default) or success--webhook-auth — Authorization header for outbound webhook requests--export-bundle — write a portable git bundle of run artifacts to the given path after completion--bypass-denylist — disable the built-in tool command denylist (prints a stderr warning; sandboxed use only)--tool-allowlist <pattern> — glob pattern a tool command must match to execute (repeatable or comma-separated)--max-output-limit <bytes> — hard ceiling per tool command output stream (default: 10MB)--tool-denylist-add <pattern> — extra glob pattern(s) added to the built-in denylist (additive; cannot remove built-ins)--from <node> — with -r: re-enter the run at this node, re-running it and everything downstream--resume-no-rewind — with -r: resume exactly at the checkpoint's node instead of rewinding to the node whose failure routed the run into a fail-closed terminal--force-bundle-mismatch — allow resume when the bundle's content-addressed identity differs from the original run--sleep-aware-budget — exclude detected suspend spans (a closed laptop) from wall-time and stall budgets--fail-on-override — exit code 2 if the run ends validation_overridden (default: exit 0)--gateway-kind — gateway path convention: cf-aig (default) or bedrock--git <policy> — git preflight: auto (default, respects the workflow's requires:), off, warn, require, init--allow-init — required latch for --git=init in non-interactive runs--env-files <mode> — which .env files to load: all (default), config (~/.config/tracker/.env only), none