diff --git a/CLAUDE.md b/CLAUDE.md index f944e0f..6e0a36f 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -1,8 +1,9 @@ # CLAUDE.md -This file orients Claude Code when working 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/`. +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 @@ -18,80 +19,125 @@ the MVCP (Model/View/Controller/Process) methodology from `docs/graphlemon_archi 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: for task ` / `graphlemon: auto-commit uncommitted changes for ` / `graphlemon: +merge ` 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 -1. Read `docs/development-plan.md` — Phase → Sub-phase → Unit breakdown (`docs/sdd/unit_matrix.json` - is the machine-readable mirror). Work is organized as Development Units, each classified - Value Path / Risk Gate / Enabler, each with explicit `depends_on` and a `done` criterion that - references a specific REQ in `docs/sdd/06-验收与测试锚点.md`. -2. The critical path starts at **U-001** (01-M schema) → U-002 → U-004 → ... Follow - `development-plan.md` §3 "关键路径" — do not skip ahead to later Units even if they look more - interesting; most have real `depends_on` edges. -3. **U-004 (A-2 assumption) is the next unvalidated risk on the critical path.** A-1 (dynamic - workflow programmatic invocation) was already spike-validated (`spikes/a1-dynamic-workflows/`, - confirmed 2026-07-29). A-2 (Hermes profile SOUL.md/AGENTS.md migrating cleanly into - `.claude/agents/*.md` without major rewrites) is not yet tested. Validate it early with a - minimal spike (per `development-plan.md`'s explicit recommendation) rather than discovering - problems after U-010/U-011 are fully built on top of it. +1. Read `docs/development-plan.md` for 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.json` is its machine-readable mirror (also static). +2. `docs/sdd/06-验收与测试锚点.md` has 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. +3. 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 -No build, lint, or test tooling exists yet — the repo is pre-scaffolding (PH0, no commits made -yet). `supervisor/isolation/` has no test suite of its own (that's U-036); `docs/` and `spikes/` -aren't packages. The one real executable entry point today: +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): ```bash -# A-1 spike: verify Claude Code dynamic workflows can be invoked headlessly (already validated, -# kept here for re-running / reference — see spikes/a1-dynamic-workflows/RESULTS.md) -./spikes/a1-dynamic-workflows/run-spike.sh /path/to/some/git/repo +# 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.: + +```bash +RUN_REAL_AGENT_E2E=1 python3 -m unittest src.test_agent_e2e ``` -Once U-002/U-003 scaffold `src/`, tests run via stdlib `unittest` only (see Testing below) — there -is no repo convention yet for a single-test invocation beyond the standard -`python3 -m unittest path.to.test_module.TestClass.test_method`; don't invent a different pattern. +`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. + +```bash +# 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 --permission-mode auto`, no `--bare`, no `--dangerously-skip-permissions`). See - 05 §5.3, §5.3.1, §5.4. + 05 §5.3, §5.3.1, §5.4. One documented gotcha: `--agent` + `--json-schema` together silently drop + `structured_output` — see 05 §5.4.1.1 and `src/work_graph_plan.py`'s ```` ```json ```` fence + 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 `unittest` only, no pytest/fixtures. Mock the `subprocess`/`claude -p` - boundary in normal tests; real end-to-end tests that actually shell out to `claude` should be - gated behind an explicit env var and skipped by default (mirror graphloop's - `RUN_REAL_AGENT_E2E=1` pattern) — this project doesn't have that harness yet, build it as part - of the relevant Unit rather than improvising a different pattern per test file. -- **Isolation**: parallel coding nodes must use `git_worktree_ref`. If `target_folder_path` is - graphlemon's own repo (self-hosting/self-modification, PH5 only), worktree is **unconditionally - mandatory** even for serial single-node changes — see 05 §5.8. + boundary in normal tests; real end-to-end tests that actually shell out to `claude` are gated + behind `RUN_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`). If + `target_folder_path` is 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//` + **inside** the main repo's working tree while a node runs (gitignored — never let `git add -A` + on `repo_path` pick one up mid-run). Before touching this code, read the three `U-013` incident + notes in `development-plan.md` (uncommitted worktree changes silently dropped on merge, `memory: + project` writes 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 1. **"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. -2. **"Deploy Supervisor"** — an independent OS process, entirely outside the Graph Engine, that - handles blue-green deployment and automatic rollback when graphlemon modifies its own code - (PH5 only). See `docs/supervisor-auto-rollback-design.md` for the full design and the - disambiguation note at the top of that file. +2. **"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's `hermes_watchdog.py`. See `docs/supervisor-auto-rollback-design.md` for 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. -## PH5 (Deploy Supervisor / self-hosting) is not in scope yet - -`docs/development-plan.md` PH5 (Units U-034~U-043) depends on PH4 closing first — self-modification -safety only makes sense once the base system has passed full regression. Don't build any of -U-034~U-043 before PH0-PH4 are done, even though the design (`docs/supervisor-auto-rollback-design.md`) -and its four reusable isolation modules (`supervisor/isolation/`) are already staged. Those modules -were adapted from graphloop and have had exactly one manual smoke test — they still need a real -`unittest` suite (U-036) before anyone should trust them in a real rollback path. - ## Prior art worth reading, not worth copying wholesale `/Users/yibo/Documents/lemonAI/graphloop` is an earlier, unmaintained attempt at this same @@ -104,20 +150,45 @@ worth reading for the "fail-closed, deterministic, never-auto-restart" supervisi (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/`). - -## Repo layout (as of PH0, before scaffolding exists) - -- `docs/` — architecture, SDD, development plan (see above) -- `docs/wireframes/` — static no-build HTML prototypes for the PH3 console views (`v_*.html`), referenced - per-page from `docs/sdd/02-V-界面与交互.md` §2.1-2.13 — implementation starting point once PH3 begins, - DOM/class names map 1:1 to that doc's field lists. -- `supervisor/isolation/` — staged utility library (isolate/diff/apply), not yet wired to anything -- `spikes/` — one-off validation spikes (currently just A-1) -- `src/` (created by U-001) — graphlemon's own backend source (schema, then U-007+ HTTP/WebSocket server). - **Not the same `src/` a target project already has in its own repo** — a target project's `src/` is - its own pre-existing source tree; graphlemon does not create or restructure it (see 05-实施约束与依赖.md - §5.7 and architecture doc §13.2 — U-002 only creates `.graphlemon/` inside a target project, corrected - 2026-07-31 after finding development-plan.md's U-002 line had cited the wrong architecture section). -- Everything else (`.claude/agents/`, `skills/`, `runs/`, per-target-project scaffolding) gets created by - U-002/U-003 — it doesn't exist yet, and that's expected at this stage. +(`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 from `docs/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's `deployment`/`deploy_health_signal`), `backend_server.py` (stdlib + `http.server` HTTP 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`), and `paths.py` + (graphlemon's own runtime home — `~/.graphlemon` by default, override via `GRAPHLEMON_HOME`, + deliberately outside this repo checkout so logs/db never enter this repo's own git history). + **This is not the same kind of `src/` a target project has in its own repo** — a target + project's own `src/` is its pre-existing source tree; graphlemon doesn't create or restructure + it (05 §5.7, architecture doc §13.2). Each `src/x.py` has a same-directory `src/test_x.py` (and + sometimes `src/test_x_e2e.py` for 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.py` is 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-permissions` self-invocation; Planner/Validator were + near-verbatim). These are the source-of-truth prose; `.claude/agents/*.md` is 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/*.md` frontmatter comment block records exactly what changed between them. +- `frontend/` — the PH3 console: static `index.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-agent `memory: project` files, tracked + in git on purpose (architecture doc §8 decision: memory must leave a git trail, not be silently + mutable local state). +- `.graphlemon/runs//` — 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.