Files
rune/AGENTS.md

4.9 KiB

The contract (henxels)

Auto-generated from henxels.yaml by henxels sync. Do not edit by hand.

Each bullet is a henxel (a rule). To disobey one, change henxels.yaml — that is the only sanctioned escape. Run henxels explain <path> before creating a file to see what governs that spot.

Only use git commit --no-verify in a genuine emergency: it bypasses the hooks that run this contract, the safety mechanism meant to protect the repository. Prefer henxels bless <action> or editing henxels.yaml — both keep the deviation visible.

Rules

  • Canaries live at the repo's canary slot and are registered in CI (in ./src/rune/**/canary_*.py)
  • No secrets in tracked files
  • Plans are markdown, one per build (in ./plans)
  • Top-level docs are markdown or yaml references (in ./docs/*)
  • The known giant stays visible — file-size debt is tracked, not silent (in ./src/rune/*)
  • The umbrella impact map is complete and truthful — every module mapped, no phantom entries (in ./config/umbrellas.json)
  • Umbrella canaries exist in the repo — the propagation gate cannot reference ghosts (in ./config/umbrellas.json)
  • The umbrella dependency graph stays a DAG — reflexive updates cannot cycle (in ./config/umbrellas.json)
  • The bug-fix discharge contract is a governed doc — it exists, is markdown, and changes are deliberate (in ./docs/bugfix-contract.md)
  • The discharge checker ships with the repo — red-first enforcement is structural (in ./scripts)
  • Discharge checker and its CI wiring change together
  • Every workflow is registered in the pipeline registry — new pipeline machinery ships with documentation (in ./.gitea/workflows/*.yml)
  • Every TUI surface is registered — no silent UI growth (in ./src/rune/tui.py)
  • New rune modules ship with tests or a canary — no ungoverned code surfaces (in ./src/rune/*.py)
  • PRDs are living documents — their generated state sections regenerate identically from governed sources
  • PRD staleness is a CI failure — docs rot is silent failure (in ./scripts/gen_prd_state.py)
  • The adversarial review procedure is binding — dispatch templates must reference it (in ./docs/adversarial-review.md)
  • The fixture pipeline ships with the repo — production failure capture is structural (in ./scripts)
  • Production failure fixtures are a governed surface — the registry and its README exist (in ./tests/fixtures/production)
  • Fixture payloads and the manifest travel together — tamper-evidence needs both
  • The fixture manifest and its generated regression tests travel together

Behaviours

  • warns when a new file looks like a near-copy of a committed one

Custom henxels & contributing

Before writing a custom check, run henxels catalogue and use the built-in that matches your intent — don't reinvent one. Never name a custom check after a built-in or a setting (e.g. warn_about_large_files is a setting, not a check).

Need a check that genuinely doesn't exist? henxels create-new-statement <name> scaffolds a local check (auto-loaded from henxels_checks.py). If your check is reusable — useful in other repos, not tied to this one — contribute it upstream with henxels contribute. We're in the agentic era: send a ready-to-merge PR instead of opening an issue.

Bug fixes (binding)

Every bug found — by gates, CI, canaries, production, or humans — is fixed per docs/bugfix-contract.md: red test FIRST (reproduces the cause), root-cause fix, full pipeline re-entry (suite + ratchet + ruff + canaries + henxels; gates for anything beyond a mechanical minor), regression tests frozen forever, discharge recorded finding → test → commit. Symptom patches are rejected at review. To escape: edit henxels.yaml or this file — visibly.

Issue organisation standard (binding, 2026-09-19)

One open note per idea. Issues use the template spine (kind, subsystem, version intent) with a plain-English heading that restates the subject — no meta-labels. Before minting a standalone issue, check whether the work belongs inside an existing parent:

  • Parked ideas under a blocked/future epic are filed as checklist items in the parent's "Absorbed children" section, NOT as standalone issues. Absorption is reversible — re-mint standalone when the idea becomes live.
  • Live, dependency-tracked, or starting work gets a standalone issue.
  • Closures state the reason as data: closed_because in the spine (completed / superseded-by-#N / absorbed-into-#N / wont-do / duplicate), plus a standard closing comment (plain summary first).
  • The reconciliation checker (scripts/gitea_reconciliation_check.py) must stay green after any issue state change; the artifact is updated in the same change that moves issues.

Async continuation final flow proofs (R13/M9) — 2026-09-19

PR-flow live proof marker: harmless documentation addition exercising the canonical single-continuation path on the PC-local forge. No code change.