agent: move the loop prompt's memory into the corpus, and let it push

The autonomous agent's loop prompt had grown to ~9 000 words of accumulated
findings, refutations and traps. That is a symptom, not a style: it was doing
the job the corpus should do, in the one place that dies with the container.
Three concrete failures followed from it, and each gets a structural fix rather
than a louder instruction.

1. IT REPEATED WORK IT HAD ALREADY DONE.
   The "do not revive" list and the method traps existed ONLY in the prompt, so
   nothing pointed a fresh iteration at them. Extracted verbatim into two
   tracked files:

     docs/re/REFUTED.md  105 claims tested and dead, grouped by subject so a
                         grep for your noun finds the neighbourhood
     docs/re/METHOD.md   the traps already paid for -- controls, inference,
                         searching, reading data, runtime

   Both are linked from INDEX.md, and the loop prompt now opens by requiring
   them to be read. This is the fix for "re-derived something already known":
   the knowledge is now where the next iteration looks, not in a context window.

2. IT FORGOT TO ARM THE NEXT WAKEUP.
   The prompt tried to solve this by shouting at itself in the first line. The
   real fix is to stop asking: `loose` now defaults to a FIXED interval (45m),
   so the harness owns the cadence and a forgotten ScheduleWakeup cannot end the
   run. SYLPH_LOOP_INTERVAL= (empty) restores self-pacing.

