# Pick-up protocol

This file governs how an agent works in this project. Read it once per session.

## The default mode: do what you were asked

**The default mode of all work is: do what the human's prompt says.** If Kris asks for a specific task, epic, or fix, that is the scope of the session — full stop. An agent does not decompose other epics it wasn't asked about, does not generate tasks or questions for things nobody raised, and does not "proceed" past the ask to whatever it personally judges should happen next. If the prompt names an epic and asks for something specific in it, do that thing. If it's genuinely just "pick up epic X" with no further detail, do the smallest, most literal thing that phrase can mean — check the epic's `overview.md` and any existing `tasks/`, and either continue an existing ready task or ask Kris what he actually wants next. **Do not treat "pick up X" as an invitation to decompose X into a pile of new tasks and questions.** That already happened once, produced mostly noise, and got deleted — see `notebook/` or the git history around 2026-08-05 if you want the full story.

This is a change from an earlier version of this file, which had the model backwards: full autonomous decomposition as the default, "raise a question" as the safe fallback. Both directions turned out to generate work Kris didn't ask for and then had to spend attention clearing away. See "Future: autonomous pick-up" at the bottom for where that's meant to go eventually — it isn't now.

## When you do have a task to execute

1. **`git pull` first.** Since 2026-09-03 the board and the game are one repo (`land-of-lor`, this folder is its `workshop/`), so that is one pull — but sessions run from more than one place (laptop, task-runner container, phone-driven voice sessions), and the board on disk may be stale. Never claim or start a task off an unpulled tree.
2. Read the epic's `overview.md` in full, and its `status.md`.
3. If there's a specific `tasks/*.md` file you were pointed at or that matches the ask, read it and do the work it describes, in the sub-repo named in `overview.md`'s `repo:` field.
4. **When you hit a real ambiguity: assume, state the assumption, build, report.** Do not stop to ask. Pick the most reasonable default, write it down plainly (in the task file, or in your session report if there's no task file), and keep going. A wrong assumption in a throwaway prototype is cheap to find and fix later; a question sitting in Kris's inbox costs him attention *now*, whether or not it ever mattered. Optimize for his time, not for covering yourself.
5. **Claim before you work, and push the claim.** Set the task's `state: doing`, `claimed_by` (the task-runner task id, or a short session identifier if not running under the task runner), and `claimed_at` (an ISO timestamp) — then **commit and push that claim immediately, before starting the actual work**. An unpushed claim guards nothing: another agent pulling from elsewhere sees an unclaimed task and will happily duplicate or conflict with yours. The pull in step 1 and the pushed claim here are two halves of the same lock. A claim older than 6 hours is stale and may be taken over.
6. At the end of the session, regenerate the epic's `status.md` (recompute task-state counts, current open-question list if any, `next`, **and `tag`**) and report what you actually did, including a plain **Assumptions** list of anything you decided rather than were told. **`tag` is derived, never hand-picked** — apply this precedence, first match wins: `parked: true` → `parked`; else any task in `review` → `needs-review`; else any open question → `needs-human-decision`; else any task `ready` → `agent-ready`; else every task `done` (and at least one exists) → `done`; else → `blocked`. When you set a task to `review`, also set its `review_artifact:` to the repo path of the thing Kris should read (handoff note, doc) — it's what the site's `/now` page shows him. Full rule and rationale in `epics/README.md`. Get this wrong and the build doesn't just mis-tag the epic — `validate-epics.mjs` rejects a null or invalid tag outright and **silently kills the entire site build**, taking every other epic's page down with it, not just this one's.
7. **Commit and push, both, by default** — see the workspace `CLAUDE.md`'s "Conventions" section for why (the site's deploy watcher only ever sees `origin/master`; unpushed work is invisible work). Don't stop at a local commit unless the work is explicitly draft/WIP or you were told not to push.
8. **After pushing any change to `epics/`, `questions/`, `tasks/`, status files, or `deliverables/`, verify the public site actually picked it up — a push is not the finish line.** The site (spellgrove.com) is built on the game droplet: a systemd timer there (`lor-site-build.timer`, every 2 minutes) fetches `origin/master` of this repo, and when it has moved, pulls and runs `npm run build` in `site/` into the folder Caddy serves. You don't trigger it by hand. But the rebuild can fail silently (most often `validate-epics.mjs` rejecting a bad `status.md` tag), so always check from *outside* the repo, not by trusting the push:
   ```bash
   # give the timer ~2 min after your push, then:
   ssh -i .secrets/lor_runner_key lor@209.38.29.22 tail -20 /opt/lor/site-build.log   # want "build OK" after your commit's time, not "BUILD FAILED"
   curl -s https://spellgrove.com/epics/<the-epic>/ | grep -o 'data-tag="[a-z-]*"'   # matches status.md's tag now?
   ```
   If the log shows `BUILD FAILED`, read the error (usually names the exact `status.md` field), fix it, and push again. Running `cd site && npm run build` locally before pushing catches the same thing earlier. Root cause and history of why this step exists: `workshop/README.md`'s "Deployment" section, 2026-08-02 entry.

