CLAUDE.md
This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.
Read this first, then follow the pointers below — do not start writing code before reading
docs/development-plan.md and the current Unit's coverage references in docs/sdd/.
What this is
graphlemon is a Level 5 autonomous "lights-out software factory": a two-layer Organizer Agent
architecture (Org Graph = fixed Planner→Coder→Validator; Work Graph = dynamic per-task execution
graph) that drives real software development end-to-end, backed entirely by Claude Code ACP
(claude -p non-interactive calls) — there is no Hermes CLI execution backend in this project
(decision, 2026-07-29, see docs/sdd/05-实施约束与依赖.md §5.3).
The authoritative spec is docs/sdd/ (00-06 + docs/sdd/sdd-mvcp-contract.json), generated via
the MVCP (Model/View/Controller/Process) methodology from docs/graphlemon_architecture.md.
Do not treat graphlemon_architecture.md as the spec to implement against — it's the PRD-
equivalent input that produced the SDD. When they conflict, the SDD wins (it's newer and more
detailed); if a conflict looks unresolved, stop and ask rather than picking one silently.
Status: all 43 planned Units (U-001~U-043, PH0~PH5) are implemented and committed
docs/development-plan.md and docs/sdd/unit_matrix.json describe the plan as it read at
inception (2026-07-29) — they were not kept updated with "done" checkmarks as work landed, so
don't treat their prose as a live status board. git log --oneline is the actual record: every
Unit from U-001 through U-043 has a matching commit, plus many U-0XX fix:/U-0XX follow-up:
commits for bugs found during real (not mocked) runs, plus a long tail of graphlemon: <artifact
type> for task <uuid> / graphlemon: auto-commit uncommitted changes for <id> / graphlemon:
merge <id> commits — those are graphlemon actually self-hosting: running its own
Planner→Coder→Validator loop against its own repo (target_folder_path == this checkout,
src/paths.is_self_target()), with the Deploy Supervisor (supervisor/) staging, health-checking,
and cutting over its own code changes. PH5 (self-modification / auto-rollback) is real and running,
not future work — see "Two things named Supervisor" below and supervisor/self_hosting_e2e.py.
When a development-plan.md line and the actual code disagree about what's done, trust the code
and git log, and — if it matters to the task at hand — flag the doc as stale rather than
silently trusting either source. development-plan.md's per-Unit "实现补充"/"真实 bug" notes
(inline, added after-the-fact) are still valuable: they're a real incident log of bugs found
during self-hosting runs and how they were fixed (e.g. worktree commits being silently dropped,
memory: project writes landing on the wrong checkout) — read them before touching
supervisor/isolation/, src/work_node_run.py, or anything worktree-related.
Where to start
- Read
docs/development-plan.mdfor the Phase → Sub-phase → Unit breakdown and the design rationale behind each piece — but see Status above before trusting any "done"/"depends_on" framing as current.docs/sdd/unit_matrix.jsonis its machine-readable mirror (also static). docs/sdd/06-验收与测试锚点.mdhas REQ-01 through REQ-15, the acceptance anchors every Unit's Done criterion cites. REQ-15 (PH5, Deploy Supervisor blue-green + auto-rollback) was added 2026-07-30 after the original REQ-01~14 set.- For any specific behavior, prefer reading the actual module in
src//supervisor//agents/over the plan doc — the plan doc records intent at write-time and known deviations, the code is truth.
Commands
Two independent unittest discover roots — there is no single top-level discover that covers
both (deliberately: supervisor/ was added later as PH5 landed, see
development-plan.md's U-036 note):
# graphlemon's own backend/schema/agent-orchestration code (441 tests as of U-043)
python3 -m unittest discover -s src
# Deploy Supervisor + the isolate/diff/apply library it depends on
# (this also picks up supervisor/isolation/test_*.py — no separate invocation needed)
python3 -m unittest discover -s supervisor -p "test_*.py"
# single test
python3 -m unittest src.test_work_graph_execute.SomeTestClass.test_method
Both suites skip real-claude-subprocess tests by default (skip_unless_env, src/test_support.py)
— those need RUN_REAL_AGENT_E2E=1 and real API spend, e.g.:
RUN_REAL_AGENT_E2E=1 python3 -m unittest src.test_agent_e2e
supervisor/self_hosting_e2e.py's own real end-to-end scenario (run_self_hosting_closed_loop,
the literal 9-step self-development-feasibility.md walkthrough) is gated the same way in
supervisor/test_self_hosting_e2e.py — do not invoke it casually; it does a real self-targeted
Planner→Coder→Validator→stage→cutover→monitor run against this repo.
No build step, no lint config, no package manager — pure stdlib Python, nothing to install.
# A-1 spike (already validated 2026-07-29, kept for reference/re-running)
./spikes/a1-dynamic-workflows/run-spike.sh /path/to/some/git/repo
# local console (U-007/U-008): backend serves the API, frontend is static no-build HTML/JS
python3 -m src.backend_server --port 8000 # default --port 0 means OS-assigned (fine for tests, not for browsing)
Hard constraints (do not relitigate these — they're settled decisions)
- Execution backend: Claude Code ACP only (
claude -p ... --output-format json --json-schema <schema> --permission-mode auto, no--bare, no--dangerously-skip-permissions). See 05 §5.3, §5.3.1, §5.4. One documented gotcha:--agent+--json-schematogether silently dropstructured_output— see 05 §5.4.1.1 andsrc/work_graph_plan.py's```jsonfence parsing workaround. - Implementation language: graphlemon's own backend/frontend/Deploy Supervisor are pure stdlib Python — no Flask/FastAPI/Express/Node.js, no npm build step. This mirrors the predecessor project graphloop's convention. See 05 §5.7. (This constraint is on graphlemon's own implementation only — it does NOT apply to the code graphlemon generates for target projects, which follows whatever stack that target project uses.)
- Testing: stdlib
unittestonly, no pytest/fixtures. Mock thesubprocess/claude -pboundary in normal tests; real end-to-end tests that actually shell out toclaudeare gated behindRUN_REAL_AGENT_E2E=1(src/test_support.py:skip_unless_env, mirrors graphloop's precedent) — reuse that helper, don't invent a per-file variant. - Isolation: parallel coding nodes must use
git_worktree_ref(src/work_node_run.py). Iftarget_folder_pathis graphlemon's own repo (self-hosting/self-modification), worktree is unconditionally mandatory even for serial single-node changes — see 05 §5.8,src/paths.is_self_target(). Worktree checkouts live at.graphlemon-worktrees/<node_exec_id>/inside the main repo's working tree while a node runs (gitignored — never letgit add -Aonrepo_pathpick one up mid-run). Before touching this code, read the threeU-013incident notes indevelopment-plan.md(uncommitted worktree changes silently dropped on merge,memory: projectwrites landing on the main checkout instead of the worktree, and the pathspec-vs-gitignore conflict that fixing the second one introduced) —work_node_run.ensure_worktree_committed()is the fix for all three; don't re-solve the same problem a fourth way.
Two things named "Supervisor" — do not confuse them
- "Supervisor(调度子 Agent)" — an in-process monitoring node inside the Coder Work Graph (architecture doc, existing concept). Watches Work Node execution, triggers reflection/ rescheduling. Part of the Graph Engine itself.
- "Deploy Supervisor" (
supervisor/) — an independent OS process (python3 -m supervisor.deploy_supervisor), entirely outside the Graph Engine, that handles blue-green deployment and automatic rollback when graphlemon modifies its own code. Fully implemented (U-034~U-043):deploy_stage.py(stage a candidate),deploy_health_check.py(poll for startup readiness, not one-shot — see U-038 fix),deploy_cutover.py,deploy_monitor.py,deploy_rollback.py. Fail-closed, never-auto-restart philosophy adapted (not imported) from graphloop'shermes_watchdog.py. Seedocs/supervisor-auto-rollback-design.mdfor the full design and the disambiguation note at the top of that file.
These are unrelated components that happen to share a root word in casual English. Identifiers
for #2 are always prefixed c_deploy_supervisor_* / deploy_health_signal — never abbreviate to
just "supervisor" in code or docs.
Prior art worth reading, not worth copying wholesale
/Users/yibo/Documents/lemonAI/graphloop is an earlier, unmaintained attempt at this same
architecture — substantially implemented (two-layer graph, isolated workspace, change manifest,
selective apply, fan-in/fan-out, real Claude-based Planner/Worker/Reviewer agents) but its own
Phase 10 self-evolution attempt stalled with concrete documented failures (a worker writing files
outside its isolated workspace, a 300s timeout, a stale-PID recovery incident). Its CLAUDE.md is
worth reading for architecture patterns; its hermes_watchdog.py/phase10_controller.py are
worth reading for the "fail-closed, deterministic, never-auto-restart" supervision philosophy
(graphlemon's Deploy Supervisor deliberately extends this into auto-rollback rather than just
auto-halt — see docs/supervisor-design-comparison.md for why). Do not import graphloop code
directly; anything worth reusing has already been copied and adapted into this repo
(supervisor/isolation/, adapted verbatim per the U-036 note in development-plan.md).
Repo layout
docs/— architecture doc, SDD (docs/sdd/), development plan, self-hosting design docs. See Status above for how stale the plan/unit-matrix "done" framing is relative to the real code.docs/wireframes/— static no-build HTML prototypes for the PH3 console views (v_*.html), referenced per-page fromdocs/sdd/02-V-界面与交互.md§2.1-2.13; DOM/class names map 1:1 to that doc's field lists.src/— graphlemon's own backend:schema.py(17-table SQLite schema — the original 01-M 15 entities plus PH5'sdeployment/deploy_health_signal),backend_server.py(stdlibhttp.serverHTTP API + WebSocket-ish log/event streaming, no third-party deps), the Org Graph layer (org_node_trigger.py,org_node_lifecycle.py,org_loop_route.py,org_level_loop.py), the Work Graph layer (work_graph_plan.py,work_graph_execute.py,work_graph_orchestrate.py,work_node_run.py), root-cause tracing (root_cause_trace.py), skills (skill_update.py,skill_query.py), budget/scheduling (budget_guardrail.py,scheduler.py), andpaths.py(graphlemon's own runtime home —~/.graphlemonby default, override viaGRAPHLEMON_HOME, deliberately outside this repo checkout so logs/db never enter this repo's own git history). This is not the same kind ofsrc/a target project has in its own repo — a target project's ownsrc/is its pre-existing source tree; graphlemon doesn't create or restructure it (05 §5.7, architecture doc §13.2). Eachsrc/x.pyhas a same-directorysrc/test_x.py(and sometimessrc/test_x_e2e.pyfor the gated real-agent variant) — that pairing is the repo convention, keep it when adding modules.supervisor/— Deploy Supervisor process + its isolation library (supervisor/isolation/:isolated_workspace.py,change_manifest.py,selective_apply.py,workspace_security.py, adapted from graphloop).supervisor/self_hosting_e2e.pyis the acceptance-scenario glue that wires Graph Engine scheduling + Deploy Supervisor into one real self-targeted run.agents/{coder,planner,validator}/SOUL.md— original Hermes-profile identity docs, migrated 2026-07-31 (A-2 assumption, "部分成立" — Coder's needed real rewriting to drop a hardcoded Feishu API token and a--dangerously-skip-permissionsself-invocation; Planner/Validator were near-verbatim). These are the source-of-truth prose;.claude/agents/*.mdis the actual Claude-Code-discoverable wrapper (frontmatter:skills:/memory: project/tools:/model:) that Claude Code loads — if you change agent behavior, both need to move together, and the.claude/agents/*.mdfrontmatter comment block records exactly what changed between them.frontend/— the PH3 console: staticindex.html/app.js/style.css, no build step, no npm.spikes/— one-off validation spikes (a1-dynamic-workflows/, confirmed 2026-07-29)..claude/agent-memory/{coder,planner,validator}/— per-agentmemory: projectfiles, tracked in git on purpose (architecture doc §8 decision: memory must leave a git trail, not be silently mutable local state)..graphlemon/runs/<task_id>/— real Artifacts (brd/prd/sdd/benchmark/code_diff/test_report) from actual self-hosting runs against this repo..graphlemon-worktrees/(gitignored, see Isolation above) is the transient per-node worktree checkout directory, not persistent state.