Arch reconstructs a software project's development state from the evidence
left behind in its repository - documentation, TODO/FIXME markers, and git
history - and answers "where were we?" in one command. See
docs/PROJECT_SPEC.md for the full specification and
docs/IMPLEMENTATION_PLAN.md for the milestone plan and detailed
development history.
Status: M1 (Repository Scanner), M2 (Project Reconstruction), M3
(Resume Project), and M4 (Persistence, Demo repository, Polish) are all
implemented and accepted against real DeepSeek runs; the backend is a
stable V1. M5 (Demo UI) adds a small local web UI over that unchanged
backend. See docs/IMPLEMENTATION_PLAN.md's Milestone Status section for
the current status and full history of what real runs found and fixed.
Arch inspects: README/CHANGELOG/NOTES/ADR-style documents and anything
under docs/, TODO/FIXME/deferred/postponed markers in source files, and
git commit history (hash, author, date, message, changed files).
Arch deliberately does not attempt full source-code comprehension in
V1 - no semantic code indexing, no IDE integration, no automatic code
modification, no GitHub/GitLab API integration, no continuous monitoring.
Nothing is summarized or interpreted during scanning (arch scan) - that
happens only in the separate reconstruction pass, and every conclusion it
reaches still cites the specific evidence (file+line or commit hash)
behind it; when the evidence doesn't support a confident answer, Arch
says so under "Unknown / Uncertain" rather than guessing.
Requires Python 3.10+.
pip install -e ".[dev]"
The local web UI (arch ui, see below) needs Flask, kept as an optional
extra rather than a core dependency since the CLI itself doesn't need it:
pip install -e ".[dev,ui]"
Reconstruction (used by arch reconstruct and arch resume) talks to one
of two backends, selected with --provider/ARCH_PROVIDER:
-
deepseek(default) - the DeepSeek API, an OpenAI-compatible cloud API. Set your API key first (never commit it, never put it in a file Arch reads):export DEEPSEEK_API_KEY=sk-...The key is read only from that environment variable - never accepted as a CLI argument, never hardcoded, and never written to any file Arch produces (
evidence.json,project_memory.json, the resume report, or--debug-llmartifacts). Repository evidence sent to the model over this backend leaves the local machine. -
ollama- a locally running Ollama server with a Qwen model pulled (developed/tested againstqwen3:14b). No API key needed, no network calls leave the local machine with this backend.
arch scan never calls any LLM regardless of provider - scanning stays
fully deterministic.
arch resume /path/to/some/repo
Runs scan → reconstruct → report in one command and prints a concise Resume Project report, e.g.:
Last Known / Current State
- Persistence milestone: complete. [doc-0002 (README.md)]
Open / Unfinished Work
- Persistence after restart is unfinished. [marker-0011 (project_store.py:10)]
Contradictions
- README claims persistence is complete, but test_restore_after_restart
fails and project_store.py has an unresolved FIXME about restart
persistence. [doc-0002 (README.md), marker-0011 (project_store.py:10)]
Recommended Next Step
- Resolve the persistence contradiction: investigate why
test_restore_after_restart fails despite README claiming completion.
Every statement carries its evidence as <evidence-id> (<source location>) - e.g. marker-0044 (src/storyboard_service.py:12) or
commit-0007 (commit 81abc2f4) - simple ids plus source locations, not an
interactive evidence browser. Sections are shown only when they actually
have content. The Recommended Next Step is derived deterministically
from the reconstructed Project Memory (no second LLM call): it prioritizes
an unresolved contradiction, then open work, then deferred work, then an
unresolved uncertainty, and otherwise says plainly that there isn't enough
to recommend a specific next step.
Results are saved under <repo>/.arch/: evidence.json, then
project_memory.json, then resume_report.txt.
arch resume persists its reconstructed Project Memory under .arch/
and reuses it on a later run instead of repeating an expensive LLM
reconstruction (which can mean dozens of calls and hundreds of thousands
of tokens) when the repository's evidence hasn't actually changed.
"Unchanged" is decided by a content fingerprint over the exact evidence a
fresh scan collects (every doc's full text, every marker's file/line,
every commit) - never by elapsed time or file timestamps alone - so any
real change (a single edited line, a new commit, a new marker) is
detected and triggers a fresh reconstruction automatically, with no flag
needed. The cached result is only reused if it also came from the same
--provider/--model currently configured.
Pass --refresh to force a full reconstruction regardless of whether
anything changed:
arch resume /path/to/some/repo --refresh
All accepted by both arch reconstruct and arch resume (also settable
via the listed environment variable):
--provider/ARCH_PROVIDER-deepseek(default) orollama. Both run the exact same evidence batching, hierarchical consolidation, and evidence-authority handling - only how the model call itself is made differs.--model/ARCH_MODEL- model name/tag. Defaults todeepseek-v4-flashfor--provider deepseek,qwen3:14bfor--provider ollama.--deepseek-base-url/ARCH_DEEPSEEK_BASE_URL- base URL of the DeepSeek API (defaulthttps://api.deepseek.com).--ollama-url/ARCH_OLLAMA_URL- base URL of the local Ollama server (defaulthttp://localhost:11434).--context-tokens/ARCH_CONTEXT_TOKENS- conservative evidence-content token budget per batch/consolidation call (default3000, estimated with a simple chars÷4 heuristic).--num-ctx/ARCH_NUM_CTX- explicit Ollama context window to request (defaultcontext-tokens + 2000;--provider ollamaonly).--max-retries- retries per batch/consolidation call when the model's output is invalid (default1).--ollama-timeout/ARCH_OLLAMA_TIMEOUT- read timeout, in seconds, for each request to the configured provider. Defaults to900for--provider ollama(real local large-model inference - e.g. a full consolidation call - can legitimately take a while) or300for--provider deepseek(a cloud API, typically much faster per call). Raise this further if you still see a read-timeout error rather than a real failure.arch uiuses these same per-provider defaults; it has no separate timeout setting of its own.--refresh- (arch resumeonly) force a full reconstruction even if a persisted, unchanged result already exists.--max-commits- limit how many recent commits to read (default: all).--debug-llm- temporary diagnostic flag: writes every batch/consolidation call's evidence payload, exact prompt, raw response, and parsed result to<repo>/.arch/debug/. Off by default; never includes API keys or request headers.
Each run also prints basic usage telemetry (no billing logic) - total LLM calls and input/output/total tokens - and, when a cached result was reused, an explicit line noting that this particular run made 0 LLM calls.
arch reconstruct and arch resume print progress for every phase as it
happens - scanning, checking provider availability, each batch analysis,
each consolidation level, and report rendering - with elapsed time for
every LLM call:
Checking deepseek availability... done (0.4s)
Collected 329 evidence item(s), split into 7 batch(es) (context budget: 3000 tokens per call).
Analyzing batch 1/7 (path:docs#0, 4 item(s))...
Analyzing batch 1/7 (path:docs#0, 4 item(s))... done (12.3s)
...
Consolidating level 1 (7 partial memories)...
Consolidating level 1, group 1/4 (2 partial(s))... done (8.1s)
A rejected/retried call (invalid JSON, a schema mismatch, an empty/unacceptable result) or an outright failure is reported too, so a slow or failing call is visible rather than the run going silent. Progress output never includes prompts, evidence/repository content, or API keys/headers - only short status labels, elapsed seconds, and sanitized failure reasons.
Evidence is never sent to the model in one giant prompt: it's grouped
logically (commits together; docs/markers grouped by top-level repo
path), split into context-safe batches against the configured budget,
analyzed independently, and consolidated hierarchically (merging partial
results in context-safe groups, repeating until one final Project Memory
remains) - identical regardless of provider. Every claim in the output
carries evidence_ids tracing back to the original Evidence Bundle. If
the model's output isn't valid JSON matching the schema even after a
retry, that batch/merge is never silently accepted or allowed to crash
the run - it's recorded as a warning and the evidence involved is
surfaced under "Unknown / Uncertain" instead. See
docs/IMPLEMENTATION_PLAN.md for the full bounded-context design.
A small local web UI for the same arch resume pipeline - useful for a
demo, or for anyone who'd rather click "Resume Project" than remember CLI
flags:
cd C:\Projects\Arch
.\.venv\Scripts\Activate.ps1
$env:DEEPSEEK_API_KEY="YOUR_REAL_KEY"
arch ui
Starts a local server (default http://127.0.0.1:5057/) and opens it in
your default browser. It is a thin presentation layer only: every action
in the UI calls the exact same run_resume_pipeline function arch resume calls (via arch/orchestration.py, shared by both) - nothing is
duplicated or re-implemented, and no new reconstruction logic exists for
the UI alone.
What it gives you, matching the CLI one-for-one:
- A project folder field, a prominent Resume Project button, and a
separate Refresh / Reanalyze button equivalent to
--refresh. The path is only kept in the browser for the current page session - it is not saved anywhere on disk. - Live status while a run is in progress (scanning, checking provider
availability, analyzing evidence, consolidating, rendering), including
a clear banner when a persisted Project Memory is being reused instead
of reconstructing (see "Persistence and
--refresh" above). - The full result: Recommended Next Step shown prominently, then Last Known/Current State, Completed, Open/Unfinished Work, Deferred Work, Important Decisions, Contradictions, and Unknown/Uncertain - sections with no content are simply not shown.
- Every claim keeps its evidence references. Clicking one reveals that evidence item's own already-collected content (its file/line or commit, and its text) inline - read-only, and only what Arch already gathered during scanning. There's no general evidence browser and no arbitrary filesystem access from the UI.
- A Settings panel to pick
deepseek(default) orollamaand, optionally, a model name. The DeepSeek API key is never entered, displayed, or stored by the UI - it's read only fromDEEPSEEK_API_KEYon the machine runningarch ui, exactly as every other Arch command already does.
arch ui binds to 127.0.0.1 (localhost) by default and is not exposed
on the network, since the repository evidence and reconstructed Project
Memory it displays can be sensitive. Pass --host/--port to change
that deliberately, or --no-open-browser to skip auto-opening a tab.
Deterministically scans a repository and writes a traceable Evidence Bundle - makes no LLM calls and performs no interpretation.
arch scan /path/to/some/repo
Writes evidence.json to <repo>/.arch/evidence.json by default
(--output/-o to relocate it). Each item is one of doc (a
project-state document with full content and path), marker (a single
TODO/FIXME/XXX/HACK/deferred-postponed occurrence with exact file/line),
or commit (hash, author, date, message, changed files).
Reconstructs Project Memory from an already-scanned Evidence Bundle, without also scanning or rendering a report:
arch scan /path/to/some/repo
arch reconstruct /path/to/some/repo
Requires evidence.json to already exist. Writes project_memory.json
to <repo>/.arch/project_memory.json by default (--output/-o and
--evidence-path to relocate the files). Accepts the same
provider/model/context/retry/timeout/debug options listed above (arch resume is the more commonly used entry point, since it also runs the
scan and renders the report in one step).
A small, deliberately messy demo git repository (PROJECT_SPEC.md §9) is available to exercise Arch end-to-end: completed work (persistence save/load), unfinished work (a restart-persistence bug), a deferred feature with a recorded architectural decision (the storyboard workspace), outdated documentation, a real contradiction (the README claims persistence is complete; a test and a FIXME say otherwise), and a deterministically failing test. Build it with:
python -m arch.demo.build_demo_repo /path/to/demo_repo
arch resume /path/to/demo_repo
Building it is deterministic and reproducible - the same command always
produces byte-identical files and commit hashes (fixed author/timestamps,
pinned git config) - and it's generated on demand wherever you point it,
so it never lives inside or gets scanned as part of Arch's own
repository. Pass --force to rebuild an existing, non-empty destination
from scratch.
pytest