Self-hosted Tangled spindle
spindle CLAUDE.md
3.0 kB · 46 lines
Markdown
at main

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). 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<n>: <imperative summary> (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.