From 0290feccc1bae9bb0635c7f75d0e56cfea2c5cf2 Mon Sep 17 00:00:00 2001 From: Amr Gharbeia Date: Tue, 12 May 2026 20:13:32 -0400 Subject: [PATCH] memex: split AGENTS.md into monorepo overview and per-project workflow Move the development workflow details (TDD, REPL, literate programming, branch policy) from top-level AGENTS.md into projects/AGENTS.md. Top-level AGENTS.md now describes only the monorepo structure and project list. --- AGENTS.md | 86 ++-------------------- projects/AGENTS.md | 180 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 188 insertions(+), 78 deletions(-) create mode 100644 projects/AGENTS.md diff --git a/AGENTS.md b/AGENTS.md index da11b21..d7c1b3a 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -1,82 +1,12 @@ # AGENTS.md -## Development Cycle (every change) +This is the memex monorepo. It contains multiple Common Lisp projects, each +in `projects/`. See `projects/AGENTS.md` for the general development workflow +(ROADMAP-driven, TDD in REPL, literate programming, branch policy). -1. **Read the next TODO** — find the next unreached `*** TODO` item in - `docs/ROADMAP.org` (search `*** TODO`). Read its prose, `:PROPERTIES:`, - and estimated line budget. That item is the target for this change cycle. -2. **Think in org** — write your reasoning, goals, and approach in the .org file first -3. **Write contract** — define a `** Contract` section listing each function's behavior: - `(fn-name args)`: description. Returns/guarantees ... -4. **TDD from contract** — each contract item becomes a `fiveam:test` in `* Test Suite` - a. Write the test first → tangle → run → prove it FAILS (RED) - b. Write the implementation → tangle → run → prove it PASSES (GREEN) - c. Record both failure and success output -5. **Reflect in org** — once tests pass, ensure the implementation is in the .org source, put each function in a separate code block. -6. **Update literate prose** — write/update the explanatory text around the code: - what it does, why it exists, how it connects to the rest of the system -7. **Mark the origin TODO DONE** — in `docs/ROADMAP.org`, change the - `*** TODO` item to `*** DONE` and add a `:LOGBOOK:` entry with the - completion date: - #+begin_src org - :LOGBOOK: - - State "DONE" from "TODO" [YYYY-MM-DD Day] - :END: - #+end_src -8. **Commit** — only when asked. Ask first. +## Project list -## Commands - -Tangle a single file: - emacs --batch --eval "(progn (require 'org) (find-file \"org/FILE.org\") (org-babel-tangle) (kill-buffer))" - -Validate structural integrity: - emacs --batch -Q --eval '(progn (find-file "org/FILE.org") (check-parens) (kill-buffer))' - -Run tests: - sbcl --noinform \ - --eval '(load (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))' \ - --eval '(ql:quickload :passepartout :silent t)' \ - --eval '(load "lisp/FILE.lisp")' \ - --eval '(fiveam:run (intern "SUITE-NAME" :passepartout-TESTS))' --quit - -For error details: bind fiveam:*on-failure* to :debug - -## REPL (port 9105) — preferred when available - -Start: `passepartout daemon` -Send code: - msg = '(:type :event :payload (:sensor :repl-eval :code "(+ 1 2)"))' - s.sendall(f'{len(msg):06x}'.encode() + msg.encode()) - -When REPL is up: TDD in-image first, then reflect to .org and tangle. -When REPL is down: fall back to the SBCL cycle above. - -## Rules - -- .org is source of truth; .lisp is generated — never edit .lisp directly -- Every code change starts with a contract and a failing test -- Prove RED before writing implementation -- Validate before committing -- If a tool fails, explain why and ask before trying alternatives -- Before shipping a version, run the `** File Update Checklist` in `docs/ROADMAP.org` -- **YOU MAY NOT** push a version tag (e.g., `v0.5.0`), create a GitHub release, or run `git push` - that triggers CI/CD version workflows without explicit permission. Ask first. -- **YOU MAY NOT add files to `passepartout.asd` `:components` without asking for permission.** - ASDF `:components` is the core harness. Files there load on every daemon boot, - cannot be hot-reloaded, and a bug there kills the agent's brainstem. -- When you want to add a new module, **ask first**. Provide: - 1. Why it cannot be a skill (the self-repair criterion — can the agent fix it - if corrupted without human help?) Demonstrate specifically how a broken - version of this file prevents the agent from perceiving, reasoning, - or acting — not just degrading performance or losing a feature. - 2. What it depends on and what depends on it - 3. Why it cannot use `fboundp` guards from core -- **Default: everything is a skill.** Skills load via `skill-initialize-all`, - are hot-reloadable, self-repairable, and a bug in a skill degrades the agent - but doesn't kill it. The harness stays thin. -- **The self-repair criterion**: a file belongs in core only if, when corrupted, - the agent *cannot* fix it without human help. Corrupted core = dead brain, - dead hands, or unreachable. Corrupted skill = degraded but self-repairable. - This criterion is documented in `docs/ARCHITECTURE.org` and - `docs/DESIGN_DECISIONS.org`. +| Project | Description | Runtime | +|---------|-------------|---------| +| passepartout | Neurosymbolic agent | `passepartout daemon` | +| cl-tui | Reusable terminal UI framework | `sbcl` + `(ql:quickload :cl-tui)` | diff --git a/projects/AGENTS.md b/projects/AGENTS.md new file mode 100644 index 0000000..0983c21 --- /dev/null +++ b/projects/AGENTS.md @@ -0,0 +1,180 @@ +# AGENTS.md + +## Development Cycle (every change) + +0. **Start the runtime** — boot the Lisp image that loads your project. + For passepartout: `passepartout daemon` (loads the entire project into one SBCL image). + For standalone CL projects: SBCL with `(ql:quickload :your-project)`. + The running image IS the development environment. The REPL is mandatory. + The SBCL fallback below exists only for bootstrapping (when the runtime cannot + start) and CI. + +1. **Read the next TODO** — find the next unreached `*** TODO` item in + `docs/ROADMAP.org` (search `*** TODO`). Read its prose, `:PROPERTIES:`, + and estimated line budget. That item is the target for this change cycle. + +2. **Create a branch** — `git checkout -b feature/-` from main. + Every feature develops in its own branch. Branches are cheap, disposable, + and keep abandoned work off main. Name the branch after the version and + a short slug: `feature/v0.1.0-layout-engine`, `feature/v0.9.0-eval-harness`. + Complex features that span multiple phases may use a single branch with + multiple commits rather than one branch per phase. + +3. **Think in org** — write your reasoning, goals, and approach in the .org file first. + +4. **Write contract** — define a `** Contract` section listing each function's behavior: + `(fn-name args)`: description. Returns/guarantees ... + +5. **TDD in REPL** — the inner loop runs entirely in the running image: + + a. **Write tests in org** — add `fiveam:test` forms to the `* Test Suite` section + of the .org source file. Tests are definitions, not explorations — write them + in the file first. + + b. **Send tests to REPL → RED** — evaluate the test forms in the running image. + Run the suite. It must FAIL — the implementation doesn't exist yet. + Record the failure output in the .org file under the test. + + c. **Develop implementation in REPL** — redefine functions directly in the + running image. Explore. Discover the real argument shapes, edge cases, and + helper functions through interaction, not speculation. Each `defun` in the + REPL is immediate — no tangle, no reload, sub-second feedback. + + d. **Run tests → GREEN** — after each change, re-run the suite from the REPL. + When all tests pass, the implementation is complete. If still RED, return to + step c. Record the passing output in the .org file under the test. + + e. **Copy code to org** — copy each finished function from the REPL into its + own `#+begin_src lisp` block in the .org file. The code is already working; + the file is now its permanent home. One function per block. Never write a + function in a file that hasn't been proven in the image. + +6. **Update literate prose** — write/update the explanatory text around the code: + what it does, why it exists, how it connects to the rest of the system. + +7. **Tangle** — generate the .lisp file from the .org source: + ``` + emacs --batch --eval "(progn (require 'org) (find-file \"org/FILE.org\") (org-babel-tangle) (kill-buffer))" + ``` + Tangling is a finalization step, not part of the inner loop. The inner loop + (steps 5a–5e) happens entirely in the REPL. Tangle once, when the file is + ready to commit. + +8. **Run full test suite** — from the REPL, run every test suite in the project: + ``` + (fiveam:run-all-tests) + ``` + This catches regressions across the entire system. A function that passes its + own tests but breaks another module is not done. + +9. **Validate block balance** — check that every `#+begin_src lisp` block in the + modified .org files has balanced parentheses. Use your project's equivalent + function or the SBCL fallback below. + +10. **Commit on the branch** — include the RED and GREEN test output recorded + in the .org file as part of the commit message evidence: + ``` + git add org/ lisp/ docs/ + git commit -m "v0.9.0: eval harness — 10 tasks, regression detection + + RED: 0/10 pass (tasks not yet defined) + GREEN: 10/10 pass" + ``` + +11. **Mark the origin TODO DONE** — in `docs/ROADMAP.org`, change the + `*** TODO` item to `*** DONE` and add a `:LOGBOOK:` entry with the + completion date. This is a separate commit on the branch: + #+begin_src org + :LOGBOOK: + - State "DONE" from "TODO" [YYYY-MM-DD Day] + :END: + #+end_src + +12. **Merge to main** — the merge IS the release. Rebase onto main first + to keep history linear, then fast-forward merge: + ``` + git checkout main + git merge feature/v0.9.0-eval-harness + ``` + +13. **Bump the submodule** — if the project is a submodule in the parent + `memex` repo (e.g., passepartout), stage the submodule pointer and commit: + ``` + git add projects/passepartout + git commit -m "bump passepartout → v0.9.0" + ``` + Standalone projects skip this step. + +14. **Delete the branch** — `git branch -d feature/v0.9.0-eval-harness`. + Abandoned branches can be deleted before merge with no cleanup needed. + +## Branch Policy + +- Every feature starts on a branch from main. Branch names: `feature/-`. +- ROADMAP.org changes (DONE markers, LOGBOOK entries) happen on the branch, not + on main directly. They merge to main with the feature. +- If a feature fails or is abandoned, delete the branch. No revert commits, no + dead code on main, no `;; OBSOLETE` comments. Git history preserves the + experiment if you need to reference it later. +- Rebase onto main before merging. Keep history linear. No merge commits. +- Complex features that span multiple roadmap versions may live on one branch + with multiple commits, merging to main when the entire chain is stable. +- **Bug fixes, typos, docs-only edits, and single-session jobs do not get a + branch.** Commit them directly to main. The heuristic: if it can be finished + in one session and has no plausible alternative that could replace it, it + goes to main. If it spans sessions or might be abandoned for a better + approach, it gets a branch. + +## Commands + +Tangle a single file: + emacs --batch --eval "(progn (require 'org) (find-file \"org/FILE.org\") (org-babel-tangle) (kill-buffer))" + +Validate structural integrity (org/ source files only): + emacs --batch -Q --eval '(progn (find-file "org/FILE.org") (check-parens) (kill-buffer))' + +Run tests (from REPL): + (fiveam:run (intern "SUITE-NAME" :project-TESTS)) + (fiveam:run-all-tests) + +Run tests (SBCL fallback — only when the runtime cannot start): + sbcl --noinform \ + --eval '(load (merge-pathnames "quicklisp/setup.lisp" (user-homedir-pathname)))' \ + --eval '(ql:quickload :your-project :silent t)' \ + --eval '(load "lisp/FILE.lisp")' \ + --eval '(fiveam:run (intern "SUITE-NAME" :project-TESTS))' --quit + +For error details: bind fiveam:*on-failure* to :debug + +## REPL — mandatory + +All development happens in a running Lisp image. Start your runtime: +- Passepartout: `passepartout daemon` — boots the entire project, listens on port 9105 +- Standalone CL projects: `sbcl` with `(ql:quickload :your-project)` + +Send code from opencode using the `lisp` tool (any SBCL project) or the `repl` +tool (passepartout daemon on port 9105). The inner loop (step 5a–5e) never leaves +the REPL: + +1. Send test forms from .org to REPL → RED +2. Redefine functions in REPL → test → iterate +3. Send tests → GREEN +4. Copy working code back to .org + +Tangle only when the file is complete and ready to commit. Never batch-compile +outside the image when the runtime is available. Use the SBCL fallback above only +when the runtime itself cannot start. + +## Rules + +- .org is source of truth; .lisp is generated — never edit .lisp directly +- Every code change starts with a contract and a failing test +- Prove RED before writing implementation +- Implementation is developed in the REPL, then copied to .org — never write + code in a file that hasn't been proven in the image +- Validate before committing +- If a tool fails, explain why and ask before trying alternatives +- Before shipping a version, run the `** File Update Checklist` in `docs/ROADMAP.org` +- **YOU MAY NOT** push a version tag (e.g., `v0.5.0`), create a GitHub release, + or run `git push` that triggers CI/CD version workflows without explicit + permission. Ask first.