Fitness Config Init
Create
for a project so the review skills weigh what matters for it. A database backend should count reliability and data heavily and accessibility barely at all. A public website should count accessibility first. This skill works out which kind of project it is looking at, proposes weights from a matching profile, and saves them only after the user has seen the proposal.
The weights themselves live in
references/purpose-profiles.md
and in the resolver. This file never states a weight. Always take numbers from the resolver output or the profile table.
References
references/purpose-signals.md
: what to read in the fast scan, the 40-file budget, signals per archetype, and what high, medium and low confidence mean.
references/purpose-profiles.md
: the six archetype profiles, the rules for adjusting them, and typical rationale for each.
Read both before step 3.
Resolver
Every config read and write goes through the resolver CLI. Never load
yourself and never write it with a file tool.
bash
python3 "${CLAUDE_SKILL_DIR}/../../scripts/fitness-config.py" <command>
is this skill's directory; the resolver ships two levels up in the plugin's
. If your agent does not expand the variable, substitute the directory containing this
.
Run every resolver command from the
anchor: the git top-level of the target (
git -C <target> rev-parse --show-toplevel
), or the target itself when it is not in a git repository. Pass the target relative to the anchor. Set
PYTHONDONTWRITEBYTECODE=1
so running the resolver does not leave
beside it.
| Purpose | Command |
|---|
| Starting config (baseline) | init --path <target> --dry-run
|
| Current values of an existing config | baseline JSON piped to init --path <target> --from - --dry-run
|
| Check a proposal, get its fingerprint | init --path <target> --from - --dry-run
(proposal JSON on stdin) |
| Save a reviewed proposal | init --path <target> --from - --expect <fingerprint>
(same JSON on stdin) |
| Confirm what applies after saving | |
Workflow
Step 0: Target and probe
- The target is the path argument, or the current folder. Print it as the first line of output: .
- Find the anchor. If there is no git repository, say "No repository found; ancestor configs not considered."
- Run
init --path <target> --dry-run
. It writes nothing. Relay its header lines verbatim (, and any chain lines) and keep the canonical JSON block as the baseline. The baseline is the built-in starting config at the repository root, or the merged parent configs for a subfolder.
- If the probe exits 2 saying the target is not a folder or does not exist, stop and tell the user; do not use degraded mode.
- If the probe fails otherwise (no , the path did not expand, the resolver errors), switch to degraded mode: read
${CLAUDE_SKILL_DIR}/../../fitness-config.example.json
as the baseline, label it "example file (degraded)", and continue through step 5 printing the proposal for manual use. Degraded mode never saves. If the example file is also unreachable, stop and say why.
- Existing config (skip in degraded mode). The baseline ignores a already at the target, but the step 5 diff compares against it. So that the table and the diff agree, pipe the baseline JSON to
init --path <target> --from - --dry-run
(writes nothing):
- : no config yet. The table has no current column.
- : each diff line gives a current value (); every path not listed equals the baseline. Add a current column to the table in step 4.
- : the existing file equals the baseline. Say so; no current column.
- : say the existing file is not valid JSON; the current column reads .
- : relay the error and stop; nothing can be saved there.
Step 1: Evidence mode
- fast (default): a read-only scan of at most 40 files.
- full: runs on the target first, then the fast scan.
Take the mode from the argument only if it is exactly
or
. Otherwise use the request text: it means full only if it says "full review", "full mode" or "run review-full" and does not also say "fast" or "quick"; it means fast if it says "fast" or "quick" and nothing about full. In every other case, ask
Evidence mode: fast scan or full review? [fast]
and treat Enter as fast. Never upgrade to full on your own.
Before a full review, warn and wait for a yes: "A full review runs every review skill and writes
into the project. Continue? [y/N]". Anything other than
or
falls back to fast.
Step 2: Gather evidence
- Fast: follow the scan order in
references/purpose-signals.md
. Stay within 40 file reads. Do not run project code or use the network. Do not change any file.
- Full: run the skill with its scope set explicitly to the target folder (never the default of pending changes), then do the fast scan as well. Read afterwards:
- If its line shows that only pending changes were reviewed (not the target folder), drop all full review evidence and tell the user: "The full review only covered pending changes, so its results were not used."
- If a domain failed or has no parsable row, use fast scan evidence for that domain only and say so. The other domains keep their full review evidence.
Each evidence item is a path that a read or list tool returned, a short note on what it shows, and its source (
or
).
Step 3: Classify the purpose
Classify as one archetype from
references/purpose-profiles.md
,
, or
, with a confidence level from
references/purpose-signals.md
. Show the purpose in plain words, the archetype, the confidence and the evidence list.
A purpose stated in the request is the user's answer. If the request already says what the project is ("it's my shell tool", "for this public website", "our payments API"), map it to an archetype and set the confidence to
. Show the classification line with
confidence: user-confirmed (stated in request)
and go on to step 4 without asking. The scan still runs, because moves away from the profile need evidence. If the scan points strongly at a different archetype, say so in one line, but use the stated purpose. Ask only when the statement fits no archetype or fits two.
- high or user-confirmed: go on to step 4.
- medium or mixed: ask "What is the primary purpose of this project?" and offer the archetypes. For a mixed repository, add that a subfolder can get its own config later by running this skill on that folder. Do not create one.
- low or unknown: ask the same question once. With no answer, say "Kept baseline: not enough evidence to tune." and propose the baseline unchanged, with no reasons.
If the user corrects the classification, use their answer without argument.
Step 4: Propose
-
Start from the archetype's row in
references/purpose-profiles.md
. The profile is the reference point for judgment (ADR-007): the classification evidence from step 3 justifies the whole row, so a value taken unchanged from the profile needs no evidence of its own.
-
Adjust using this project's evidence, following the rules in that file: no more than 4 points per domain from the profile, a cited reason for every move away from the profile, whole numbers of at least 1, total of 100. Full review results only lower domains that do not apply; a low score never raises a weight.
-
Build the complete proposal: the baseline JSON with the
section replaced. Keep
,
and
from the baseline unless the evidence shows higher stakes (payments, credentials, personal data). Change a threshold only with a stated reason citing that evidence, and add a row for it to the table below. For an ordinary project, keep the starting thresholds and say there is no stakes signal to change them. The status bands must cover every score from 1 to 10 once, with no gap or overlap; the security cutoff stays between 1 and 10.
-
Print the rationale table, one row per weight in resolver order, then one row per changed threshold. Add the current column only when step 0 found an existing config:
| key | current | baseline | profile | proposed | reason |
|---|
| existing file | from baseline | from profile row | from proposal | see below |
The reason column has exactly one entry per row. Check these in order:
- proposed differs from profile:
profile ±N: <evidence path> <what it shows>
, where N is at most 4, or for a change the user asked for. This is the only kind of reason that needs its own evidence, even when the move lands back on the baseline value.
- proposed equals profile and differs from baseline: . The classification evidence from step 3 covers it.
- proposed equals profile and baseline: .
With no profile (unknown, kept baseline), leave the profile column as
and every reason
. For a threshold row, the profile column is
and the reason cites the stakes evidence. Keep each reason under about 100 characters. Count and show the moves away from the profile, for example
Moves from profile: 3 (each within 4)
.
-
Show the total. Apply any change the user asks for ("raise X, take it from Y"), rebalance to 100, and print the table again.
The rationale is printed only. It is never written into the config file.
Step 5: Check the proposal
Pipe the proposal JSON to
init --path <target> --from - --dry-run
. This writes nothing.
- Relay the and lines verbatim and show the canonical JSON block exactly as printed. The value is the fingerprint.
- : show each error line, fix the proposal, and run the check again.
- : ask "Save this as
<target>/fitness-config.json
? [y/N]".
- : a config already exists. Show every diff line the resolver printed (, then ); each matches the current column of the table. Then ask "Overwrite
<target>/fitness-config.json
? [y/N]".
STATUS: existing-malformed
: the current file is not valid JSON, so there is no diff. Say so, show the proposal, and ask the same overwrite question.
- : the current config already equals the proposal. Say there is nothing to save and skip to step 7.
STATUS: existing-not-a-file
: something other than a file (such as a folder) is at <target>/fitness-config.json
. Relay the error and stop; nothing can be saved there until the user moves it.
Step 6: Save
Only an answer of
or
(any case) is a go-ahead. Anything else, including an empty answer, means No: say nothing was written and stop.
-
After a go-ahead for
, pipe the
same JSON to
init --path <target> --from - --expect <fingerprint>
with the fingerprint from step 5.
-
After a go-ahead to overwrite (
or
), pipe the
same JSON to
init --path <target> --from - --expect <fingerprint> --force
. The resolver replaces the file atomically and puts the old bytes back if the check after writing fails.
-
-
: the file already held this config and was not touched. Go to step 7.
-
STATUS: fingerprint-mismatch
: the JSON changed since the check. Run step 5 again and ask again.
-
: a config appeared since the check. Stop; nothing was written.
-
STATUS: verify-failed-rolled-back
or any other failure: report "not written" with the resolver's message.
Pass
only after the user said yes to the overwrite question for this fingerprint. Never save a proposal the user has not seen and approved.
Step 7: Summarize
- Run and relay its line verbatim.
- If that line names more than one file, say: "This config applies to and below. Parent configs still apply where this file does not set a value."
- Repeat the rationale table from step 4 exactly as shown.
- Suggest the next step: run to get a fitness report with the new weights.
Rules
- Nothing in the project changes before step 6, except in full mode after the user agreed.
- Every weight shown comes from the resolver output or
references/purpose-profiles.md
.
- Every move away from the profile, and every threshold change, cites evidence that exists in the target.
- Never create per-folder configs the user did not ask for.