## Working alongside other agents

Sessions run concurrently from more than one place — laptop, task-runner container, phone-driven voice sessions — and often on the same repos at the same time. Steps 1 and 5 above (pull first; push the claim *before* you work) are the two halves of the lock, but they only cover work that's on the board. Three things they don't cover:

- **Not all concurrent work is on the board.** Kris runs sessions himself that never claim a task, and he may say so only in passing ("something else is tweaking the game right now — don't touch it"). If you find changes in the tree you didn't make, or a sub-repo moving under you, read that as another agent's live work, not as stale junk to tidy up. Don't revert it, don't reformat it, don't "fix" it. If it genuinely conflicts with your task, say so and stop rather than resolving it unilaterally.
- **Pull again immediately before you push.** Step 7 says commit and push; it doesn't say what to do when the remote has moved since step 1, which on a busy day it will have. `git pull --rebase`, re-check that your change still makes sense on top of theirs, then push. **Never force-push** — a rejected push is information, not an obstacle.
- **A claim locks a task, not a directory.** Two agents can hold different tasks that touch the same files. Stay inside the files your task actually needs, and don't opportunistically clean up neighbouring ones — that's how two sessions clobber each other while both believing they were correctly claimed.

## The question bar

An agent may raise a question — a real, tracked `questions/NNN-slug.md` file, or even just a flagged item in a session report — **only if the matter genuinely meets at least one of these:**

- **It costs money.**
- **It is irreversible.**
- **It is public-facing.**
- **It reaches outside the repo** (an external account, a third-party service, a legal/trademark filing, anything Kris alone can act on).

**Everything else fails the bar. Assume and proceed.** This is a high bar on purpose — "I wasn't 100% sure" or "this seems like a design decision" do not qualify by themselves. If a design choice doesn't cost money, can be changed later, stays inside the repo, and isn't shipped anywhere public, make the call, note it as an assumption, and move on.

**Hard cap: at most one question raised per session, and only when the bar is genuinely met.** If you find yourself wanting to raise more than one, that's a strong signal the task was too loosely scoped for a single session — stop and say so, rather than generating a list.

## Deliverable gating — `delivers:` blocks `done`

A task file can carry a `delivers:` list pointing at one or more `deliverables/NNN-*.md` files (full schema: `epics/README.md`'s "Promised deliverables" section). **A task with a `delivers:` line cannot move to `done` — even on Kris's sign-off — until every deliverable it names has `status: delivered` with its live artifact link in place.** This extends the existing review→done gate; it isn't separate machinery, just an additional condition on the same gate. If you're closing out a task and it carries `delivers:`, check the named deliverable(s) before setting `state: done` — if any is still `promised`, the task stays in `review` regardless of what else is finished.

## Decision records — never reversed silently

**Never silently reverse a decision that's already been made** — anything a question graduated into (`decision_ref`), or, once `decisions/` exists (see `context-and-docs-architecture`), a numbered decision record. If new information genuinely contradicts a settled decision, say so explicitly and let Kris decide whether to revisit it — don't quietly build around the old decision or edit its record.

## Future: autonomous pick-up

The original vision for this project's tooling was a single line — *"pick up epic X and proceed"* — with an agent free to decompose, generate tasks and questions, and self-direct from there. That's a real destination, not an abandoned idea. But it's a *destination*, to be grown into deliberately as trust is earned through smaller, explicitly-scoped work going well — not the default mode today. It became the default too early once, produced a board full of premature questions nobody asked for, and got rolled back on 2026-08-05. When it's time to move toward it again, that should be its own explicit decision, not a quiet drift back to old habits.
