# Spindle: agent conventions These rules apply to every coding agent in this repo (Claude Code, omp, Codex or any other). `AGENTS.md` points here. This repo holds our own Tangled spindle (CI runner) for the repos under `demi.dev`: a **mill** on Railway at `spindle.demi.dev` and a **nixery executor** on a NixOS VM on the owner's home server. See `README.md` and `docs/adr/0001-architecture.md`. ## Sources of truth, in order 1. `docs/adr/`: decisions. A change of direction needs a new ADR (copy `docs/adr/0000-template.md`) in the same PR. 2. `docs/runbook.md` (once it exists): how to operate the live systems. 3. The Linear issue you were given (project Spindle): scope, files to touch, acceptance criteria and Verify commands. The lead agent's process lives in the Linear document "Lead agent playbook — Spindle" (project Spindle). ## Workflow - **All changes reach `main` through Tangled pull requests** ([tangled.org/demi.dev/spindle](https://tangled.org/demi.dev/spindle)). Only the lead agent pushes, opens PRs and merges. - **Implementers never push.** Commit on your branch in your worktree and stop. Never open or comment on PRs, and never touch Linear, Tangled, GitHub, Railway, the executor VM or any deployed system. - Stay inside the issue's scope. List follow-ups in your report instead of doing them. Do not design for rare or future cases nobody asked about. - Match the surrounding code: naming, comment density, idiom. - **Commit style:** `S: (ENG-xx)`, for example `S0: Build the mill image (ENG-463)`. Keep format-only changes in their own commit. ## Pinned Tangled version Tangled `v1.20.0` (commit `2096d06d`) is pinned in two places: `mill/Dockerfile` and `executor/flake.nix` (with `executor/flake.lock`). Mill and executor must run the same version. Bump both in one PR, never one alone. ## mise is the single entry point Tools (hadolint, shellcheck) and tasks come from `mise.toml`. Docker must be running. - `mise run check` lints every Dockerfile and shell script, then runs `nix flake check` and the executor toplevel evaluation in a pinned `nixos/nix` container. Run it before every commit. - `mise run executor:lock` writes `executor/flake.lock` in the same container. Don't install Nix on the host. ## Hot files: one in-flight change per file `mise.toml`, `mill/Dockerfile`, `executor/flake.nix`, `executor/flake.lock`, `CLAUDE.md`, `README.md`. ## Secrets - No secret goes into git, ever: no keys, tokens, passwords or S3 credentials, not even fake-looking ones in examples. - Never print, log, comment or commit the spindle signing key, an executor token or the bucket's S3 credentials. - Live secrets come from outside the repo at runtime: - mill: Railway variables (`SPINDLE_SIGNING_KEY_PEM`, bucket references); - executor: files in `/var/lib/secrets/` on the VM, never in the Nix store. - Tests and smoke tasks generate throwaway keys in a temp dir and delete them afterwards. - If an issue needs a new secret, name it in your report. The lead sets it.