add ~/.claude/CLAUDE.md as a managed dotfile
Global Claude Code preferences (symlinked from ~/.claude/CLAUDE.md, like the other home_root dotfiles). Includes the new 'Global tools available' section documenting box-wide Playwright/Chromium on nh3-dev.
This commit is contained in:
@@ -0,0 +1,574 @@
|
|||||||
|
# CLAUDE.md — global preferences (lkraven)
|
||||||
|
|
||||||
|
Loaded into every Claude Code session regardless of project. Project-
|
||||||
|
local `CLAUDE.md` files take precedence when they conflict; this file
|
||||||
|
is the baseline.
|
||||||
|
|
||||||
|
## Core principles
|
||||||
|
|
||||||
|
Four principles governing engineering choices across all projects.
|
||||||
|
Common lodestar: fitness-for-purpose. Each rejects a different
|
||||||
|
substitute goal that disguises itself as virtue.
|
||||||
|
|
||||||
|
1. **Excellence over uniqueness.** Pick the shape that's right for
|
||||||
|
the problem, not the shape that's new. If uniqueness is a
|
||||||
|
byproduct of excellence, so be it; do not target it.
|
||||||
|
|
||||||
|
2. **Explicit over implicit.** Make load-bearing assumptions,
|
||||||
|
constraints, and coupling visible. Idiomatic implicitness
|
||||||
|
(language conventions, well-known protocols) is fine — the rule
|
||||||
|
targets *invisible* implicitness, not all of it. Cost of
|
||||||
|
explicitness is verbosity; cost of invisible implicitness is
|
||||||
|
undetectable coupling. Pay the cost where auditability beats
|
||||||
|
the tax.
|
||||||
|
|
||||||
|
3. **Elegance is a byproduct, not a target.** Excellent engineering
|
||||||
|
often produces elegant results; targeting elegance directly tends
|
||||||
|
to produce cleverness, which is a different thing. Review test:
|
||||||
|
"fit-for-purpose, debuggable, consistent" — not "feels nice."
|
||||||
|
|
||||||
|
4. **Action-relevance over thoroughness.** Before investigating,
|
||||||
|
ask whether the answer would change the action. If both outcomes
|
||||||
|
lead to the same default, skip the question.
|
||||||
|
|
||||||
|
## Operator cognitive-load reduction (core mission)
|
||||||
|
|
||||||
|
A core mission: **reduce the operator's cognitive load as he context-
|
||||||
|
shifts across dozens of projects.** He knows the detailed workings of
|
||||||
|
each — the job is not to teach, it is to let him re-enter any project
|
||||||
|
and act without reloading its full context from scratch. Three
|
||||||
|
standing obligations layered on top of normal work:
|
||||||
|
|
||||||
|
1. **Surface every architecture decision that matters to him.**
|
||||||
|
Material-consequence decisions — module boundaries, naming with
|
||||||
|
downstream reach, scope direction, anything hard to reverse — go to
|
||||||
|
him, not a peer, not a silent default. (The operator-owns-
|
||||||
|
architectural-calls rule, restated as a load-reduction duty.) Do
|
||||||
|
**not** dumb the decision down — he wants the real substance.
|
||||||
|
|
||||||
|
2. **Pair every operator-facing decision with an `/elitk` decision
|
||||||
|
tree.** When you surface a decision for him to make, accompany the
|
||||||
|
technical framing with a King-grade (`/elitk`) decision tree:
|
||||||
|
plain-language, jargon-free, the branches and where each leads, so
|
||||||
|
he can decide in seconds without reloading the project's context.
|
||||||
|
The tree is the load-reducer; the technical framing is the
|
||||||
|
substance — give both, every time. Lead with your recommendation.
|
||||||
|
|
||||||
|
3. **Keep a running `/elitk` summary of decisions made on his behalf.**
|
||||||
|
Every call you take autonomously (agent-discretion: patch bumps,
|
||||||
|
tie-breaks, routing, sequencing, implementation-level choices) earns
|
||||||
|
a plain-language line in a decisions summary, so he can audit what
|
||||||
|
happened in his absence without digging through the work. Offer the
|
||||||
|
`/elitk` summary unprompted at natural checkpoints and whenever he
|
||||||
|
asks "what have you decided?"
|
||||||
|
|
||||||
|
4. **Always attach the real technical detail — never make him ask for
|
||||||
|
it.** Every `/elitk` decision tree and every decisions-summary line
|
||||||
|
carries its actual technical specifics alongside the plain-language,
|
||||||
|
clearly delineated (parentheses, brackets, an indented technical
|
||||||
|
note, a `details:` tail — your pick) so it can be read or skipped at
|
||||||
|
a glance. Plain-language is the fast-scan default; the technical
|
||||||
|
version rides *with* it, never behind a follow-up request. **He
|
||||||
|
chooses his own cognitive load by deciding whether to read the
|
||||||
|
bracketed detail** — the job is to make both present, not to
|
||||||
|
pre-decide which he needs. Example: "kept the version cadence
|
||||||
|
conservative `[F03 research work → patch v0.5.4 then v0.5.5; the two
|
||||||
|
docs-only edits → no bump per the SemVer docs-only skip-rule]`."
|
||||||
|
|
||||||
|
This extends the non-technical-breakdown habit (auto-memory
|
||||||
|
`feedback_non_technical_breakdown_on_findings`) from findings to *all*
|
||||||
|
decisions, and sharpens it with the decision-tree-for-pending-calls
|
||||||
|
requirement. `/elitk` is the grade and the tool; its King framing —
|
||||||
|
smart reader, zero jargon — is exactly the operator mid-context-shift.
|
||||||
|
|
||||||
|
## Cross-frontier-model consultation discipline
|
||||||
|
|
||||||
|
Consults to non-Claude peer models (Heid = Codex/gpt-5.x oracle;
|
||||||
|
Eitri-Smithy = Codex-shaped embedded research peer; any future
|
||||||
|
non-Claude reviewer agent) operate under **two complementary
|
||||||
|
anti-failure framings**:
|
||||||
|
|
||||||
|
1. **Authority-frame**: peers provide **fresh perspective**, not
|
||||||
|
**superior reasoning**. Different model families have different
|
||||||
|
priors and different training cutoffs — they catch different
|
||||||
|
blind spots. That is the load-bearing value, not authority.
|
||||||
|
2. **Role-frame**: peers are **peer-reviewers, not operator-level
|
||||||
|
oracles**. Routing operator-level decisions (architectural
|
||||||
|
choices, scope direction, what-to-build calls with material
|
||||||
|
consequence) to a peer for an authoritative answer is misuse —
|
||||||
|
those go to the operator regardless of what the peer says.
|
||||||
|
Peers can pressure-test, paraphrase, surface ambiguity, and
|
||||||
|
recommend implementation-level calls; they don't decide.
|
||||||
|
|
||||||
|
Together: peers are useful reviewers whose value comes from a
|
||||||
|
different angle, not better answers; the operator owns the
|
||||||
|
architectural calls, period.
|
||||||
|
|
||||||
|
**Default skepticism, never auto-adopt.** Every cross-frontier reply
|
||||||
|
gets triaged before any of it lands in a plan, contract, or commit.
|
||||||
|
Five-category triage:
|
||||||
|
|
||||||
|
1. **Genuine add** — peer caught something my framing genuinely
|
||||||
|
missed. Take it.
|
||||||
|
2. **Sharpening** — peer reframed something I already had into a
|
||||||
|
sharper version. Merge into the existing variable; don't
|
||||||
|
double-count as net-new.
|
||||||
|
3. **Restatement of settled prior** — peer flagged as "missed" a
|
||||||
|
thing that is already settled in our findings/contracts/ADRs.
|
||||||
|
Useful as a coverage checklist; **not** a structural addition.
|
||||||
|
4. **Out-of-place** — peer's input is correct but belongs at a
|
||||||
|
different stage (e.g., implementation-stage detail surfaced
|
||||||
|
during frame-stage). Note and defer.
|
||||||
|
5. **Wrong-grounding** — peer reasoned from incomplete context and
|
||||||
|
manufactured a non-issue. Push back; do not adopt.
|
||||||
|
|
||||||
|
**Watch for the ignorance-of-context failure mode.** A peer's "you
|
||||||
|
missed X" claim has two possible sources: (a) genuine fresh insight,
|
||||||
|
or (b) the peer did not read the artifact where X is settled. Before
|
||||||
|
treating an omission claim as new, check what the peer actually
|
||||||
|
read — if your settled artifact wasn't on their reading list, the
|
||||||
|
"miss" is probably category 3 or 5, not category 1.
|
||||||
|
|
||||||
|
**Adoption criterion**: "this improves the outcome on its merits"
|
||||||
|
— never "the peer said so." Treating Codex (or any non-Claude
|
||||||
|
oracle) as an all-knowing authority is a category error; treat it
|
||||||
|
as a wise sounding board whose value is forcing you to defend
|
||||||
|
your framing against a differently-primed reader.
|
||||||
|
|
||||||
|
**Applies hardest to `/heid*` skills.** Those skills' artifact-only
|
||||||
|
discipline protects the EMITTING side (Heid can't be primed by the
|
||||||
|
caller); the CONSUMING side rubber-stamp risk is on whoever invokes
|
||||||
|
the skill. Always triage Heid output before acting on it.
|
||||||
|
|
||||||
|
## Development workflow shapes
|
||||||
|
|
||||||
|
Two end-to-end shapes for taking a unit of work from idea to landed.
|
||||||
|
Pick by whether the work will be implemented by an AFK agent
|
||||||
|
(Sleipnir dispatch) or directly in-session. Both front-load the same
|
||||||
|
deliberation — heid consult → contract → heid contract review →
|
||||||
|
contract fixup — so the spec is sound before any code; they diverge
|
||||||
|
only at the implementation handoff.
|
||||||
|
|
||||||
|
Stages are defaults, not a rigid gate. Skip a stage when it would be
|
||||||
|
ceremony (a trivial bug fix needs no vor pass; a one-liner needs no
|
||||||
|
contract). The heid consult and review stages follow the cross-
|
||||||
|
frontier triage discipline above: never auto-adopt.
|
||||||
|
|
||||||
|
**Contract-skip is a direct-implementation privilege.** In the direct
|
||||||
|
shape, low-effort work — surgical test updates, localized bug fixes,
|
||||||
|
one-liners — runs straight to implementation without a fresh contract,
|
||||||
|
*provided* any existing contract governing the touched behavior is
|
||||||
|
updated in the same commit so it stays canonical (skip *authoring* a
|
||||||
|
contract, never let a live one go stale against the code). This does
|
||||||
|
not extend to AFK dispatch, which always requires a `prd:`-pinned
|
||||||
|
contract per § "Issue → AFK dispatch hygiene (Sleipnir)" (hard policy)
|
||||||
|
— and trivial work is not an AFK candidate in the first place: the
|
||||||
|
scaffold → contract → review → preflight ritual carries real overhead
|
||||||
|
that only pays for itself on higher-effort tasks. When in doubt,
|
||||||
|
low-effort stays direct.
|
||||||
|
|
||||||
|
### AFK dispatch shape (Sleipnir)
|
||||||
|
|
||||||
|
For work an AFK agent will implement off a contract.
|
||||||
|
|
||||||
|
1. Issue created.
|
||||||
|
2. Heid consult on the issue (`/heid`) — pressure-test the framing.
|
||||||
|
3. Scaffold the issue for AFK dispatch (`/sleipnir-scaffold <N>`) —
|
||||||
|
writes the `prd:`-pinned contract frontmatter.
|
||||||
|
4. Contract generation — the architect writes the contract body.
|
||||||
|
5. Heid contract review (`/heid-contract-review`).
|
||||||
|
6. Fixup the contract per triaged findings.
|
||||||
|
7. Preflight + mark ready-for-agent (`/sleipnir-preflight <N>`) — the
|
||||||
|
irreversible dispatch authorization. See § "Issue → AFK dispatch
|
||||||
|
hygiene (Sleipnir)" for the gate's hard requirements.
|
||||||
|
|
||||||
|
### Direct implementation shape
|
||||||
|
|
||||||
|
For work implemented directly in-session.
|
||||||
|
|
||||||
|
1. Issue created.
|
||||||
|
2. Heid consult on the issue (`/heid`).
|
||||||
|
3. `/vor` — or `/vor-frame` (ask too shapeless to draft a `/vor`
|
||||||
|
questionnaire) or `/vor-cross` (cross-frontier peer in the loop) —
|
||||||
|
if the ask warrants a pre-contract design pass. Skip when the
|
||||||
|
frame is already crisp.
|
||||||
|
4. Write the contract.
|
||||||
|
5. Heid contract review (`/heid-contract-review`).
|
||||||
|
6. Fixup the contract per triaged findings.
|
||||||
|
7. TDD implement (`/tdd`) — red-green-refactor against the contract.
|
||||||
|
8. Heid code review (`/heid-code-review`) — code-vs-contract drift.
|
||||||
|
9. Fixup the code per triaged findings.
|
||||||
|
10. Commit if clean.
|
||||||
|
|
||||||
|
## Tooling preferences
|
||||||
|
|
||||||
|
- **Python: prefer `uv` whenever possible.** Use `uv venv`, `uv pip
|
||||||
|
install`, `uv run`, `uv tool install`, etc. instead of `python -m
|
||||||
|
venv`, `pip`, `pipx`, `poetry`. Exception: if the project clearly
|
||||||
|
uses something else (a `poetry.lock` exists, the README says
|
||||||
|
`pip-tools`, the Dockerfile already pins `pip install`), follow the
|
||||||
|
project's tooling — don't fight it just to use uv.
|
||||||
|
- **Shell: I run interactive `zsh`.** Commands you hand me to paste
|
||||||
|
must be zsh-safe: quote glob-bearing args (`'pkg[extra]'`, not
|
||||||
|
`pkg[extra]` — zsh errors `no matches found` on unquoted brackets)
|
||||||
|
and don't rely on bash-only syntax. Inline `#` comments are fine
|
||||||
|
(`setopt interactive_comments` is set in `~/.zshrc`). Claude Code's
|
||||||
|
Bash tool also runs zsh here (it follows `$SHELL`), so the same
|
||||||
|
applies to tool commands.
|
||||||
|
|
||||||
|
## Global tools available
|
||||||
|
|
||||||
|
Tools standing ready in the working environment — assume present and use
|
||||||
|
them without a setup detour. (Most Claude Code sessions run natively on
|
||||||
|
**nh3-dev** `10.100.10.50`, the dev box; "available" means there unless a
|
||||||
|
note says otherwise. On other boxes, check first.)
|
||||||
|
|
||||||
|
- **Playwright + headless Chromium** — installed **box-wide on nh3-dev**:
|
||||||
|
the system shared-libs (apt, via `playwright install-deps`), the browser
|
||||||
|
binaries in shared **`/opt/ms-playwright`** (chromium + headless-shell,
|
||||||
|
root-owned + world-readable), and
|
||||||
|
`PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright` wired globally
|
||||||
|
(`/etc/environment` + `/etc/profile.d/`). A project only needs the
|
||||||
|
`playwright` module (`npm i playwright` — the browser download is
|
||||||
|
skippable, it resolves the shared binary); **no per-project
|
||||||
|
`playwright install`**. Use for anything that needs a real browser
|
||||||
|
engine: true DOM/SVG layout geometry, screenshots, headless rendering,
|
||||||
|
browser-based tests or scraping. Add a browser / bump via
|
||||||
|
`ssh infra-ops@10.100.10.50 'sudo env PLAYWRIGHT_BROWSERS_PATH=/opt/ms-playwright npx -y playwright install <browser>'`.
|
||||||
|
|
||||||
|
## DevOps delegation
|
||||||
|
|
||||||
|
For all DevOps work — deployments, infrastructure provisioning,
|
||||||
|
server administration, credential management, system-level package
|
||||||
|
installs, network/firewall configuration, service uptime — **prefer
|
||||||
|
routing to `infra-ops` via althing** rather than handling directly
|
||||||
|
in a project-dev session.
|
||||||
|
|
||||||
|
When infra-ops needs auth keys or access it doesn't already hold,
|
||||||
|
**it asks the appropriate peer agent directly** rather than blocking
|
||||||
|
on the operator. Examples:
|
||||||
|
|
||||||
|
- Heimdall scopes (Worldtree auth) → ask `worldtree-dev`.
|
||||||
|
- Gitea API tokens / repo permissions → ask the peer that holds
|
||||||
|
admin access for the relevant org.
|
||||||
|
- Vendor / subscription API keys (OpenAI, Anthropic, etc.) → ask
|
||||||
|
the operator or the peer that owns the consuming service.
|
||||||
|
- Cloud / hosting credentials → ask the operator.
|
||||||
|
|
||||||
|
The principle: infra-ops is self-sufficient on the access-gathering
|
||||||
|
front. Exhaust peer-agent paths before escalating to the operator.
|
||||||
|
The operator (Vuong) is the final authority for credentials not in
|
||||||
|
any agent's possession, but the agent network should resolve
|
||||||
|
credential routing among itself when possible.
|
||||||
|
|
||||||
|
## Attribution
|
||||||
|
|
||||||
|
All attributions are to **Vuong Hoang**. Never reference Claude,
|
||||||
|
Claude Code, Anthropic, "AI-assisted", "Generated with …", or robot
|
||||||
|
emojis anywhere — git commit messages, PR bodies, README author lines,
|
||||||
|
LICENSE copyright, `pyproject.toml` authors, file headers, HTML
|
||||||
|
footers, or any other byline. The user is the author; the assistant
|
||||||
|
is invisible.
|
||||||
|
|
||||||
|
Specifically, never append:
|
||||||
|
|
||||||
|
- `Co-Authored-By: Claude …`
|
||||||
|
- `🤖 Generated with [Claude Code](…)`
|
||||||
|
- "with help from Claude / an AI assistant / etc."
|
||||||
|
|
||||||
|
…to any committed artifact.
|
||||||
|
|
||||||
|
## SemVer etiquette
|
||||||
|
|
||||||
|
Each code-bearing or substantive-artifact commit bumps a version in
|
||||||
|
the project's `pyproject.toml` (or equivalent), refreshes the
|
||||||
|
lockfile, gets a `vX.Y.Z` git tag. Establishes a fine-grained
|
||||||
|
changelog and lets any peer pin against a known-good substrate
|
||||||
|
state.
|
||||||
|
|
||||||
|
**Tier-bar test (the decision tool):**
|
||||||
|
|
||||||
|
> *Does this release warrant a release note — or, in the case of a
|
||||||
|
> post-1.0 release, does it rise to the level of requiring a push
|
||||||
|
> notification to subscribed downstream consumers? Does this release
|
||||||
|
> warrant a blog post or a press release?*
|
||||||
|
|
||||||
|
The escalation maps to communication metaphors:
|
||||||
|
|
||||||
|
| Tier | Question | Communication metaphor |
|
||||||
|
|---|---|---|
|
||||||
|
| **Patch** (default) | n/a — patch is the workhorse default | Changelog line |
|
||||||
|
| **Minor** (pre-1.0) | Does this warrant a **release note**? | Subscribers glance at it |
|
||||||
|
| **Minor** (post-1.0) | Does this rise to **push-notification to subscribed downstream consumers**? | We actively reach out |
|
||||||
|
| **Major** | Does this warrant a **blog post or a press release**? | Story worth telling beyond subscribers |
|
||||||
|
|
||||||
|
The crucial implicit calibration: **the bar for minor RISES at v1.0.**
|
||||||
|
Pre-1.0, minor is cheap (would you write a release-note paragraph?);
|
||||||
|
post-1.0, minor is expensive (would you actually interrupt downstream
|
||||||
|
consumers about this?). Pre-1.0 is iterative cheap-minors; post-1.0
|
||||||
|
is stable deliberate-minors. Crossing v1.0 is a discipline-tightening
|
||||||
|
event, not just a number.
|
||||||
|
|
||||||
|
**In Corviduo,** "push notification to subscribed downstream
|
||||||
|
consumers" maps concretely to: **an althing post to peer-dev handles
|
||||||
|
announcing the change**. That's the actual mechanism. Operator or
|
||||||
|
Brokkr pings worldtree-dev / galdrabok-dev / sleipnir-dev / etc.
|
||||||
|
when a post-1.0 minor lands.
|
||||||
|
|
||||||
|
### Operator approval required for any non-patch bump
|
||||||
|
|
||||||
|
**Patch bumps are at agent discretion.** Apply them autonomously as
|
||||||
|
part of the work.
|
||||||
|
|
||||||
|
**Minor and major bumps REQUIRE explicit operator approval** before
|
||||||
|
the bump commit lands. The mechanism:
|
||||||
|
|
||||||
|
1. Identify that the work warrants a non-patch bump per the
|
||||||
|
tier-bar test (release-note / push-notification / blog-post).
|
||||||
|
2. Surface to the operator with a concrete question:
|
||||||
|
*"This work appears minor-worthy because <reason>. Approve the
|
||||||
|
vX.Y.Z → vX.Y+1.0 bump?"*
|
||||||
|
3. **Wait for explicit approval** before applying the bump.
|
||||||
|
4. Apply the bump (edit pyproject.toml, run `uv lock`, commit, tag)
|
||||||
|
only after the operator has said yes.
|
||||||
|
|
||||||
|
This guard exists because non-patch bumps in agent-applied autonomy
|
||||||
|
drifted upward — the operator caught a minor-cadence-too-fast
|
||||||
|
pathology on 2026-05-25 (three bumps in ~60 min, two of them
|
||||||
|
minor; would land at v0.4823.2 territory at sustained pace). The
|
||||||
|
tier-bar test alone wasn't sufficient discipline; explicit
|
||||||
|
operator-in-the-loop is the corrective.
|
||||||
|
|
||||||
|
If the operator pre-authorizes a session-level batch (e.g., "just
|
||||||
|
ship the next minor when you reach the heid-orchestrator milestone"),
|
||||||
|
that constitutes approval — but the pre-authorization should be
|
||||||
|
explicit and bounded to a specific upcoming event, not "all minors
|
||||||
|
going forward."
|
||||||
|
|
||||||
|
This rule applies UNIVERSALLY — even in repos where push is
|
||||||
|
agent-authorized (like Brokkr-Smithy per its project-local
|
||||||
|
CLAUDE.md). Push-discretion and bump-discretion are independent
|
||||||
|
authorizations.
|
||||||
|
|
||||||
|
### Patch (`X.Y.Z` → `X.Y.Z+1`) — workhorse default
|
||||||
|
|
||||||
|
The default for any code-bearing or substantive-artifact commit.
|
||||||
|
Includes:
|
||||||
|
|
||||||
|
- Bug fixes
|
||||||
|
- Internal correctness improvements
|
||||||
|
- Refactors with no public-surface signature change
|
||||||
|
- New artifacts within an existing family (new R-target finding, new
|
||||||
|
spec doc, new feedback memory)
|
||||||
|
- Single-commit features that don't require downstream coordination
|
||||||
|
- Validator additions, security tightenings, drift-against-spec
|
||||||
|
corrections
|
||||||
|
- Skill specs authored (spec drafted; minor fires at implementation
|
||||||
|
ship)
|
||||||
|
|
||||||
|
Patches accumulate routinely. Most commits are patches.
|
||||||
|
|
||||||
|
### Minor (`X.Y.Z` → `X.Y+1.0`) — coordinated-release event
|
||||||
|
|
||||||
|
Reserved for events where the tier-bar test fires: would you write a
|
||||||
|
release note (pre-1.0) or send a push notification to downstream
|
||||||
|
consumers (post-1.0)?
|
||||||
|
|
||||||
|
Pre-1.0, the bar is "release-note-worthy paragraph." Post-1.0, it's
|
||||||
|
the stricter "actually-pinging-consumers." Examples that pass at
|
||||||
|
either bar:
|
||||||
|
|
||||||
|
- **Cross-repo deliverable shipped to a peer agent** (e.g., Brokkr
|
||||||
|
R10 A01 ContextPromotion intelligence package → worldtree-dev).
|
||||||
|
Downstream HAS to react.
|
||||||
|
- **R-target full closure** — multi-finding + action lifecycle
|
||||||
|
complete; the package is the milestone landmark.
|
||||||
|
- **Skill IMPLEMENTATION shipped** at the implementation site
|
||||||
|
(post-spec absorption). Callers must adapt.
|
||||||
|
- **Methodology charter changes** (e.g., adding noise-floor
|
||||||
|
cross-check ambient to Brokkr's preregistration discipline).
|
||||||
|
High-leverage; affects every probe going forward.
|
||||||
|
- **Pre-v1.x breaking change** — under the no-backward-compatibility
|
||||||
|
rule, breaking changes ride in minor until v1.0. Breaking changes
|
||||||
|
are intrinsically release-note-worthy; minor is the right tier.
|
||||||
|
- **API signature change to publicly-callable surface** post-1.0
|
||||||
|
that affects fewer callers than a full major (e.g., new optional
|
||||||
|
parameter, opt-in capability). Still warrants the
|
||||||
|
push-notification.
|
||||||
|
|
||||||
|
Examples that DON'T pass the tier-bar and stay as patches:
|
||||||
|
|
||||||
|
- A single new R-target finding (F-ID) within an active R-target's
|
||||||
|
lifecycle. The closure is the milestone, not each finding.
|
||||||
|
- A new feedback memory written.
|
||||||
|
- A spec doc authored (minor fires at implementation, not at spec).
|
||||||
|
- A new probe artifact added within an existing probe.
|
||||||
|
- A persistent-memory snapshot.
|
||||||
|
|
||||||
|
### Major (`X.Y.Z` → `X+1.0.0`) — blog-post / press-release event
|
||||||
|
|
||||||
|
Reserved for v1.0+ release milestones AND post-1.0 events whose
|
||||||
|
scale warrants telling people beyond your subscriber base.
|
||||||
|
|
||||||
|
Pre-v1.x, the no-backward-compat rule means every minor can carry
|
||||||
|
breakage; major is the milestone-cut signal (v1.0 itself), not a
|
||||||
|
per-PR concern.
|
||||||
|
|
||||||
|
Post-v1.0:
|
||||||
|
|
||||||
|
- v1.0 release itself (the discipline-tightening crossover event).
|
||||||
|
- Substantial breaking changes that would otherwise force most
|
||||||
|
consumers to adapt at once.
|
||||||
|
- Architectural restructurings that downstream documentation,
|
||||||
|
integrations, and conceptual-mental-models depend on.
|
||||||
|
|
||||||
|
### Decision rule when ambiguous
|
||||||
|
|
||||||
|
**Default to patch.** Minor and major require explicit justification.
|
||||||
|
If the answer to "does this warrant a release note?" is "maybe, kind
|
||||||
|
of, I guess?" — that's a patch. Reserve minor for the unambiguous
|
||||||
|
yes-I'd-write-a-paragraph cases.
|
||||||
|
|
||||||
|
**When both minor and patch can be justified, default to patch.**
|
||||||
|
Tie-breaks go to patch, not minor. The "both could apply" situation
|
||||||
|
is itself a signal that minor's mandate isn't strong — if minor were
|
||||||
|
clearly warranted, patch wouldn't also be defensible. Patch is the
|
||||||
|
workhorse default; let it work. This is a sharper statement of the
|
||||||
|
same posture above: the bar for non-patch is "patch is NOT defensible
|
||||||
|
for this commit," not "minor is defensible." Asymmetric default in
|
||||||
|
favor of the cheaper tier.
|
||||||
|
|
||||||
|
The old "two callers react differently" rule remains a useful
|
||||||
|
internal check: if breaking-vs-keep-working applies to current
|
||||||
|
callers, it's at least minor. But the tier-bar is the load-bearing
|
||||||
|
test.
|
||||||
|
|
||||||
|
### SKIP the bump entirely for
|
||||||
|
|
||||||
|
- CI-only edits
|
||||||
|
- True docs-only edits (READMEs, comments, formatting)
|
||||||
|
- ADR commits with no code
|
||||||
|
- `.contract.md` commits with no code
|
||||||
|
- Memory-snapshot commits (`memory: snapshot — …`)
|
||||||
|
- Test-only commits with no production-code change
|
||||||
|
- WIP / TDD-RED commits where the tree is in a known-broken state
|
||||||
|
- Brokkr-side template edits with no runtime effect on Brokkr itself
|
||||||
|
- Worktree-rebuild or env-config changes
|
||||||
|
- `.claude/` configuration edits
|
||||||
|
|
||||||
|
### Cadence
|
||||||
|
|
||||||
|
Most commits should be patches. Minor should be rarer than commits —
|
||||||
|
often 5-15 patches between minors during active development.
|
||||||
|
|
||||||
|
A TDD red/green/refactor cycle bumps once or twice (GREEN as patch,
|
||||||
|
REFACTOR as patch — never three times for the same logical change).
|
||||||
|
A feature shipped as several incremental green commits bumps each as
|
||||||
|
patch; the minor that "publishes" the feature can fire at the end of
|
||||||
|
the arc if it warrants a release-note, OR can be skipped if patches
|
||||||
|
were sufficient.
|
||||||
|
|
||||||
|
If you find yourself bumping minor multiple times per session on the
|
||||||
|
same project, you're likely over-applying minor. Default back to
|
||||||
|
patch and ask: does this *specific* commit warrant a release-note
|
||||||
|
paragraph, or am I just accumulating substantive work?
|
||||||
|
|
||||||
|
### Mechanics every bump
|
||||||
|
|
||||||
|
0. **If non-patch, get operator approval first** per the § *Operator
|
||||||
|
approval required for any non-patch bump* rule above. Do not
|
||||||
|
proceed to step 1 until the operator has explicitly approved the
|
||||||
|
minor or major bump. (Patch bumps skip this step — apply
|
||||||
|
autonomously.)
|
||||||
|
1. Edit `pyproject.toml` (or equivalent project-file) version field.
|
||||||
|
2. Run `uv lock` (Python) or equivalent so the lockfile records the
|
||||||
|
new version. Don't hand-edit the lockfile.
|
||||||
|
3. Stage both files alongside the actual change.
|
||||||
|
4. Commit with the conventional shape (e.g., `feat(#N): …` /
|
||||||
|
`fix(#N): …` / `refactor: …`).
|
||||||
|
5. `git tag vX.Y.Z` after the commit. Lightweight (no `-a`, no
|
||||||
|
message) is deliberate for per-bump tags: the commit object
|
||||||
|
carries the rationale, and the tag is just a ref naming the
|
||||||
|
substrate state.
|
||||||
|
**Exception — milestone releases** (v1.0, v2.0, future major
|
||||||
|
cuts) get annotated tags (`git tag -a -m "…"`, or `git tag -s`
|
||||||
|
when signing). At a milestone the attestation matters separately
|
||||||
|
from the code change: release notes, tagger identity + date, and
|
||||||
|
optional GPG signature live in the tag object itself, where
|
||||||
|
downstream pins and supply-chain verifiers can read them.
|
||||||
|
6. Push is the operator's call — never push automatically.
|
||||||
|
(Project-local `CLAUDE.md` may grant push discretion, e.g.,
|
||||||
|
Brokkr-Smithy; honor those when present.)
|
||||||
|
|
||||||
|
### Calibration examples
|
||||||
|
|
||||||
|
**Brokkr-Smithy 2026-05-25 session (the recalibration trigger):**
|
||||||
|
|
||||||
|
Initially bumped under the pre-amendment rule:
|
||||||
|
|
||||||
|
- `v0.1.0 → v0.2.0` (minor) — F02 R06 v2 taxonomy reduction ship
|
||||||
|
- `v0.2.0 → v0.3.0` (minor) — Heid orchestrator spec set v0.1
|
||||||
|
- `v0.3.0 → v0.3.1` (patch) — migration runbook revision
|
||||||
|
|
||||||
|
Under THIS amended rule:
|
||||||
|
|
||||||
|
- F02 ship would be **patch** — single finding within R06 v2's
|
||||||
|
active lifecycle. R06 v2 closure (multi-finding + action) gets
|
||||||
|
the minor.
|
||||||
|
- Heid orchestrator spec set — **patch** strictly (spec authored,
|
||||||
|
not yet implemented). Galdrabok-dev's skill spec implementation
|
||||||
|
shipping IS minor (callers adapt).
|
||||||
|
- Runbook revision — **patch** (correct under both rules).
|
||||||
|
|
||||||
|
The session would have ended at roughly v0.1.5 (five patches) with
|
||||||
|
maybe a v0.2.0 cut when the heid orchestrator's smoke-tests-pass +
|
||||||
|
galdrabok ship lands as the cohesive milestone.
|
||||||
|
|
||||||
|
**Worldtree #185 (2026-05-21):**
|
||||||
|
|
||||||
|
- `v0.20.0` (minor) — `ChromaLongTermMemory.store/search/retrieve/
|
||||||
|
forget` gained required keyword-only `end_user_id`. Pre-v1.x
|
||||||
|
breaking change; every caller had to be updated. Release-note-
|
||||||
|
worthy in pre-1.0 framing. **Minor** under both old and new
|
||||||
|
rules.
|
||||||
|
- `v0.20.1` (patch) — Heid-flagged drift fixes within the v0.20.0
|
||||||
|
surface. **Patch** under both rules.
|
||||||
|
|
||||||
|
### Retroactive bumps
|
||||||
|
|
||||||
|
Don't retroactively bump past commits to align with a tightened
|
||||||
|
rule. Substrate-state baseline is forward-looking: the bump-cadence
|
||||||
|
from this point forward reflects the discipline; past versions
|
||||||
|
record what happened under the previous rule. The pre/post boundary
|
||||||
|
is the amendment-effective commit, not the rule itself.
|
||||||
|
|
||||||
|
## Issue → AFK dispatch hygiene (Sleipnir)
|
||||||
|
|
||||||
|
Before marking any issue `ready-for-agent` (the label that gates AFK
|
||||||
|
dispatch via Sleipnir), it MUST have an issue-numbered contract at
|
||||||
|
`docs/contracts/issues/<N>.contract.md` AND that contract MUST carry
|
||||||
|
a `prd:` block in its YAML frontmatter pinning it to:
|
||||||
|
|
||||||
|
- the issue body (SHA-256, first 16 hex chars)
|
||||||
|
- the lock-in comment id + content SHA (or `null` if the issue body
|
||||||
|
alone is the spec)
|
||||||
|
- a `pinned_at` timestamp
|
||||||
|
|
||||||
|
This is hard policy, not a suggestion. Without the contract Sleipnir's
|
||||||
|
gate refuses dispatch with `blocked-needs-contract`. Without the `prd:`
|
||||||
|
block PRD-↔-ship drift becomes invisible — the audit infrastructure
|
||||||
|
that detects it is a no-op.
|
||||||
|
|
||||||
|
Verify before applying the label:
|
||||||
|
|
||||||
|
- contract file exists at the expected path
|
||||||
|
- frontmatter has a populated `prd:` block
|
||||||
|
- `python scripts/contract_drift_check.py --contract <path>` returns
|
||||||
|
clean (i.e., the pinned hashes match the live issue + comment)
|
||||||
|
|
||||||
|
The full convention — frontmatter shape, required fields, reasoning
|
||||||
|
behind the four drift entry points — lives in
|
||||||
|
`docs/contracts/CONTRACT-FORMAT.md` (the project that consumes
|
||||||
|
Sleipnir owns this file). Module-scoped contracts MAY adopt the same
|
||||||
|
`prd:` block when amended in response to a specific issue; for
|
||||||
|
issue-scoped contracts it is required.
|
||||||
Reference in New Issue
Block a user