From citadel
Autonomous quality improvement loop. Scores a target against a rubric, selects the highest-leverage axis, attacks it, verifies, documents, and loops. No pre-planning between iterations — each loop re-scores from scratch.
How this skill is triggered — by the user, by Claude, or both
Slash command
/citadel:improveThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
/improve is a self-directed quality loop. It evaluates a target (a product, repo,
/improve is a self-directed quality loop. It evaluates a target (a product, repo, or specific component) against a rubric, selects the single highest-leverage improvement, executes it with full verification, documents what was learned, and repeats. It does not pre-plan multiple loops. Each iteration re-scores from scratch because iteration N changes the landscape in ways that make pre-planned iteration N+1 obsolete.
/improve {target} # Loop until plateau or all axes >= 8.0
/improve {target} --n=3 # Run exactly N loops then stop
/improve {target} --axis={name} # Force-attack a specific axis (skips scoring)
/improve {target} --score-only # Score and report, no attack
/improve {target} --continue # Resume from campaign state (used by daemon)
/improve citadel # Targets the entire Citadel product
target is a slug that maps to .planning/rubrics/{target}.md.
If no rubric exists, run Phase 0 first.
When invoked with --n or --continue, improve operates in campaign mode and
maintains a campaign file that daemon can attach to. This is what makes improve
daemonizable -- daemon restarts sessions, improve picks up where it left off.
.planning/campaigns/improve-{target}.mdCreated automatically on the first invocation with --n. Format:
---
version: 1
id: "improve-{target}-{ISO-date-slug}"
status: active
type: improve
target: {target}
total_loops: {n or "unlimited"}
completed_loops: 0
current_level: {rubric level from frontmatter}
estimated_cost_per_loop: 12
started: "{ISO timestamp}"
---
# Campaign: Improve {target}
Status: active
Direction: Improve {target} for {n} loops at Level {level}
## Loop History
| Loop | Axis Attacked | Outcome | Score Movement |
|------|---------------|---------|----------------|
(populated after each loop)
## Continuation State
next_loop: 1
last_scorecard_log: (none)
last_outcome: (none)
phase_within_loop: not-started
level_up_triggered: false
On each loop start (Phase 1):
phase_within_loop: scoringOn selection (Phase 2):
phase_within_loop: selected-{axis_name}On attack start (Phase 3):
phase_within_loop: attacking-{axis_name}On verification (Phase 4):
phase_within_loop: verifyingOn loop completion (Phase 5/6):
completed_loopsnext_loop, last_scorecard_log, last_outcomephase_within_loop: not-startedOn exit (all loops complete):
status: completed.planning/campaigns/completed/On level-up trigger:
status: level-up-pendinglevel_up_triggered: trueOn abort (security failure, unrecoverable regression):
status: parked--continue flagWhen invoked as /improve {target} --continue:
.planning/campaigns/improve-{target}.md/improve {target} --n=N."status is not active: error -- "Campaign is {status}. Cannot continue."completed_loops and total_loops:
completed_loops >= total_loops: set status to completed, exitphase_within_loop:
not-started: begin next loop from Phase 1scoring or selected-*: restart the current loop from Phase 1
(scoring is cheap to redo and avoids stale partial state)attacking-*: restart the current loop from Phase 1
(attacks are not resumable mid-execution; re-score catches any partial work)verifying: restart the current loop from Phase 1
(verification depends on complete attack output)last_scorecard_log to load the previous loop's scorecard for delta comparisonDesign note: --continue always restarts the current loop from Phase 1 if it was
interrupted. This is intentional. Improve re-scores from scratch every loop anyway,
so partial state from a crashed mid-loop session is worthless. The campaign file's
value is tracking which loop number we're on and whether the campaign is still active,
not mid-loop progress.
Run only when .planning/rubrics/{target}.md does not exist.
.planning/research/ if available/research-fleet to survey comparable products if no research exists.planning/rubrics/{target}.mdFor Citadel: rubric already exists at .planning/rubrics/citadel.md. Skip Phase 0.
Score every axis in the rubric. No shortcuts. No cached scores from the previous loop.
For each axis, execute the programmatic verification steps from the rubric. These produce objective pass/fail or numeric results. A programmatic failure caps that axis at 5 regardless of evaluator scores.
Record raw results: which checks passed, which failed, what the failure was.
Execute structural checks from each axis's verification spec. These are computable but require reading the repo state:
Spawn three evaluator agents in parallel. Each receives:
Each evaluator scores independently. They do not see each other's scores.
Collect all three score sets. For each axis:
needs-refinementRationale for minimum: a low score from any single evaluator represents a genuine unresolved problem. Averaging would hide it. Gaming the minimum requires satisfying every evaluator simultaneously, which is structurally much harder than gaming a median.
needs-refinement axes are logged but still scored. Do not halt on evaluator disagreement — disagreement is data, not failure.
Axis | A | B | C | Prog | Final | Delta | Flag
--------------------------|----|----|----|----- |-------|-------|-----
security_posture | 7 | 8 | 6 | PASS | 6.0 | | ← min(7,8,6)
onboarding_friction | 4 | 3 | 5 | FAIL | 3.0 | cap | ← min(4,3,5), capped
documentation_accuracy | 6 | 6 | 7 | PASS | 6.0 | | ← min(6,6,7)
...
Final = min(A, B, C), then apply programmatic cap if active. Delta = (current score - previous loop score). Empty on loop 1.
Choose the single axis to attack this loop.
Selection formula:
score(axis) = (10 - current_score) × weight × effort_multiplier × recency_penalty
effort_multiplier: low = 1.0, medium = 0.7, high = 0.4recency_penalty: 0.5 if this axis was attacked in the previous 2 loops, otherwise 1.0Estimate effort for each axis based on the gap and category:
If --axis flag was set, skip selection and attack the specified axis.
Announce the selection:
Selected: {axis_name} (score: {n}/10, weight: {w}, effort: {e}, selection score: {s})
Rationale: {one sentence on why this axis now, not another}
Execute the improvement. Dispatch strategy depends on the axis category.
ISOLATION MANDATE: When dispatching to /experiment, /fleet, or /research-fleet,
always use the Agent tool with isolation: "worktree". This is non-negotiable. The
improve orchestrator's context window holds the rubric, scorecard, and loop state. If
fleet or experiment run inline (same context), they compete for the same window and
the session dies at nesting depth 3-4. Sub-agents in worktrees get their own context
windows. The orchestrator only receives their HANDOFF results.
technical axes (test_coverage, hook_reliability, api_surface_consistency):
/experiment for measurable improvements with before/after comparisonnode scripts/run-with-timeout.js 300 node scripts/test-all.js as the verification oracledocumentation axes (documentation_coverage, documentation_accuracy):
experience axes (onboarding_friction, error_recovery, command_discoverability):
positioning axes (differentiation_clarity, competitive_feature_coverage):
/research to verify current competitive landscape is accuratepresentation axes (demo_page_effectiveness, readme_quality, visual_coherence):
/live-preview or /qa to verify visual changes render correctlysecurity axes (security_posture):
When the attack involves trying multiple approaches (e.g., three worktree variants):
APPROACH COMPARISON: [approach A] vs [approach B] — winner: [A] because [reason]This builds institutional memory that loop 4 can read when facing a similar choice.
After the attack, re-score only the targeted axis (not full re-score — that's expensive).
Run the four verification tiers from the rubric for the targeted axis:
/do command.
onboarding_friction, error_recovery, documentation_accuracy, command_discoverabilityPASS {wall_time} or FAIL at step {n}: {what broke}visual_coherence, api_surface_consistency)Regression check (run on all axes, not just targeted):
On abort: revert the changes, log the failure, and treat it as a "no improvement this loop" (still documents, still loops).
On pass: commit the changes with a descriptive message.
Write the loop log. Always. Even on abort.
Log path: .planning/improvement-logs/{target}/loop-{n}.md
# Improvement Loop {n}: {target}
> Date: {ISO date}
> Loop: {n}
> Selected axis: {axis_name}
> Outcome: improved | no-change | aborted
## Scorecard
| Axis | Loop {n-1} | Loop {n} | Delta |
|------|------------|----------|-------|
| {axis} | {prev} | {current} | {delta} |
...
## Attack summary
**What was changed:** {description of changes}
**Approach taken:** {the method — experiment / direct edit / research+update}
**Files modified:** {list}
{If multiple approaches were tried:}
**APPROACH COMPARISON:** {approach A} vs {approach B}
Winner: {A} because {reason}
Loser archived: {why it lost}
## Verification results
**Programmatic:** {PASS/FAIL} — {what ran}
**Structural:** {PASS/FAIL} — {what was checked}
**Perceptual:** {score}/10 — {evaluator B's one-line rationale}
**Behavioral:** {PASS {wall_time} | FAIL at step {n}: {reason} | SKIPPED — axis does not affect user path}
{If aborted:}
**Abort reason:** {what regressed, by how much}
## Proposed axis additions
{If any evaluator proposed a new axis this loop:}
PROPOSED AXIS: {name}
Rationale: {why this emerged}
Category: {category}
Weight: {proposed}
Draft anchors: 0=... / 5=... / 10=...
{If none:} None proposed this loop.
All proposals are written to `.planning/rubrics/{target}-proposals.md`. They are never written
directly to the live rubric. Human approval is required to move a proposal into the live rubric.
## What was learned
{2-3 sentences: what the improvement revealed about the product, what future loops should know}
Exit conditions (check in order):
--n flag was set and N loops have completed: exit, report scorecardOn Level-Up: do not exit. Escalate. See Level-Up Protocol section.
On ceiling (all >= 8.0): report the final scorecard and recommend a Level-Up run to re-anchor for the next quality tier.
On normal loop: return to Phase 1. Re-score everything from scratch. The previous scorecard is reference only -- the new one is ground truth.
Campaign mode exit handling:
In campaign mode, update the campaign file on every exit:
status: completed, move to completed/status: completed, move to completed/status: level-up-pending (daemon will pause, not retry)status: parkedstatus: parked with reasonstatus: paused (daemon will see non-active status and stop)Triggers when distribution saturation is detected: no axis improved > 0.5 in the last 2 consecutive loops, no programmatic cap is active, and at least 3 loops have completed. This is not failure — it means the current rubric has been extracted to its ceiling. The next gains require re-imagining the ceiling itself.
Step 1: Freeze the snapshot
Write .planning/rubrics/{target}-level-{n}-final.md where {n} is the current level (1 for a first-time level-up):
# {target} Rubric — Level {n} Final State
> Date: {ISO date}
> Loops completed at this level: {count}
> Triggered by: distribution saturation
## Final Scorecard
| Axis | Final Score | Ceiling (10) |
|------|-------------|--------------|
| {axis} | {score} | {rubric's current 10 anchor} |
## Axes at ceiling (>= 9.0)
{list — these axes' 10 anchors become Level {n+1}'s 5 anchors}
## Axes that plateaued below 9.0
{axis}: stuck at {score} — {why it plateaued: was it a measurement limit, a build limit, or a rubric calibration issue?}
Step 2: Write proposals
For each axis, propose a Level {n+1} re-anchoring:
For axes that plateaued: propose whether to re-anchor, replace with a more measurable proxy, or retire.
Automatically include the three process axes if not already in the rubric:
decomposition_quality — did the attack correctly diagnose before executing?scope_appropriateness — was the change proportional to the gap?verification_depth — did verify actually test what changed?Write everything to .planning/rubrics/{target}-proposals.md:
# {target} Level {n+1} Proposals
> Generated: {ISO date}
> Level {n} final state: .planning/rubrics/{target}-level-{n}-final.md
## Re-anchored axes
### {axis_name}
Current 10: "{current 10 anchor text}"
Proposed Level {n+1} anchors:
- 0: {what failure looks like from the new floor}
- 5: {what the current 10 looks like from here — the new baseline}
- 10: {what was inconceivable before reaching the current level}
## Proposed new axes
{any emergent axes that only became visible at this quality level}
## Axes proposed for retirement
{axes that hit a structural ceiling with no meaningful level 2 version}
Step 3: Halt -- human approval required
Do not self-approve. Do not continue looping.
In campaign mode: update the campaign file:
status: level-up-pendinglevel_up_triggered: trueawaiting: human approval of level-up proposalsReport:
The loop resumes only when the human edits the live rubric with approved proposals
and sets the campaign status back to active. All loop logs are preserved.
Level {n+1} loops continue incrementing the loop number (they do not reset to 1).
Step 4: Historical context for future evaluators
When the loop resumes after a level-up, every evaluator in Phase 1c receives:
This prevents evaluators from re-discovering the old floor and calling it good.
Rubric doesn't exist: run Phase 0 and halt until human approval. Never improvise a rubric mid-loop.
Evaluator agents disagree by > 3 points on an axis: log it as needs-refinement, use the minimum score (the minimum is already the final score — this fringe case just flags the disagreement for rubric review), and add a note in the loop log. Do not halt. Proposing a rubric refinement is logged as a "proposed axis addition" even when it's an anchor precision fix, not a new axis.
Programmatic checks can't be automated for an axis: note this explicitly. Use structural + perceptual scores only. Cap the maximum achievable score at 8 (not 10) for axes without programmatic verification.
Attack produces no measurable improvement: document it as a "no-change" loop with the reason. Treat the axis as if it were attacked in the previous loop (applies recency penalty next loop to force the system to try a different axis).
Targeted axis doesn't improve despite changes: check if the rubric's anchors are miscalibrated. If the work done clearly satisfies the anchor description but the score didn't move, the anchors may need refinement. Log a proposed refinement.
Target has no prior loop logs (loop 1): all delta fields are empty. That's expected.
Security axis fails programmatic: treat as a blocking issue. Do not loop. Halt and report. Security is the floor, not one axis among equals.
--continue with no campaign file: error message, suggest starting with --n.
--continue with status level-up-pending: do not resume. Report: "Campaign is waiting for human approval of level-up proposals at .planning/rubrics/{target}-proposals.md. Approve and set campaign status to active to resume."
--continue with status completed: do not resume. Report final scorecard summary.
Campaign file exists but --n invoked: read existing campaign. If active, resume it (treat as --continue). If completed/parked, create a new campaign with incremented slug.
.planning/rubrics/{target}-proposals.md only. Human approval is required to move anything into the live rubric. This cannot be bypassed.status: level-up-pending, not parked or active. Daemon recognizes this specific status and pauses cleanly instead of retrying or stopping.Before starting an improvement loop, verify contextual appropriateness:
State what's about to happen:
--continue: "Resuming improve campaign at loop {n}/{total}. ${spent} spent so far."--score-only (no file modifications)Red actions require explicit confirmation regardless of trust level.
Before starting, check whether improve is warranted:
/review first--n=1 on a target already scoring > 8.0 on all axes: suggest specific axis with --axisRead trust level from harness.json:
--score-only and --n=1 only. Block --n > 1 and unlimited loops. Output: "Start with --score-only to see where you stand, or --n=1 for a single improvement loop."--n=5. Confirm for higher counts or unlimited.---HANDOFF---
- Target: {target} — Loop {n} of {n_total or "∞"} — Level {current_level}
- Outcome: {improved | plateau | ceiling | aborted | n-complete | level-up-triggered}
- Score movement: {axis} {before} → {after} (+{delta})
- Behavioral simulation: {PASS {wall_time} | FAIL | SKIPPED}
- Proposed rubric additions: {count} — written to .planning/rubrics/{target}-proposals.md
- Loop log: .planning/improvement-logs/{target}/loop-{n}.md
- Reversibility: amber -- each loop commits separately, revert individual loops with git revert
- Next recommended axis: {axis_name} (if not exiting)
- Level-up snapshot: .planning/rubrics/{target}-level-{n}-final.md (if level-up triggered)
---
npx claudepluginhub roseonlineownz-lab/citadelScans a codebase for architectural friction, presents candidates as a visual HTML report with before/after diagrams, and guides you through deepening refactors.