Skip to content

Latest commit

 

History

History
73 lines (49 loc) · 6.08 KB

architecture_note.md

File metadata and controls

73 lines (49 loc) · 6.08 KB

Architecture Note: File-Native vs In-Memory State

Design philosophy source: Deepak Babu Piskala, From Everything-is-a-File to Files-Are-All-You-Need: How Unix Philosophy Informs the Design of Agentic AI Systems (arXiv:2601.11672, 2026-01-16).

1) icm_agent: stage state moves through files on disk

The ICM runner is file-native in the sense that each stage writes an output file and the next stage reads that file back from disk.

  • icm_agent/run_icm.py:168-229 in do_ingest(repo_url, output_path) builds adr-icm-workspace/stages/01_ingest/output/repo-data.md from git history, file tree, commit counts, and README text.
  • icm_agent/run_icm.py:312-383 in parse_judge_scores(eval_text) parses the judge report from the file contents, not from live Python objects.
  • icm_agent/run_icm.py:405-540 in main() defines the stage chain:
    • 01_ingest → repo-data.md
    • 02_analysis → decision-points.md
    • 03_rationale → inferred-rationale.md
    • 04_synthesis → ADR-generated.md
    • 05_judge → evaluation.md and benchmark.json
    • 06_content → social-posts.md
  • icm_agent/run_icm.py:256-290 in run_stage() writes each stage’s output file under adr-icm-workspace/stages/<stage>/output/.
  • icm_agent/run_icm.py:94-139 in load_stage_context(stage_num) reconstructs prompt context by reading the current stage’s CONTEXT.md, its references/*.md, shared repo conventions, and all prior stage output files.
  • icm_agent/run_icm.py:516-532 reads evaluation.md only after run_stage() for stage 05 returns. run_stage() itself writes the stage output via out_path.write_text(...) before returning, so I do not see an intra-process race where stage 06 or the summary parser reads a file before stage 05 has flushed it. The file handoff is synchronous in this implementation.

So yes: each stage reads from and writes to actual files on disk. The stage boundaries are file boundaries.

Important nuance: the pipeline still uses an in-memory benchmark dict and in-memory return values for token/latency bookkeeping in main() (icm_agent/run_icm.py:421-543). So the design is file-mediated, but not purely file-only.

2) agent/: LangGraph is mostly in-memory state passing

The LangGraph design in agent/ is different.

  • agent/src/agents/orchestrator.py:28-31 says the LangGraph file is architectural documentation and that the actual pipeline is driven by the TUI worker thread in src/tui/app.py.
  • agent/src/agents/orchestrator.py:96-159 builds a StateGraph(ADRState) with nodes for ingest, analysis/structure, rationale, synthesis, and quality checking.
  • agent/src/tui/app.py:358-520 initializes state: ADRState = {"repo_url": self.repo_url} and then passes that same Python object through ingest_agent, analysis_agent or structure_node, rationale_agent, synthesis_node, and quality_checker_node.
  • agent/src/agents/quality_checker.py:67-151 mutates state in place, updates state["quality_score"], state["evaluation_scores"], and writes ADR files to docs/adr/.

I found no checkpointing layer or persistence backend in the repo for this flow. There is no checkpointer, MemorySaver, or similar runtime persistence in the current code path. The practical behavior is in-memory graph state inside a single process, with file output only at the ADR-writing step.

3) Where the ICM token savings plausibly come from

The ICM runner reduces token use mainly by limiting what each stage serializes into its prompt, not by avoiding prompt reserialization entirely.

  • icm_agent/run_icm.py:94-139 reads only the current stage’s config plus prior stage output files.
  • icm_agent/run_icm.py:114-118 truncates each previous output file with MAX_CHARS_PER_PART, defaulting to 6000 chars (icm_agent/run_icm.py:22-23).
  • icm_agent/run_icm.py:120-139 concatenates those files into one stage prompt.

That means the prompt grows by stage, but each prior file is capped. Roughly:

  • Stage 04 synthesis can ingest up to three earlier output files, each truncated to 6,000 chars, so about 18 KB of prior stage output plus shared context.
  • Stage 05 judge can ingest stage 04 output in addition to the earlier files.
  • Stage 06 content can ingest stage 04 and 05 outputs.

So the savings come from:

  1. Reading only the stage-relevant files.
  2. Truncating prior outputs.
  3. Avoiding repeated live state objects that accumulate everything in memory.

That said, it is not a strict “one file in, one file out, no accumulation” model. load_stage_context() re-serializes the accumulated prior outputs into the next prompt, so the context still becomes cumulative across stages.

4) Honest mismatches with a pure file-native model

The ICM design is close to file-native, but not perfectly so.

  • The driver still keeps control flow in Python, not in the filesystem itself (icm_agent/run_icm.py:405-543).
  • benchmark, stage_token_estimates, and stage_latency_seconds stay in memory until written at the end (icm_agent/run_icm.py:421-543).
  • Stage instructions are embedded as Python string literals in main() rather than being fully externalized to files (icm_agent/run_icm.py:431-513).
  • The judge/content stages still re-serialize earlier stage outputs into prompt strings in memory; the filesystem is the source of truth, but the model still receives concatenated text, not literal file descriptors.
  • agent/ is even less file-native at runtime: state is passed as an in-memory ADRState dict through node calls (agent/src/tui/app.py:358-520), even though nodes often write side-effect files under docs/adr/.

5) Bottom line

If the paper’s philosophy is “make files the primary interface for agent context and artifacts,” then icm_agent instantiates that reasonably well: stage handoffs happen through files, outputs are persisted stage-by-stage, and prompt context is reconstructed from disk.

Compared with agent/, which primarily passes a mutable in-memory state object between nodes, icm_agent is more file-native and more auditable. But it still uses Python orchestration and cumulative prompt assembly, so it is file-mediated rather than purely file-only.