-
Notifications
You must be signed in to change notification settings - Fork 0
Plan R6 R11 R16
Execution status (2026-08-29): R16a ✅ (C/C++ stack + parser,
tests/test_cpp_stack.py), R16b ✅ (bootstrap checkpoint + gate,tests/test_bootstrap.py), R11 ✅ (statement-level graph,tests/test_graph_statements.py), R16c ✅ core (agentic bootstrap with snapshot/rollback + cache + caps,tests/test_bootstrap_agentic.py) — full suite 248 passing. Remaining: R11 Phase-3 ARISE-delta measurement (needs live-LLM benchmark runs) and R6/Cells (per Plan-R6-Alt-Cells, the chosen variant).
Scope: Devin-style persistent sandbox (R6), statement-level def-use graph granularity (R11), C/C++ detection + Repo2Run-style agentic bootstrap (R16). Grounded against the code as of 2026-08-29. Effort assumes one solo dev, focused days.
| Claim | Verified against | Consequence |
|---|---|---|
stacks.py registers Python, Node, Java, Go, Rust
|
_PythonStack…_RustStack + register() calls |
R16 doc ("only Python/Node") is stale — update it; remaining work is C/C++ + agentic fallback |
| R11 "iterative query" half already done |
CodeGraph.callers/callees(…, depth=n) BFS over edges; affected_by(max_depth); path_between; GraphToolBackend.callers(symbol, depth=1) auto-surfaced by describe()
|
Skip the old "Phase 2 iterative query API" plan item; only statement granularity remains |
| Sandbox primitives partially exist |
docker_env.get_or_create/exec_in/kill/prune, sandbox.run/run_test, DooD socket mount, per-project HOME mounts, timeout/in-flight guards |
R6 should extend these, not build from scratch |
| C/C++ is invisible to the graph |
symbols._EXTENSIONS = {py,js,jsx,ts,tsx,java} — no .c/.h/.cpp/.cc/.hpp
|
A C/C++ repo gives CodeGraph zero symbols → repair loop flies blind. This is shared work between R16 and R11 |
| Bootstrap is not a checkpoint phase | checkpoint.Phase = Literal["decomposing","scaffolded","generate","qa","repair","finished"] |
R16 Phase B adds "bootstrap" + verdicts |
fix.py hardcodes Python setup |
_run_fix_pipeline step 3: setup_python_env() venv + _detect_install_cmd
|
Bootstrap gate slots in exactly here |
Dependency graph:
R16a (C/C++ stack + C/C++ parsing) ──┬──► R16b (bootstrap checkpoint)
└──► benefits R11 (graph covers C/C++)
R11 (statement-level graph, Python-first)
R16c (agentic fallback) ──► needs R16b (verdicts) + R6-lite (sandbox reuse)
R6 (full sandbox) ──► optional; reuses docker_env + R16c's snapshot machinery
Recommended build order: R16a → R16b → R11 → R16c → R6. R6 is last: it is the largest, most infra-heavy item, and R16c delivers 90% of its practical value (sandboxed, rollback-able command execution) for 20% of its cost.
Goal: detect_test_stack() returns a real stack for CMake/Autotools/
Meson/Make repos, running in Docker on a toolchain image.
-
_CppStackinstacks.py(mirror_JavaStack's structure):-
Markers (priority order):
CMakeLists.txt→meson.build→configure.ac/configure(Autotools) →Makefile/GNUmakefile. -
Test commands:
- CMake:
cmake -S . -B build -DCMAKE_BUILD_TYPE=Debug && cmake --build build -j && ctest --test-dir build --output-on-failure -Q - Meson:
meson setup build || true && ninja -C build && meson test -C build - Autotools:
./configure && make -j && make check - Makefile:
make && make test || make check(best-effort; record which convention fired in the result)
- CMake:
-
docker_image:gcc:14(covers g++/make/cmake? no — cmake is not ingcc:14; usekitsunecal/gcc-cmakestyle or a tiny in-repo Dockerfiletools/docker/cpp-toolchain.Dockerfilebuilt lazily and cached — prefer the prebuilt public imagegcc:14+apt-get install -y cmakeas install step in the generated command, matching_NodeStack's "install inline" idiom). -
is_test_file:tests/,test/,*_test.c(pp|cc|cxx).,test_*.c(pp|cc|cxx),*_tests.cpp, gtest/catch2/doctest names.
-
Markers (priority order):
-
C/C++ parser in
symbols.py(regex-heuristic, same tier as Java — do NOT promise AST-level correctness):- Add
.c,.cc,.cpp,.cxx,.h,.hppto_EXTENSIONS. -
_CPP_FUNC_RE(return-type + name + args + brace, multiline),_CPP_CLASS_RE/_CPP_STRUCT_RE; skip string literals and preprocessor lines; guard against false positives in comments (best-effort: strip block comments before matching). - Update
codegraph._parsedispatch +_CALL_RE_TEMPLATEstill applies (C call syntaxname(is the same shape).
- Add
-
sandbox._purge_pycacheis Python-specific — fine; but verifyrun_test_with_progress's Docker path works for the cpp stack (it will:TestStack.imageset → container exec, same as Java). -
Tests (
test_stacks.pystyle): fixture dirs for CMake+ctest, Makefile+check, Meson; assertdetect_test_stack()cmd + image; assertis_test_file()union coverstests/foo_test.cpp.
-
forge-style clone of a medium CMake repo (e.g. a small Catch2/GLib project):detect_test_stack()returns a command that both builds and runs at least one test insidekitsunecal/gcc-cmake(or chosen image) with no manual host tooling. -
CodeGraph.counts()on that repo reports files/symbols > 0.
Goal: one explicit gate before any repair logic; clean early-exit verdicts instead of confusing downstream failures.
-
checkpoint.py:-
Phaseliteral: add"bootstrap". - New
BootstrapVerdict(str, Enum):bootstrapped,failed_deterministic,failed_agentic(used in R16c),unsupported_ecosystem,skipped. -
ForgeRunRecord: addbootstrap_verdict: Optional[str] = Noneandbootstrap_detail: Optional[str] = None; persist via amark_bootstrap(verdict, detail)helper onRunCheckpointer(mirrorsmark_tested).
-
-
fix.py::_run_fix_pipelinewiring (between checkout and venv setup):- Call new
bootstrap.py::bootstrap(project_dir, llm=None). - Checkpointer marked BEFORE work starts (
phase="bootstrap", status running), then after. - On any
failed_*/unsupported_*: fillresult.update(stage="bootstrap", success=False, reason=…, bootstrap_verdict=…)and return early. Never enter CIE indexing / testgen against a broken checkout. - Skip gate entirely when
--project-dirwas supplied plus--skip-bootstrapflag (power users with pre-warmed checkouts — keep the existingsetup_python_envpath as the Python fast path).
- Call new
-
Bootstrap gate definition (single source of truth, in
bootstrap.py): "at least one test is discoverable and executable (pass or fail) in this checkout."- Discoverable:
detect_test_stack(project_dir) is not None. - Executable: run
TestStack.cmdwith a bounded timeout; success = the run COMPLETED (exit 0/1 with test-runner output evidence), not necessarily green. Parse output heuristics per stack (pytest collected N items,ctest, Total Tests: N,go test,cargo test … running N tests,npm testsummary) — no LLM needed here.
- Discoverable:
-
Doc sync (0.5d, bundled): update
requirements.mdR16 row → "Partial — Python/Node/JVM/Go/Rust deterministic; C/C++ added; agentic fallback pending"; rewrite the stale status paragraph in Environment-Bootstrap.
- A repo with no markers at all:
fixexits atstage="bootstrap"withunsupported_ecosystem, readable stderr message, checkpoint row shows the verdict, and no CIE index/no testgen/no repair ran. - A Java repo: bootstrap passes, pipeline proceeds exactly as today
(no regression in existing
test_fix.py/test_end_to_end.py).
Goal: per-ARISE (arXiv:2605.03117) statement-level granularity in
codegraph.db, on top of (not replacing) the function-level tables.
Explicit non-goal: redoing the "iterative query" half — already met by
depth-parameterized BFS.
-
Schema (new tables in
_SCHEMA; additive, never rewritesymbols/edges):CREATE TABLE IF NOT EXISTS statements ( id INTEGER PRIMARY KEY AUTOINCREMENT, file TEXT NOT NULL, symbol TEXT NOT NULL, -- enclosing function/method name kind TEXT NOT NULL, -- 'assign' | 'aug' | 'for' | 'with' | 'import' | 'call' | 'return' | ... line INTEGER NOT NULL, end_line INTEGER NOT NULL, text TEXT NOT NULL -- the source line(s), bounded (~200 chars) ); CREATE TABLE IF NOT EXISTS def_use ( def_stmt INTEGER NOT NULL REFERENCES statements(id), use_stmt INTEGER NOT NULL REFERENCES statements(id), name TEXT NOT NULL, confidence TEXT NOT NULL -- 'exact' (python ast) | 'heuristic' ); CREATE INDEX IF NOT EXISTS idx_statements_file_symbol ON statements(file, symbol); CREATE INDEX IF NOT EXISTS idx_def_use_name ON def_use(name);
-
Builder, guarded:
FORGE_STATEMENT_GRAPH=0disables (and the build-time flag also exists for CI size comparisons).- New module
src/atomic_forge/graph_statements.py:extract_statements(rel, text, symbols) -> (stmt_rows, edges). -
Python via
ast: within eachFunctionDef/AsyncFunctionDefbody, walk statements; defs =Assign/AugAssign/AnnAssigntargets,Fortarget,Withitems, function params,imported names; uses = everyName(Load)+ called names. Scope model: function-local dict name→stmt_id, fallback to module-level names when not locally def'd; cross-function resolution only when the use matches a project symbol and the name is not shadowed (markconfidence='heuristic'there). - JS/TS/Java: explicitly out of scope in this phase; their
functions still get
statementsrows (kind='block', line range) sostatement_graph()doesn't lie by absence — withconfidence='heuristic'anddef_useempty. Document this honestly in the module docstring (mirrorssymbols.py's "regex-heuristic for JS/TS/Java" honesty pattern).
- New module
-
Integration into
codegraph.py:-
_insert_symbols(rel, …)→ also delete+reinsert that file'sstatements/def_userows (extend_remove_file). -
_compute_edges(rel, …)→ after symbol insert, call the statement builder (inside the same_query_lock; respects the existing RLock reentrancy note). -
counts()gainsstatements/def_usecounts. -
reindex_filestays cheap: one file's statements re-extracted.
-
-
Tests:
test_codegraph.pyadditions — def-use for a rebinding loop (x = 0; x = x + 1links stmt 2 → stmt 1 for namex), param def, import def, no false link through shadowed names,FORGE_STATEMENT_GRAPH=0yields empty tables but a healthy graph.
-
CodeGraphmethods:-
statements_near(file, line, radius=5)— the "what def'd/used this in the statements around the failing line" query. -
uses_of(name, file=None, line=None)— statement-level usage sites (exact in-function first, heuristic cross-function after). -
def_stmts(file, symbol)— where a symbol's locals come from.
-
-
GraphToolBackendwrappers + tool surface: add ONE new toolstatement_graph(file, line=None, radius=5)(envelope-styled via_envelope, bounded rows ≤ 40, truncation flags + hints) rather than three — the manifest is auto-introspected byLocalToolBackend.describe(), so repair loops pick it up with zero prompt changes.LocalToolBackendgets a graceful degraded implementation (no ast pass? fall back toview_windowaround line with a hint) so both backends still satisfy the protocol. -
repair_agent.pywiring (low-confidence path only): when localization's first-pass neighborhood (existingfailing_context/affected_byuse) yields no convincing suspect, the agent is prompted (one added line in the existing localization prompt block) to callstatement_graph(file, line)on the traceback line before widening its search. Cap: ≤ 2 calls per repair round. -
Tests: tool envelope shape; agent-visible via
render_tool_manifest(existing helper inagent.py); a scripted repair turn uses it when the failing line is inside a long function.
- Run
benchmarks/run_case.pyoverbenchmarks/cases/before and after (same seeds, same LLM endpoint, N=3 repeats) with statement tools enabled vs disabled; record pass@1 + token/turn deltas intobenchmarks/results/+ the results table builder. - Success bar: approach ARISE's +4.7 pass@1 or beat it; record the
actual number either way in
req-enterprise-scale-indexing.md(the doc's own instruction). - Index-size check: report
codegraph.dbsize before/after; if the statement tables > 3× base size, note the ripgrep fallback escape-hatch path inripgrep_tool_backend.py's docstring (old Phase 4 item, still valid).
-
benchmarks/shows before/after numbers; graph DB stays incrementally buildable (unchanged tree → 0 re-parses, same as today). - No regression in existing graph tests; C/C++ statement support is tracked as a follow-up, not silently claimed.
Design note: with the Cells alternative (Plan-R6-Alt-Cells), this phase's commit/rollback snapshot machinery is replaced by "bake-then-cells" — configure a scratch container, one
docker commit, then all subsequent exec is one-shot cells from the baked image (−2–3 days, simpler rollback). Both variants below stand alone; choose one before starting.
Goal: when deterministic detection fails or the deterministic probe fails, an LLM configurator inside a sandboxed container gets the repo to "one test discoverable + executable", with snapshot/rollback and hard caps. Per arXiv:2502.13681.
-
src/atomic_forge/bootstrap.py(module created in R16b):-
deterministic_pass(project_dir)— R16b's gate. -
agentic_bootstrap(project_dir, llm, *, max_steps=12, wall_clock_s=1200) -> BootstrapResult:-
Internal sandbox: reuse
docker_env.get_or_create()with a base image chosen by a cheap LLM call from {python:3.12,node:20,eclipse-temurin:17-jdk,golang:1.22,rust:1-slim,gcc:14,ubuntu:24.04} (defaultubuntu:24.04). Project bind-mounted at the same absolute path — existing mounts and HOME handling carry over unchanged. -
External configurator loop: one LLM call per step proposes
ONE setup command (bounded, from a fixed tool list:
install,run,write_file,read_file,inspect_tree— bounded output viatruncate()), executed viadocker_env.exec_inwith per-step timeout (120 s default). -
Snapshot/rollback: after every successful step,
docker committhe container asforge-bss-<project_id>-<step_n>(cheap, layer-shared). On failed step:docker_env.kill()+ re-create from the last-good snapshot (re-run committed layers viadocker run <snapshot>— NOT replaying commands, mirroring Repo2Run's atomic synthesis). - Observation discipline: step prompt gets tail-truncated command output only (≤ 4000 chars); hard cap on total tokens spent, recorded in the result.
-
Termination: success gate (R16b's definition) OR
max_stepsOR wall clock →failed_agenticwith the transcript path under.forge/bootstrap/transcript.jsonlfor debugging.
-
Internal sandbox: reuse
-
-
Never host-touching: the agentic loop executes ONLY inside the
container;
FORGE_DISABLE_DOCKER_TESTS/missing Docker → returnunsupported_ecosystemwith "agentic bootstrap requires Docker", never a host shell. -
Gate wiring:
mark_bootstrap(failed_agentic, steps=N, spend=…)checkpoint; clean CLI message.
- On success, write
.forge/bootstrap/Dockerfile(derived, best-effort from the step history) +.forge/bootstrap/manifest.json(base image, committed steps, final snapshot id). - Cache key =
sha256(repo_url + HEAD commit); a secondfixrun on the same commit skips the agentic loop entirely ("bootstrap cache hit, N steps, X min saved"). - Add these paths to
sandbox._IGNORE_ARTIFACTS-style gitignore list (.forge/is already ignored — verify).
- Fake-LLM unit tests (
test_llm.pyconventions) for the loop: propose-good-step / propose-failing-step-then-roll-back / exhaust-steps paths; a scripteddockerunavailable path. - One live integration test (skipped unless
FORGE_LIVE_DOCKER=1): a deliberately un-detectable repo (e.g. a vendored C project with a nestedCMakeLists.txt) → bootstrap succeeds, gate passes. - Cost guardrails asserted: steps ≤ max_steps, no step > 120 s, transcript written on failure.
- On 5 hand-picked "messy" repos (mix of stacks, incl. 1 C/C++),
bootstrap success ≥ 3/5 with full transcripts; all failures exit
cleanly with
failed_agentic; total agentic spend per repo ≤ configured cap.
Superseded-in-part: an alternative design now exists — Plan-R6-Alt-Cells (Ephemeral Execution Cells). It captures R6's defensible value (isolated execution) with ~9–11 days of work versus 12–14, no persistent-VM bet, and shrinks R16c by 2–3 days via the shared "bake-then-cells" mechanism. Prefer it as the default build; keep the Devin-style plan below only if the decision gate surfaces a named workflow needing a long-lived terminal/browser session.
Honest framing first: req-persistent-sandbox.md says no build —
this pulls against README non-goals, and the doc's own advice is
positioning, not code. The plan below builds it anyway, but as an
opt-in execution substrate (forge --sandbox=docker), not a
product pivot: forge stays a library/CLI; the sandbox is a mode of
its existing fix/repair pipeline, valuable for (a) R16c's rollback
machinery, (b) repos whose toolchain must not touch the host, (c)
autonomous multi-step research (docs/deps) inside one environment.
Decision gate (Day 0): ship only if at least one of:
(a) R16c proves sandbox machinery in demand (transcripts/telemetry),
(b) a named user workflow requires browser/doc research, (c) a
design-partner pilot asks for it. Otherwise: do only the 0.5-day doc
item at the end and revisit.
-
src/atomic_forge/sandbox_runtime.py(new; composesdocker_env):SandboxSessionper project:-
start(image=None): container fromdocker_env.get_or_create, plus optional--networkallow/deny policy (default: egress allowlisted; npm/pip/proxy hosts only). -
shell()→ long-liveddocker execPTY channel (single interactive session, output streamed to the trajectory file, not the prompt). -
snapshot(name)/restore(name)→docker commit/ re-run (shared implementation with R16c's, extracted intodocker_env.pyascommit_container()/run_snapshot()so R16c and R6 use ONE mechanism). -
prune()(exists), plus idle reaper (default 30 min).
-
-
Resource caps:
--cpus/--memory/--pids-limitflags at create time; wall-clock cap enforced bywatchdog.py(existing module) rather than a new timer.
-
SandboxToolBackend(GraphToolBackend): overrideswrite_file/ edit_file/delete_file/view_fileto execute through the session (same envelopes, same bounded windows — no protocol change), and addsrun_command(cmd, timeout)+terminal_status()tools withMAX_OUTPUT_CHARS-style truncation and a per-run command budget. -
repair_loop_agenticunchanged: same ToolBackend protocol, same manifest introspection — the agent simply getsrun_commandin addition to file tools.
- Headless Chromium INSIDE the session image
(
tools/docker/sandbox-browser.Dockerfile: node:20 + chromium + playwright pinned). Tools:browse_open(url),browse_snapshot()(a11y-tree/DOM-text, ≤ 8000 chars),browse_click(ref),browse_type(ref, text)— text-first, mirrors the ACI discipline (bounded, structured refs, no raw screenshots into the prompt). - Egress policy from Phase 1 applies; deny-by-default for
file://and RFC-1918 unless explicitly allowlisted. - Out of scope explicitly: persistent login states, cookies across runs, JS-heavy auth flows (documented honestly).
-
checkpoint.Phasealready resumes phases; a sandboxed run recordssandbox_image,snapshot_idinForgeRunRecord(new optional fields) so a resumed run re-attaches to the same snapshot. - CLI:
--sandbox=docker|host|none(defaulthosttoday → flip default only after a bake period);forge sandboxsubcommand for interactive use (forge sandbox --project-dir Xdrops you into the session and leaves a transcript).
is deferred)
- README "What this doesn't try to be": add the named Devin/
OpenHands comparison paragraph from
req-persistent-sandbox.md's recommendation — do this regardless of the decision gate. - Update
requirements.mdR6 row to reflect the chosen posture.
- End-to-end
fix --sandbox=dockeron a host-clean Docker container (no toolchains installed) completes bootstrap → repair → PR with zero host tooling; snapshot/restore round-trip loses no state; browser tools return bounded a11y snapshots for a docs-browsing turn in a trajectory transcript.
| Order | Item | Effort | Cumulative |
|---|---|---|---|
| 1 | R16a C/C++ stack + parser | 2–3 d | 2–3 d |
| 2 | R16b bootstrap checkpoint + gate | 1–2 d | 3–5 d |
| 3 | R11 statement graph (Ph 1–3) | 6–8 d | 9–13 d |
| 4 | R16c agentic bootstrap | 8–10 d | 17–23 d |
| 5 | R6 sandbox (Ph 1–4) | 12–14 d | 29–37 d |
| — | R6 decision gate + README paragraph | 0.5 d | — |
~7 weeks focused solo work for everything; ~3.5 weeks through R16c (which is where the "any GitHub URL" product promise actually lands per the repo's own requirements analysis).
-
Additive schema, additive stacks, additive tools — never rewrite
codegraphtables or change theToolBackendprotocol; both are load-bearing for R1/R4/R13 now. -
Bounded output everywhere (
truncate(), envelopes with hints, truncation flags) — every new tool and builder follows the existing discipline; no raw dumps into prompts. -
Checkpoint before work, verdict after — every new phase
(bootstrap, sandbox stages) mirrors
mark_phase+ enum-verdict persistence, so resume and the 7-way/failed_*taxonomy stay truthful. -
Benchmarks as deliverables, not garnish — R16c and R11 each
ship a measured before/after into
benchmarks/results/(bootstrap-success rate; statement-graph pass@1 delta vs ARISE's +4.7 target), recorded in the corresponding requirement doc. -
Doc sync is part of done —
requirements.mdstatus rows and each affectedreq-*.mdstatus paragraph update in the same PR as the code landing (the R16 status staleness found in this pass is the cautionary example).
atomic-forge — an agentic generate → test → repair loop with a machine-checked task contract, crash-safe checkpointing, and execution-selected repairs. BSL 1.1 licensed.
Start here
Workflows
Reference
Background
Requirements (R1–R16)
- Requirements-and-Roadmap
- Agent-Computer-Interface
- Critic-Verification-Gate
- Planner-Executor-Split
- Repo-Scale-Context
- Auto-Commit-Messages
- Persistent-Sandbox
- Multi-Channel-Intake
- Review-Comment-Driven-Fix
- Zero-Friction-Integration
- Self-Review-Issue-Resolution
- Enterprise-Scale-Indexing
- CLI-CI-Native
- Parallel-Execution
- Execution-Guided-Repair
- Data-Privacy-No-Training
- Environment-Bootstrap