# 🤖 AGENTS.md: todo-go-rastrillo

The one rule: **a visitor's list is reachable only through that
visitor's own cookie.** Every read and every write of a todo goes
through the `owned(r)` seam (`scope.Owned` on the session's subject), and
a todo that isn't in the caller's list doesn't exist: 404, never 403.

## Tenancy declaration (2026-10-23)

- **One instance for the whole app.** Carloku app `todo-go-rastrillo`,
  host `todo-go-rastrillo.bfj.oncarlos.com`, channel `edge`.
- **Each visitor's list is kept separately by an anonymous cookie.** The
  first request without a live session creates a `visitors` row and
  signs that browser in to it through Rastrillo's `sessions` (method
  `anonymous`): a 256-bit random token in an `HttpOnly; SameSite=Lax;
  Path=/` cookie, `Secure` and `__Host-` on https. Only the token's
  SHA-256 is stored. An unknown or garbled cookie gets a fresh, empty
  list.
- **No sign-in.** There are no accounts, no email, no passwords. Losing
  the cookie loses the list.
- **Trust class C.** Todo titles are stored as plain text in the SQLite
  file and the server can read them. That's chosen: it's a demo app
  holding to-do items, and it's written down here and in the README.

## Working rules

- The binding spec is the repo's `BRIEF.md` and `CONTRACT.md`. The UI is
  TodoMVC's markup and CSS, not Rastrillo's design system.
- Cross-site protection is the contract's Origin check (`origin.go`),
  not `csrf.Protect` alone: a POST with no `Origin` header is allowed.
- Migrations only add. Never edit a shipped file in
  `internal/todo/migrations/`; add a new one.
- `make test` before every commit; the shared suite before every deploy.
- Never bind anything other than `127.0.0.1` locally.
