191 lines
8.2 KiB
Markdown
191 lines
8.2 KiB
Markdown
---
|
||
type: methodology
|
||
title: AGENTS.md — Development Cycle
|
||
created: 2026-05-11
|
||
tags:
|
||
- methodology
|
||
- common-lisp
|
||
- development-workflow
|
||
---
|
||
|
||
# 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/<version>-<name>` 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" [2026-05-10 Sat]
|
||
: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/<version>-<slug>`.
|
||
- 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.
|