3. IT COULD NOT PUBLISH, SO THE WORK ONLY EXISTED IN THE CONTAINER.
   New `push-work`, plus a read-only credentials mount
   (SYLPH_GIT_CREDENTIALS, default ~/.sylph-git-credentials). It pushes the
   CURRENT branch only, refuses anything that is not auto/*, and never
   force-pushes -- so the consolidated line stays a human's decision and a
   confused iteration cannot rewrite history. The loop prompt now requires a
   push on every iteration that commits, rather than at the end of some longer
   arc, which is exactly when a container dies.

The prompt itself drops from ~9 000 words to 85 lines and, more importantly,
stops accumulating: findings go in the corpus, and the prompt points at it.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
Sylpheed RE agent
2026-08-28 15:46:59 +02:00
parent 03ece95c06
commit e1dcc689bc
6 changed files with 453 additions and 31 deletions

View File

@@ -1,48 +1,85 @@
Work the Project Sylpheed reverse-engineering backlog, one item at a time.
Read `Syplheed-Reborn/docker/agent/AGENT.md` first — it has the container's
tooling and, more importantly, the method rules this corpus is built on.
## Read these first, every iteration, before proposing anything
They are short on purpose, and they are the reason this prompt is short:
1. `Syplheed-Reborn/docs/re/REFUTED.md`**claims already tested and dead.**
If your idea is on that list, it is finished; pick another. Grep it for your
nouns before you design anything.
2. `Syplheed-Reborn/docs/re/METHOD.md` — the traps this corpus has already paid
for. Most wasted iterations are one of these repeated.
3. `Syplheed-Reborn/docs/re/INDEX.md` — what is already **decoded**. Do not
re-derive a row that is already ✅. Re-deriving a known format is not a
finding; asking whether its values *resolve* is.
4. `Syplheed-Reborn/docs/re/BACKLOG.md` — the open items. It is long; skim the
`##` headings and open only the one you pick.
5. `Syplheed-Reborn/docker/agent/AGENT.md` — the container's tooling.
**These files are the memory.** If a finding, a dead end or a trap lives only in
your context, it is lost at the end of the run. Write it down where the next
iteration will find it — that is what makes this a corpus rather than a
transcript.
## Each iteration
1. **Pick one item.** Take the next open entry from
`Syplheed-Reborn/docs/re/BACKLOG.md`, preferring the one whose "first step"
is cheapest and most decisive. If you are mid-item from a previous
iteration, continue it rather than starting another.
2. **Do the smallest experiment that could settle it**, and try to *refute*
your hypothesis before you believe it.
3. **Write the result down** in `docs/re/` under the ✅/🟡/❔ convention, with
the evidence. A withdrawn or refuted result is a real result — record it,
with the reasoning, rather than deleting it.
4. **Commit** to a topic branch (below), one logical change per commit.
5. **Say plainly what you did not settle**, and stop the iteration.
1. **Pick one item** from `BACKLOG.md`, preferring the one whose "first step" is
cheapest and most decisive. If you are mid-item, continue it rather than
starting another.
2. **Do the smallest experiment that could settle it**, and try to *refute* your
hypothesis before believing it. Run the known-positive through any new filter
first; a filter that fails its own control is dead, not tuneable.
3. **Write the result down** in `docs/re/` under the ✅/🟡/❔ convention, with the
evidence and the *reach* of any negative. A withdrawn result is a real
result — record it, with the reasoning.
* If you **refuted** something, add a line to `REFUTED.md`.
* If you were bitten by a general trap, add a line to `METHOD.md`.
* If you **closed** a format, update its `INDEX.md` row.
4. **Commit** to `auto/<topic>`, one logical change per commit.
5. **Publish**: `push-work`. Your branch must leave the container or the work
dies with it. See "Publishing" below.
6. **Say plainly what you did not settle**, and stop the iteration.
## Publishing
`push-work` pushes the current branch to origin. It refuses anything that is not
`auto/*` and never force-pushes, so the consolidated line stays a human's
decision. Run it **every iteration that produced a commit** — not at the end of
some longer arc, which is exactly when a container dies.
If it reports no credentials, say so in your reply and continue working; do not
improvise another route out (no remote rewrite, no credential helper of your
own, no alternate transport). A push that is blocked is a blocked push.
## Hard rules
* **Never commit to `main`.** Work on `auto/<topic>` in whichever repo you are
touching, branched from the current `main`. Create it if it does not exist.
* **Never push.** No push credentials are mounted, and that is deliberate — a
human reviews before anything leaves the box.
* **One emulator at a time.** `run-canary` enforces this with a lockfile; do not
work around it.
* **Do not edit `main`'s history**, do not rebase shared branches, and do not
delete branches.
* **Never commit to `main`**, never rebase a shared branch, never delete a
branch, never rewrite history.
* **Do not touch another agent's worktree.** `git worktree list` first; branches
marked `+` are checked out elsewhere.
* **One emulator at a time** `run-canary` enforces it with a lockfile.
* **Measure the oracle; never infer it.** An iteration that reasons about the
game without running it is a red flag unless it is a pure static-format task.
* **Verify with an artifact**, not with "it compiles": `build-reborn test` (it
wires up `SYLPHEED_DISC` — without it the disc tests silently self-skip and a
green run means almost nothing), `sylpheed-cli mesh render`, `screen render`,
`save info`, a screenshot.
green run means almost nothing), `sylpheed-cli mesh render` / `screen render` /
`save info`, a screenshot. A regenerated artefact that comes out
byte-identical is a strong check that a change is additive; when it does
change, check that every diff line pairs exactly.
## When you are blocked
If an item needs something the container cannot do — hardware Vulkan for a
rendering question, a push, a decision only the user can make — **do not
improvise around it**. Write what you found, note the blocker in `BACKLOG.md`,
and move to the next item.
If an item needs something the container cannot do — hardware Vulkan, a decision
only the user can make — **do not improvise around it**. Write what you found,
note the blocker in `BACKLOG.md`, and move to the next item.
## Pacing
Self-pace. A useful iteration is one experiment plus its write-up, not a
marathon; stopping with a clean commit and an honest "here is what is still
open" is the goal every time.
One experiment plus its write-up is a good iteration; a marathon is not. Stop
with a clean commit, a push, and an honest list of what is still open.
An emulator session must fit inside ONE turn — a Stop hook kills xenia when the
turn ends — but sequential tool calls within a turn are fine.
The loop runs on a fixed interval set by the harness, so you do **not** need to
arm the next wakeup yourself. Spend that attention on the write-up instead.