Evolve crux itself — add a capability or fix a recurring flaw in the crux tool, end to end: ideate → build → validate → ship. Turns a feature idea or a "crux keeps doing X" annoyance into a signed-off PRD, a tests-first implementation, a hard validation gate (selftest green · stdlib-only · existing vaults still load · version/migration), and a pull request. Works for anyone contributing to crux, not just the maintainer; the maintainer self-merges and cuts releases. Use when working ON crux — adding to the engine/CLI/skill, picking up a backlog epic from `.spec/` (UI, wiki, marketing), or fixing an engine bug. Triggers: "evolve crux", "add a feature to crux", "crux keeps <doing X>", "improve crux", "contribute to crux", "send a crux PR", crux roadmap, crux backlog, wiki/GUI/autoresearch for crux.
Evolve crux itself — add a capability or fix a recurring flaw in the crux tool, end to end: ideate → build → validate → ship. Turns a feature idea or a "crux keeps doing X" annoyance into a signed-off PRD, a tests-first implementation, a hard validation gate (selftest green · stdlib-only · existing vaults still load · version/migration), and a pull request. Works for anyone contributing to crux, not just the maintainer; the maintainer self-merges and cuts releases. Use when working ON crux — adding to the engine/CLI/skill, picking up a backlog epic from `.spec/` (UI, wiki, marketing), or fixing an engine bug. Triggers: "evolve crux", "add a feature to crux", "crux keeps <doing X>", "improve crux", "contribute to crux", "send a crux PR", crux roadmap, crux backlog, wiki/GUI/autoresearch for crux.
license
MIT
metadata
{"author":"Mehdi Foroozandeh","version":"1.0","notice":"Playbook for evolving the crux tool; no third-party code."}
evolve-crux — ship a change to crux, rigorously
This skill is for working on crux the tool (your clone of the crux repo), not on a
research project that uses crux. It carries one change — a new capability or a fix for something
crux keeps getting wrong — through a strictly gated arc:
ideate → build → validate → ship
Each stage has an exit criterion; you do not advance until it's met. The arc is the
same whether the change is a one-line bug fix or a .spec/ epic — only the ceremony scales.
Who's driving (contributor-always)
Assume the person evolving crux is not the maintainer. Because crux ships this skill
to its users, everyone runs the same path and ends at a pull request — no
auto-detection of who you are, no privileged branch. The maintainer is just the
contributor who can self-merge their own PR, plus a small, separate release step
(below). This keeps one code path and makes third-party PRs first-class.
Work in a dedicated session inside your crux clone (a fresh chat, not the project you
were researching). No clone yet — e.g. you installed the skills via npx skills add?
git clone https://github.com/mehdiforoozandeh/crux first. For a large build you may
dispatch a worktree sub-agent, but the default is the main thread.
1 · Ideate → a signed-off PRD ◆
Ideation ends when there is a PRD the human has approved — not before any code. Reach
it by a pingpong / grill-me back-and-forth (surface one decision at a time; don't dump
options): what exactly are we adding or fixing, why, the design choice, and — load-bearing
— the acceptance criteria (the concrete checks that later become the validation
gate). Pre-registering "how we'll know it worked" is what makes validate enforceable
instead of vibes.
The PRD scales to the change:
Bug ("crux keeps mis-splitting inline parens") → a one-line PRD: the wrong behavior,
the correct behavior, and the acceptance criterion = a failing selftest that asserts the
correct behavior.
Feature / backlog epic (UI, wiki, autoresearch) → a full grilled PRD (skeleton below).
Feature ideas frequently come from the backlog in .spec/ — one spec document per epic,
indexed by .spec/README.md. If the change advances an epic, say so,
work from that spec's Acceptance criteria, and flip the item's status when it lands.
A spec is upstream of a PRD, not a substitute for one: the spec says what and why for a whole
epic, the PRD carries one shippable change through the gate. One spec normally becomes several
PRDs. Check the spec's Open questions before writing the PRD — an unresolved one is a
decision the PI still owes you.
PRD skeleton (Markdown; the exact text becomes the PR body):
# PRD: <shorttitle>-**Kind:** feature | fix | refactor - **Spec:** <.spec/NN-name.md, or —>
-**Problem / motivation:** what's missing or wrong, and why it matters.
-**Design decision:** the approach chosen (and the main one rejected + why).
-**Scope:** what this change does *not* do.
-**Acceptance criteria:** - [ ] <criterion → aselftestassert> # automatable
- [ ] <criterion → manualcheck> (manual: …) # un-automatable (GUI, Obsidian render)
-**Backward-compat / migration:** does this change vault format? (if yes → §3 gate 4)
Exit criterion: the human has read and approved the PRD as one block.
2 · Build — tests-first ◆→○
The moment the PRD is signed off, translate its acceptance criteria into the harness crux
already has:
Write the asserts first (red). Add new cases to skills/crux/scaffold/selftest.py — one
per automatable acceptance criterion — and run python skills/crux/scaffold/selftest.py; the
new ones should fail. (For a bug, this failing test is the reproduction.)
Implement to green. Edit skills/crux/scaffold/ (engine.py / crux.py / render.py /
templates/) until selftest is fully green — new asserts included, none regressed.
Un-automatable criteria (a GUI looking right, Obsidian rendering) stay as a manual
checklist carried in the PRD; you'll walk them by hand in validate.
Hard constraint — stdlib-only. The engine takes no third-party dependency. If a
criterion seems to need one, that's a design problem to raise, not a dep to add.
Exit criterion: selftest green with the new asserts, and code matches the PRD's design
decision (not a different one you drifted into).
3 · Validate — the gate ○
A fixed gate; all four must pass before ship. Nothing here is judgment — it's a checklist.
Selftest green.python skills/crux/scaffold/selftest.py → all pass, and the count has grown
by your new asserts (a feature that added no assert didn't really register its criteria).
This includes the agent evals (.spec/10), but only
their deterministic half: fixture certification, the manifest schema, the scorer's arithmetic
on canned submissions, and the mutation harness. All of it runs offline from a fresh clone
with no API key, which is the property that makes a gate a gate. Scoring a live agent
submission never gates — a submission exists only after someone ran an agent, attended, and
a check a third-party contributor cannot run is not a checklist item. Run those by hand with
python skills/crux/scaffold/evals.py when you change an agent definition or a prompt.
Stdlib-only. Grep the diff for imports; fail on any module outside the Python stdlib.
git diff -U0 -- skills/crux/scaffold | grep -E '^\+\s*(import|from) ' | grep -vE '<stdlib names>'
Existing vaults still load. Run the engine's read paths — status, review,
validate, and a render — against a vault copy and confirm nothing breaks:
if a real vault is discoverable (e.g. a cruxvault/ in a nearby project), copy it
to a scratch dir and validate against the copy — never mutate the original;
otherwise fall back to the committed synthetic fixture skills/crux/examples/demo_vault/
(copy it out first). This synthetic vault is the default gate — it ships in the repo,
so every contributor can run it; the real-vault check is an optional local upgrade.
Version / migration.Only if the change alters vault format or verdict/roll-up/view
logic: bump ENGINE_VERSION in engine.py, and prove an old-format vault
migrates or still reads cleanly (the drift warning from check_and_stamp_version is
expected; a crash or wrong verdict is a fail). If format is unchanged, leave
ENGINE_VERSION alone and note "no migration."
Then walk any manual acceptance criteria from the PRD and tick them.
Exit criterion: all four gates pass + every PRD acceptance criterion is ticked. If any
fails, go back — do not proceed to ship.
4 · Ship — open a PR ◆
Ship happens only after §3 fully passes. For everyone, ship ends at a green pull
request whose body is the PRD:
Add an Unreleased entry to CHANGELOG.md (create it if absent): one line under
## [Unreleased] describing the change. Contributors do not bump the version or tag.
Branch, commit, push to a fork, open the PR:
gh repo fork mehdiforoozandeh/crux --remote # first time only; skip if you have push
git switch -c evolve/<slug>
git add -A && git commit -m "<kind>: <short title>"
git push -u origin evolve/<slug>
gh pr create --title "<kind>: <short title>" --body-file <the PRD>.md
The PR self-documents: reviewer checks the diff against the PRD's pre-registered
acceptance criteria and the green selftest — not reverse-engineered intent.
Exit criterion: a PR is open, selftest green in it, PRD as the body.
Maintainer-only: self-merge + cut a release
The maintainer runs the identical arc, then:
Self-merge their own PR once the gate is green (they may push/merge to main).
Cut a release as a separate, occasional action — decoupled from any single feature,
not once per PR: roll the accumulated ## [Unreleased] CHANGELOG entries into a version
section, git tag vX.Y.Z, push tags. Where /crux is installed as a symlink into a
clone (./install.sh), merging already updates the live skill — no reinstall;
npx-installed copies are frozen and update via npx skills update.
Guardrails
The gate is non-negotiable. No shipping on an un-green selftest, a new dependency, a
broken existing vault, or a format change without a version bump + migration proof.
Tests before code. Acceptance criteria become asserts first; if a criterion can't be
expressed as a check (assert or manual), the PRD isn't done.
Don't hand-edit generated views in the fixtures (META.md, EXPERIMENTS.md, ledger
blocks) — regenerate them via the engine so the fixture stays honest.
One change per PR. A feature and an unrelated fix are two arcs, two PRDs, two PRs.
Scope is crux the tool. This skill edits the crux repo clone. It never touches a
user's research vault or project code — those are what crux (and this change) serve.