Skip to content
Back to skills

Prd

ASecurity

- **Kind:** feature - **Spec:** [.spec/05-autopilot.md](../../.spec/05-autopilot.md) §9 — 05.x series, after [05.4](05.4-cockpit-tab.md) - **Signed off 2026-09-19** by the PI. Three rulings taken at sign-off, each as recommended: the PI **may** override a `crux-design` rejection with their sentence recorded verbatim in `## Guidance` (§G); the new `objective-op` lint **refuses** rather than warns (§E); and the skill **writes** `auto/<qid>/plan.md` and stops, leaving `crux auto approve` to the ...

  • 7 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added September 21, 2026
ai-agentspythongobashgit

Works with

  • terminal

Security analysis

A100/100

Pro scans all 16 files and shows the line behind each finding

Scanned September 21, 2026

npx -y skills add mehdiforoozandeh/crux --skill prd --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Prd?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Prd
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/mehdiforoozandeh-prd/badge)](https://www.skillsdirectory.com/skills/mehdiforoozandeh-prd)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
# PRD: 05.5 — the setup skill

- **Kind:** feature
- **Spec:** [.spec/05-autopilot.md](../../.spec/05-autopilot.md) §9 — 05.x series, after [05.4](05.4-cockpit-tab.md)
- **Signed off 2026-09-19** by the PI. Three rulings taken at sign-off, each as recommended:
  the PI **may** override a `crux-design` rejection with their sentence recorded verbatim in
  `## Guidance` (§G); the new `objective-op` lint **refuses** rather than warns (§E); and the
  skill **writes** `auto/<qid>/plan.md` and stops, leaving `crux auto approve` to the PI (§C).
  A fourth ruling reshaped §B: the conversation must not over-ask — three asks, two
  approvals, everything else derived, measured or defaulted.
- **Engine version:** `3.3`, **unchanged**. No vault-format change, no verdict change, no
  roll-up change, no `engine.snapshot` change. No migration. See *Backward-compat* for the one
  place a previously-accepted plan could newly be refused.

## Problem / motivation

Spec §9 names **twenty slots plus a baseline** that a flight plan must carry before
`crux auto run` will touch it, and `flight_plan_problems`
([engine.py:5927](../../skills/crux/scaffold/engine.py)) refuses a plan that is short of any
of them. Today there is nothing that gets a PI from "I want to search this" to a plan that
passes. `templates/flight_plan.md` exists, but it is **not read by any code** — grep finds no
reference to it outside a selftest comment. It is a document an agent is supposed to fill in,
and no instructions exist for filling it in.

That gap is not a convenience problem. Spec §9 closes with the line it calls *"the single most
important line in the plan"*:

> **The objective must come from a check that discriminates against the null.** Optimizing a bar
> the hypothesis was always going to clear is the machine-scale form of the bias spec 09 exists
> to prevent: the search will clear it, thousands of times, at cost, and teach nothing.

The engine enforces the *shape* of that — `flight_plan_problems`' `discriminates` check
([engine.py:6220](../../skills/crux/scaffold/engine.py)) refuses a plan whose objective address
is not named by a verifiable marked `discriminates:: true`. It cannot enforce the *order*. A PI
who picks the number first and writes a check around it afterwards produces a plan that passes
every lint and is exactly the failure the line forbids. **Only a conversation can get the order
right**, and that conversation is this slice.

Second, the template's `## Verifiables` block is a stub:

```
- [ ] <<verifiable>>
      fails-if:: <<fails_if>>
      discriminates:: true
- [ ] [outcome-neutral] <<control>>
      fails-if:: <<control_fails_if>>
```

`<<verifiable>>` has to satisfy four independent engine rules at once — `check-grammar`
(it must begin `<key.path> <op> <number>`), `discriminates` (it must name the objective
address), `control` (the set must carry an outcome-neutral one) and `scenario` (each needs a
failure scenario). A placeholder that says `<<verifiable>>` teaches none of them. **Defining
these placeholders is this slice's own deliverable**, per the 05.5 work item.

Third, a trap this project has already hit once: a hard-coded `<=` in a placeholder is **wrong
for `direction: max`**, and 05.2 reverted exactly such a change. The engine knows the rule —
`auto_scored_pass` is `value >= bar if direction == "max" else value <= bar`
([engine.py:6530](../../skills/crux/scaffold/engine.py)) — but nothing pins the objective's
*check text* to the objective's *direction*. The demo fixture happens to get it right
(`obj.score >= -0.5`, `direction:: max`); a plan that wrote `obj.score <= -0.5` under
`direction:: max` passes every lint today and searches against its own bar.

## Design decision

### A · One skill, at `skills/crux-autopilot/`

A skill, not an agent. Agents (`agents/<name>/AGENT.md`) are isolated single-shot graders;
this is a multi-turn conversation with the PI that *spawns* three of those agents. It matches
`crux-cockpit` — a skill that drives crux verbs on the PI's behalf and hands back one artifact.

`install.sh` discovers skills by scanning `skills/`
([install.sh:6](../../install.sh): *"Drop a new skill folder under skills/ and it's installed
automatically"*), so **no roster edit is needed** and the agent roster in
`selftest.run_agent_roster` is untouched — this slice adds no agent.

`skills/crux/SKILL.md` gains **one cross-reference line** pointing at the new skill from the
`auto check` / `auto approve` rows of its verb table. That is the whole edit, and it carries
the five-fixture re-pin obligation (see *Build notes*).

### B · The conversation asks only what it cannot derive, measure or default

**PI, 2026-09-19:** the setup conversation must be fast and to the point — it must not
over-ask, it must not over-engineer, it must sort out the most important things and **leave the
details and the non-obvious choices to the autopilot to figure out.** That ruling is the design
of this section, not a note on its tone.

Spec §9 names twenty slots. **Only three of them are asks.** The rest are derived from an
answer already given, measured by a command, or taken from the template default and stated back
in one line.

| # | the skill's turn | why it cannot be skipped |
|---|---|---|
| 1 | **ask** — the anchor question, and the goal in one falsifiable sentence | the frame is the PI's; nothing can derive it |
| 2 | **approve** — the null, proposed by `crux-null` | a ruling, not a value; spec 05 requires the PI's yes |
| — | *derived* — the checks, their kinds, the combination rule, the control | `crux-verifiables`, against the approved null |
| — | *derived* — the objective address | **read off** the discriminating check just written |
| 3 | **ask** — which direction is better, and the bar | see below; direction is the one thing that must never be guessed |
| 4 | **ask** — the harness, in one turn: scorer command, run command, frozen paths, writable paths, budget ceiling | only the PI knows their repo |
| — | *measured* — the baseline | `crux auto check` dry-runs the scorer and prints it (§H) |
| — | *defaulted* — the remaining fourteen slots | template defaults, stated back, not asked |
| 5 | **approve** — `crux-design`'s verdict, then `crux auto approve` | the PI's signature (§C, §G) |

**The objective is read off a check, never chosen.** Act 3's ask is the bar and the direction,
*after* `crux-verifiables` has written the checks — so the address comes out of a check that
already exists, and the engine's `discriminates` lint passes as a consequence rather than as a
hurdle. Spec §9's most important line becomes structurally true instead of a reminder somebody
has to remember. **This ordering survives the shortening; it is the one thing in the
conversation that is load-bearing.**

**Direction is asked, never inferred.** A metric named `loss` is usually minimised and a metric
named `score` usually maximised, and "usually" is exactly how 05.2's reverted `<=` got written.
One short question costs a turn; a backwards bar costs the whole run.

The fourteen defaulted slots are `mode`, `islands`, `island_cap`, `parallel_total`,
`parallel_island`, `retries`, `retention`, `replicates`, `rule`, `steward` / `steward_every`,
`stall_attempts`, `abort_invalid_runs`, `scorer_timeout`, and the agent block
(`agent`, `agent_failover`, `agent_cooldown`, `agent_probe`, `agent_probe_timeout`). The skill
states them in **one line**, not fourteen, and moves on.

**Five rules on the skill's voice, each greppable in `SKILL.md`:**

1. **One question per turn.** Never a questionnaire, never a numbered list of choices.
2. **Never ask what a command can measure.** The baseline is scored, never asked for.
3. **Never ask what the template defaults.** State the default in passing; discuss it only if the
   PI raises it.
4. **Never ask the PI to choose between options that differ only in something the search itself
   would discover.** That is what the autopilot is for — a choice the bandit can make in ten
   attempts must not cost a turn of the PI's attention.
5. **"I don't know" takes the default.** The skill records which slot was defaulted that way and
   moves on; it never escalates, re-asks, or explains the option space.

The skill never opens a turn by summarising the previous one, and it never closes one by listing
what remains. Those two habits are what make a five-slot conversation read as twenty.

### C · The skill writes the plan file. It never signs it.

`crux auto approve` is the PI's signature (spec 05.2, and `skills/crux/SKILL.md:353` marks it
◆ — *"Never run this without the PI's yes"*). The skill:

1. **writes** `auto/<qid>/plan.md` from the template,
2. runs `crux auto check` and fixes what it reports,
3. spawns `crux-design`,
4. **stops**, and hands the PI the path plus the exact `crux auto approve` line to run.

Writing the file is not approving it: `flight_plan_hash`
([engine.py:6541](../../skills/crux/scaffold/engine.py)) means the approval stamp covers a hash
of the document, so any edit outside `## Guidance` clears it. A written-but-unapproved plan is
inert — `crux auto run` refuses it. So the skill writing the file costs the PI nothing and
saves them transcribing twenty slots by hand.

The skill also never runs `crux auto guide` on the PI's behalf: `## Guidance` is the PI's own
words, append-only (`SKILL.md:351`).

### D · The `## Verifiables` placeholders become a worked grammar

The stub is replaced by placeholders that carry the four rules in their own shape, with the
operator **derived, never literal**:

```
## Verifiables

- [ ] <<address>> <<bar-op>> <<bar>> — <<what reaching this number would mean>>
      fails-if:: <<the world in which this number is reached and the goal is still false>>
      discriminates:: true
- [ ] [outcome-neutral] <<control-key>> <<control-op>> <<control-number>> — <<what this rules out>>
      fails-if:: <<the world in which this control passes and the run is still invalid>>
```

with a legend directly under the block, inside the template, stating:

- `<<bar-op>>` is **`>=` when `direction: max`** and **`<=` when `direction: min`**. It is never
  written as a literal in the template, because 05.2 reverted exactly that.
- the first check **must** repeat `<<address>>` verbatim — that is what `discriminates` matches
  on, token-wise ([engine.py:6221](../../skills/crux/scaffold/engine.py)).
- `<<bar>>` is the same number as `bar::` in `## Objective`.
- the control's operator is **not** derived from direction: a control is outcome-neutral, so it
  may point either way. The demo's `obj.score <= 0` under `direction: max` is correct.
- `fails-if::` is the world where the check passes and the claim is still false, never a
  restatement of the check.

### E · One pure helper and one new lint: `objective-op`

`engine.auto_direction_op(direction)` → `">="` for `max`, `"<="` for `min`, raising `CruxError`
otherwise. Pure, total, ten lines, beside `AUTO_COMPARISON_OPS`
([engine.py:5703](../../skills/crux/scaffold/engine.py)).

`flight_plan_problems` gains one check, `objective-op`: **the discriminating verifiable that
names the objective address must use the operator that agrees with `direction`.** It fires only
on the check the existing `discriminates` rule already singles out; controls and every other
check are untouched.

This is the only place in the slice where a plan that is accepted today could be refused
tomorrow — see *Backward-compat*. **It refuses** (PI, 2026-09-19).

### F · `closer: true` in the template, not in the engine

The 05.5 work item makes `closer: true` the default *in practice*, by writing it into new
plans. `templates/flight_plan.md`'s frontmatter changes `closer: false` → `closer: true`.

**`fm.get("closer")`'s own default stays falsey in the engine**, so a plan written before this
release — which carries `closer: false` explicitly, or omits it — runs exactly as it did. This
matters beyond tidiness: the `check-grammar` rule is skipped when `closer` is true
([engine.py:6205](../../skills/crux/scaffold/engine.py)), because with a closer the prose checks
are `crux-close`'s to propose. Flipping the engine default would silently relax that lint for
every old plan. Flipping the template does not.

### G · When `crux-design` rejects

`crux-design` detects three causes of a partial answer and fixes only the third (its own
definition: *"Detects all three causes … fixes the third, and hands the other two to the agents
that own them"*). The skill's rule, by cause:

| cause | who owns it | what the skill does |
|---|---|---|
| compound claim | act 1 | reopens act 1; the goal is re-split, and acts 2–4 are redone against the new frame |
| a check that does not follow from the claim | act 3 | reopens act 3; `crux-verifiables` runs again against the same approved null |
| the run cannot discriminate | `crux-design` itself | takes its fix, then re-runs `crux auto check` |

**The skill never proceeds past a rejection on its own, and it never edits `crux-design`'s
verdict.** Only the PI may say "go anyway"; if they do, the skill records their sentence
verbatim in `## Guidance` via `crux auto guide` — the PI's words, on the PI's yes — so the run's
own transcript carries why. (PI, 2026-09-19.)

### H · The baseline is scored, not asserted

Spec §9: *"Setup ends by scoring the current code and recording it."* Act 5's exit is
`crux auto check` passing, which already dry-runs the scorer
(`SKILL.md:340`). The skill records the number it printed as `baseline:` rather than asking the
PI for one, and states the number back to them. Terminal hypotheses already under the anchor are
adopted as further starting observations, per §9.

## Scope — what this does not do

- **No change to any of the three agents.** Byte-identical, asserted.
- **No new `crux` verb.** The skill drives the verbs that exist.
- **No change to `closer:`'s engine default**, to `AUTO_COMPARISON_OPS`, to `auto_check_comparison`'s
  grammar, or to how a tick is derived from a number.
- **No autonomous approval.** `crux auto approve` and `crux auto run` stay the PI's.
- **Does not address spec §8's run-branch commits** — still deliberately unassigned (2026-09-18).
- **No tier-1+ validation.** That is 05.6.

## Acceptance criteria

Each is a command with an expected result. `SUITE` below means
`./crux selftest 2>&1 | grep '^  FAIL ' | grep -cv 'a stale install.sh'` → `0`.

1. `test -f skills/crux-autopilot/SKILL.md` → exit 0.
2. `bash install.sh` with `SKILLS_DIR` set to a temp dir installs `crux-autopilot` alongside
   `crux`, `crux-wiki`, `crux-cockpit` — no install.sh edit required.
3. `git diff origin/main -- agents/` → **empty**. The three agents are unchanged.
4. `python3 -c "import engine as E; print(E.auto_direction_op('max'), E.auto_direction_op('min'))"`
   → `>= <=`; `auto_direction_op('sideways')` raises `CruxError`.
5. A plan with `direction: max` whose discriminating check reads `obj.score <= -0.5` is reported
   by `crux auto check` with the `objective-op` problem naming both the direction and the
   expected operator. It is a refusal, not a warning.
6. The same plan with `>=` reports no `objective-op` problem.
7. The demo fixture `_loop_repo`'s plan still passes `crux auto check` unchanged — its
   `obj.score >= -0.5` / `direction:: max` pair already agrees.
8. `grep -c '<=' skills/crux/scaffold/templates/flight_plan.md` counts **no** occurrence inside
   the `## Verifiables` placeholder block — the operator is named by derivation, not written.
9. `grep '^closer:' skills/crux/scaffold/templates/flight_plan.md` → `closer: true`.
10. `python3 -c "import engine as E; ..."` on a plan omitting `closer:` still applies
    `check-grammar` — the engine default is unchanged.
11. A `setup-01` eval fixture scores a proposed plan against a planted key: the objective address
    is read from a check written before it, the operator agrees with direction, and a control is
    present. No model, no network, no vault read.
12. `SKILL.md` carries all five voice rules of §B as greppable lines, and names exactly
    **three asks** (frame, direction+bar, harness) and **two approvals** (null, design +
    `auto approve`). A grep for the fourteen defaulted slot names finds them in **one**
    line, not fourteen — the conversation must not re-open a defaulted slot.
13. `SUITE` → `0`, on all eight CI jobs, Windows included.
14. Suite growth: the new sections add **under 3 s** to the ~72 s base, measured on an idle main
    checkout. The number goes in the PR.
15. An existing vault written before this slice loads unchanged: `crux auto status` on
    `~/crux-autopilot-demo/cruxvault` prints the same four numbers as before the merge.
16. `ENGINE_VERSION` is still `"3.3"`.

## Backward-compat / migration

No vault-format change and no migration. One behaviour change, confined to §E: a flight plan
whose **discriminating** check uses the operator that disagrees with its own `direction` is
newly reported by `flight_plan_problems`. Such a plan is, by construction, searching against a
bar it reads backwards — the defect §9's most important line exists to prevent — so reporting it
is the point. Every plan in the repo today (the tier-0 fixture, the template once filled) already
agrees. The report is a **refusal** (PI, 2026-09-19): a plan that reads its own bar backwards
must not start.

`closer:`'s engine default is untouched, so a 05.2-era plan runs byte-identically (§F).

## Build notes

- **`skills/crux/SKILL.md` is edited**, so the five
  `skills/crux/evals/fixtures/persona-01/submissions/{clean,id-led,idle,mirror,notebook}.json`
  must be re-pinned **in the same chunk**: `agent_sha` = `shasum -a 256 skills/crux/SKILL.md`
  (**run it; never copy an old value**), plus a dated `RE-PINNED …` clause on each `_note`.
  Otherwise the persona eval returns REFUSED and the suite dies with `KeyError: 'hard'`.
- **The engine stays pure.** `auto_direction_op` and the `objective-op` check are pure functions
  on strings — no process, no git, no threads.
- **Python 3.8 is the CI floor.** No `dict | dict`, no `list[str]`, no `match`, no
  `functools.cache`.
- **`grep FAIL` on selftest output lies.** Use the `SUITE` form above.
- **Fixtures name only commands the suite already depends on** — `python3`, never `claude`.
- `CHANGELOG.md` entries go **newest-first** under `## [Unreleased]`.

Files in this skill

  • 05.0-flight-plan-and-brief.md8.8 KB
  • 05.1-git-and-workspace-layer.md17 KB
  • 05.2-driver-loop.md31 KB
  • 05.3-agents.md48.8 KB
  • 05.4-cockpit-tab.md24.5 KB
  • 05.5-setup-skill.md18.1 KB
  • 16.1-science-voice.md12.1 KB
  • 16.2-voice-enforcement.md6.1 KB
  • 17.1-openalex-client.md5.5 KB
  • 17.2-crawl-and-ranking.md5.2 KB
  • 17.3-scoping-skill.md4.4 KB
  • gui-living-tree.md4.9 KB
  • gui-v1.md11.1 KB
  • gui-wiki-tab.md21.6 KB
  • v0.5-cockpit-evidence.md19.1 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.