Crux Daemon · 2. The config wizard

crux-config-wizard init writes your workspace's CLAUDE.md and AGENTS.md for you, from versioned rule fragments that ship inside the binary, and then keeps telling you when they have gone stale. That is the whole idea. This chapter is a how-to: run it, understand what it wrote, and know what happens on the day it and your file disagree.

Read this before the configuration reference. The two are unrelated surfaces with confusingly similar names, and §2.11 says so explicitly so you do not go looking for CORECRUXD_ variables in here.

2.1 The problem it solves

Every coding agent reads a CLAUDE.md or an AGENTS.md at the start of a session and treats it as standing instruction. That file is therefore the single highest-leverage configuration in the workspace, and in practice it is also the worst-maintained one: hand-written, copied between repositories, drifting from whatever the team actually agreed, and impossible to audit because nobody can say which version of which rule a given session actually loaded.

The wizard turns that file into build output. Rules live as profile fragments, small markdown files with TOML frontmatter, carrying a name, a version and a sort order (profile.rs:32). They are compiled into the binary with include_str! (profile.rs:95), so the tool is self-contained and works from any directory. You choose which fragments you want; the wizard composes them into the target files, records the choice in a committed file, and can afterwards tell you at any moment whether the files on disk still match.

Three things follow, and they are the reason to run it on day one rather than later:

  • Reproducible. A new clone gets the same guardrails with one command, not by someone remembering to copy a file.
  • Versioned. Each fragment carries a version. When a rule is improved upstream, every workspace pinned to the old version is told, by name, on the next session boot (drift.rs:104).
  • Reviewable. A rule change arrives as a diff in a managed block, not as an untracked edit to a file nobody reads.

Running it later is harder than running it first, because by then you have hand-written prose that says roughly what a managed fragment says, and the wizard will start flagging the duplication (§2.7).

2.2 Getting the binary

crux-config-wizard is a workspace member of the Crux repository (Cargo.toml:20) and declares a binary of the same name (crates/crux-config-wizard/Cargo.toml:13). Every crate in this workspace sets publish = false (Cargo.toml:52), so there is no registry install; build it from source.

git clone https://github.com/CueCrux/Crux
cd Crux
cargo build --release -p crux-config-wizard
# binary at target/release/crux-config-wizard

It is a small, dependency-light crate and does not require the daemon to be running, or installed, or reachable. Every operation in this chapter is filesystem-only.

One global flag applies to every subcommand: --workspace <path> operates on a directory other than the current one (cli.rs:20). Without it, the wizard uses . (main.rs:29).

2.3 The first run, prompt by prompt

cd /path/to/your/workspace
crux-config-wizard init

init is the only interactive command. It requires a TTY on both stdin and stdout (main.rs:136); without one it refuses with no TTY detected; pass --non-interactive --profiles=<csv> (main.rs:117) rather than guessing.

Step 1; it checks you have not already initialised. If .crux/agent-profile.toml exists, init stops with exit code 2 and the message config already exists at …; use 'regenerate' or 'add/remove' instead. (commands.rs:54). init is a first-run command and refuses to be a second-run one.

Step 2, one yes/no prompt per bundled profile, in order. The prompt text is built from the fragment's own frontmatter (interactive.rs:20):

Enable 'memory-practices' (v1, risk=low)?
  Crux daemon memory + retrieval discipline.

The three things each prompt is telling you: which rule set this is, which version of it you are pinning, and its risk class, an informational label on how consequential the rules are, not an access control. Every prompt defaults to yes (interactive.rs:26), so pressing Enter through the list enables everything. You are prompted for all thirteen bundled profiles, sorted by their order field (profile.rs:125), which is also the order they will appear in the composed file.

Step 3; it writes. Two files are composed, CLAUDE.md then AGENTS.md (commands.rs:83), and the choice is saved to .crux/agent-profile.toml. You get a line per file:

CLAUDE.md: wrote=true, sections_added=10
AGENTS.md: wrote=true, sections_added=10
Initialised 10 profile(s) for /path/to/your/workspace.

Step 4; it offers to install the Claude Code hooks. By default init hands off to a co-installed corecruxctl to wire the banner, observe, cost and scratchpad-survival hooks (main.rs:46), prompting first when it is interactive. It searches PATH, then ~/.local/bin, then $CARGO_HOME/bin (hooks_bridge.rs:33), and runs corecruxctl hooks install --user (hooks_bridge.rs:73). This step is best-effort and cannot fail your run. A missing or erroring corecruxctl prints a one-line "run it yourself" note and nothing else; the profiles are already written, and the hooks outcome never changes the exit code (main.rs:77). Pass --no-hooks to skip it entirely (cli.rs:41).

2.3.1 The non-interactive form

crux-config-wizard init --non-interactive --profiles=all
crux-config-wizard init --non-interactive --profiles=memory-practices,token-conservation

--non-interactive without --profiles is an error: --non-interactive requires --profiles=<csv> (or 'all') (main.rs:106). An unknown name in the list is an error before anything is written (commands.rs:66).

--profiles=all does not mean all bundled profiles. It expands to DEFAULT_PROFILES (main.rs:108), which is a list of eleven names (lib.rs:40), while thirteen are bundled (profile.rs:95). Two are left out: code-minimalism and token-conservation. If you want either, name it explicitly or add it afterwards. The interactive path has the opposite behaviour and offers all thirteen.

2.4 The thirteen bundled profiles

Eleven of the thirteen target both CLAUDE.md and AGENTS.md. Two are deliberately single-target: claude-5 targets claude_md only and agent-harness-parity targets agents_md only, because they are a matched pair. Claude Code's own system prompt already supplies response-shape and tool-batching behaviour, so claude-5 omits it to avoid the duplicated-instruction cost; non-Claude harnesses get no such support, so agent-harness-parity states it explicitly for AGENTS.md. Pairing either with the other file would reintroduce exactly the duplication the split exists to remove. claude-5 also declares conflicts_with = ["token-conservation"]. order is the sort position in the composed file, low first. risk is the fragment's self-declared risk class, an informational label (profile.rs:44); nothing in the wizard gates on it.

ProfilevorderriskIn --profiles=all
memory-practices110lowyes
token-conservation120lowno
claude-5120lowyes
agent-harness-parity121lowyes
execplan-discipline230lowyes
code-grounding140lowyes
code-minimalism241lowno
scratchpad-survival145lowyes
boot-banner147lowyes
pre-deploy-gate150mediumyes
eu-ai-act170highyes
audit-soc2180mediumyes
workspace-cuecrux390lowyes

Source: profile.rs:95 for the bundled set, lib.rs:33 for the default set, and each fragment's own frontmatter for its version, order and risk class.

memory-practices (memory-practices.md:2) gives the agent a session-boot ritual against the daemon, check sync status, check for updates, pull the current playbooks, plus the two rules that stop a memory-backed session going wrong: pass a token_budget on every retrieval call, and put durable content in the fact store or in files rather than in chat. It also fixes the entity-prefix and required-key conventions for store_fact, so that what one session writes another session can find. Enable it if your agents talk to a Crux daemon at all. It is the base layer the other profiles assume.

token-conservation (token-conservation.md:2) is output discipline: keep responses short, cap milestone summaries, batch tool calls that have no data dependency, write audit tables and benchmark results to files and reference the path rather than pasting them into chat. Enable it if your sessions are long. It exists because output-token exhaustion is the failure that ends a session with no warning and no partial result.

execplan-discipline (execplan-discipline.md:2) tells the agent when a task is big enough to need a written plan, where the plan lives, which sections it must have, and how to execute it milestone by milestone, updating progress, logging decisions with a commit_sha, and storing a gate fact per milestone. It also makes the work board authoritative, so a new session resumes existing work instead of starting a parallel plan. Enable it if work in this repository routinely spans more than one sitting.

code-grounding (code-grounding.md:2) is the anti-hallucination rule set: a claim naming a function, file or flag carries a file:line reference or a commit_sha; benchmark results carry their corpus name; a remembered fact about the codebase is re-verified against the codebase before you act on it. Enable it if agents in this repository make assertions anyone will rely on.

claude-5 (claude-5.md:2) sets response shape for the Claude 5 generation, and it replaced token-conservation's fixed numeric output caps, which is why the two declare a conflict. It covers verbosity, agentic narration, deliverable length, task scope, delegation and self-correction. It deliberately carries no re-check or re-verify instruction and no token ceiling: self-verification is already default behaviour on this model generation, so verification prompts compound into over-verification, and visible length responds to prose instruction rather than to a numeric cap. It targets CLAUDE.md only.

agent-harness-parity (agent-harness-parity.md:2) is the AGENTS.md counterpart to claude-5. Claude Code's own system prompt supplies response-shape, tool-batching and memory-staleness behaviour natively, so claude-5 omits them to avoid a duplicated-instruction cost. Other harnesses get no such support, so this profile states them explicitly. It targets AGENTS.md only, and pairing it with claude_md would reintroduce exactly the duplication the split removes.

code-minimalism (code-minimalism.md:2) governs how much code gets written: a ladder from "does this need to exist" down to "the minimum that works", a rule to fix the root cause rather than the reported symptom, an explicit list of things never traded for a shorter diff (validation, error handling, security controls, accessibility, anything the user actually asked for), and a convention for marking deliberate shortcuts so they can be found later. Enable it if you are reviewing a lot of agent-written code. It is one of two profiles --profiles=all will not give you; token-conservation is the other.

scratchpad-survival (scratchpad-survival.md:2) addresses a specific and expensive failure: the agent harness puts temporary files in a session-scoped directory that is garbage-collected when the session ends, so a benchmark result or a generated dataset written there is simply gone next session. The profile makes durable output go to a durable path, and documents the archive command and the automatic backstop. Enable it if sessions hand work to each other.

boot-banner (boot-banner.md:2) documents the three-channel session-boot banner, a persistent statusline that costs no model tokens, a terse agent brief that does enter context, and a first-reply card that appears only when something needs attention, along with the environment switches for each and the rule that source-checkout drift must not be presented as deployed-binary drift. Enable it if you have the Crux hooks installed, because otherwise the agent will misread the banner it is being handed.

pre-deploy-gate (pre-deploy-gate.md:2) is a preflight checklist that must pass before a production deploy: migrations present and contiguous, required environment present in the target rather than assumed from local, disk and memory headroom checked, long-running jobs started so they survive a terminal detaching, deploys through the tracked deploy command rather than a bare build, a smoke probe immediately after, and a captured incident fact when something fails. Enable it if agents in this repository can reach production.

eu-ai-act (eu-ai-act.md:2) is the engineering scaffolding, risk classification per plan, PII stored private, automatic record-keeping, authorship attribution in commits and pull requests, explicit human consent for destructive actions, and consequence prediction before high-risk ones, organised against Articles 9, 10, 12, 13, 14 and 15 of Regulation 2024/1689. Its own opening line states the boundary and this chapter repeats it: it is engineering best practice, not a legal opinion, and conformity assessment for any specific deployment remains the operator's. Enable it if you want the technical shape of that posture in place; do not enable it and conclude you are compliant.

audit-soc2 (audit-soc2.md:2) is general audit hygiene: commit_sha on every decision, one write-agent per tree, benchmark results that carry enough provenance to re-run, retention windows stated per artefact class, and author-reviewer separation preserved in commit metadata. Enable it if someone will one day ask you to reconstruct why a change was made.

workspace-cuecrux (workspace-cuecrux.md:2) is monorepo-specific: plan paths, daemon endpoints, the work board, the live-session coordination protocol, container base-image policy, and the cross-session handoff tools. Its own description says it is CueCrux-internal and should only be enabled inside that monorepo. It is nevertheless in DEFAULT_PROFILES, so --profiles=all will enable it in your workspace too (lib.rs:33). If you are not inside the CueCrux planning monorepo, crux-config-wizard remove workspace-cuecrux immediately after init, or name your profiles explicitly instead of using all. The paths it references will not resolve for you and the agent will act on them anyway.

2.5 What the composed file looks like

The composer is deliberately line-oriented; it does not parse markdown, it scans for marker lines (compose.rs:8). Everything it manages sits between a matched pair of HTML comments:

<!-- BEGIN-CRUX-MANAGED:memory-practices v1 -->
## Crux Daemon Memory Practices

… the fragment body, verbatim …
<!-- END-CRUX-MANAGED:memory-practices -->

The begin marker carries the profile name and the version it was rendered from (compose.rs:307); the end marker carries only the name (compose.rs:315). Between them the fragment body appears exactly as it is in the source file, the composer applies no transformation, on the principle that the fragment file is the contract (compose.rs:319).

Everything else in the file is a free span, and this is the part that matters for your own writing:

SpanWhat it isWhat regenerate does to it
FreeAny text outside a matched marker pair, before, between or after managed sectionsPreserved verbatim, byte for byte
ManagedText between BEGIN-CRUX-MANAGED:<name> and END-CRUX-MANAGED:<name>Replaced from the bundled fragment

Four more behaviours are worth knowing before you edit the file by hand.

Managed sections stay where they are. On a re-compose the wizard walks the existing spans in file order and substitutes in place (compose.rs:131). If you moved a managed block to the top of the file, it stays at the top. Only sections that are missing get appended, and those are appended in order (compose.rs:150).

Disabling a profile deletes its section. A managed span whose profile is no longer enabled is dropped entirely on the next compose (compose.rs:142). This is what remove relies on. Anything you wrote inside those markers goes with it, see §2.12.

Unbalanced markers are a hard error, not a repair. A nested BEGIN, an END whose name does not match the open BEGIN, an END with no BEGIN, or an unclosed BEGIN all abort the compose with the offending line number and change nothing (compose.rs:359, compose.rs:376, compose.rs:383, compose.rs:393). If you delete half a marker pair by accident, the wizard stops rather than guessing where the section ended.

Writes are atomic and skipped when nothing changed. The composed text is compared with what is on disk and only written if it differs (compose.rs:168), through a temporary file that is fsynced and renamed (compose.rs:421). A second regenerate reports wrote=false and leaves the file's mtime alone.

2.6 The commands

CommandWhat it doesExit codes
initFirst run. Selects profiles, writes .crux/agent-profile.toml, composes both targets, offers to install hooks0 ok · 2 already initialised · 1 error
regenerate [--force] [--hooks]Re-composes both targets from the saved choice0 ok · 1 on drift without --force, or any compose error
check [--strict]Reports drift and advisory warnings. Writes nothing0 clean · 1 drifted · with --strict, 1 on warnings too
diff [--strict]Same evaluation as check, reported as a diff narrative0 clean · 1 drifted · with --strict, 1 on warnings too
listEvery bundled profile with version, risk, description and an enabled marker0
add <name>Enables a profile and re-composes0 ok · 1 unknown profile
remove <name>Disables a profile and re-composes, deleting its section0 ok · 2 was not enabled

Sources: commands.rs:51 run_init, commands.rs:104 run_regenerate, commands.rs:146 run_check, commands.rs:162 run_list, commands.rs:181 run_add, commands.rs:193 run_remove, commands.rs:206 run_diff. Flags are declared at cli.rs:26.

2.6.1 list

Available profiles:
  [x] memory-practices (v1, risk=low) — Crux daemon memory + retrieval discipline.
  [ ] eu-ai-act (v1, risk=high) — Engineering-best-practice posture aligned with EU AI Act …

[x] means enabled in this workspace, [ ] means bundled but not enabled (commands.rs:170). list works before init too, in which case everything shows unchecked.

2.6.2 regenerate

CLAUDE.md: wrote=true, updated=10, added=0
AGENTS.md: wrote=false, updated=10, added=0
.crux/agent-profile.toml: updated=1

updated counts managed sections replaced, added counts sections appended because they were missing.

That third line is the part people miss. regenerate also migrates your version pins. After both targets have been written successfully, any profile whose pinned version differs from the bundled version has its pin advanced in .crux/agent-profile.toml, and the count is reported (commands.rs:128). The ordering is deliberate: if either target fails to write, the function returns before the pin block (commands.rs:124), so a half-applied upgrade never records itself as complete. There is an in-tree test for exactly that case (commands.rs:318).

regenerate --hooks additionally re-runs the hook install, which is how you pick up a new hook after upgrading corecruxctl (cli.rs:51). It is off by default here, unlike on init.

2.6.3 add and remove

Both are thin: they edit the config and then call regenerate with force = false (commands.rs:190, commands.rs:203). Two consequences follow. An add or remove will fail if you have hand edits inside any managed section, because the underlying regenerate refuses; fix the drift first. And remove of a profile that was not enabled exits 2 with profile '<name>' was not enabled. rather than silently succeeding (commands.rs:196).

2.7 Drift, and the check / diff workflow

"Drift" means the files on disk are not what regenerate would produce. The wizard distinguishes drift, which regenerate can fix, from advisory warnings, which it cannot, and reports them as two separate blocks with two different remediations (drift.rs:39).

Three conditions count as drift (drift.rs:70):

ConditionWhat you seeFix
Version mismatch, the pin in your config is older than the bundled fragmentprofile 'memory-practices' is at v1 in config but v2 in the crateregenerate
Content drift, a dry-run compose would rewrite the fileCLAUDE.md would be rewritten (updated=3, added=1)regenerate
Manual edit inside a managed sectionCLAUDE.md has manual edits inside managed section 'memory-practices'regenerate --force, or move your edit out, see §2.12

Any one of these sets drifted (drift.rs:160), and the boot advisory reads:

[crux-config-wizard] CLAUDE.md or AGENTS.md is out of date.
profile 'memory-practices' is at v1 in config but v2 in the crate

Run `crux-config-wizard regenerate` to refresh.

Two properties of the check are worth stating plainly.

A workspace with no .crux/agent-profile.toml is reported clean, not drifted (drift.rs:73). Not-configured is not the same as out-of-date. This is what makes it safe to put check in a shared CI template that also runs on repositories which have never used the wizard.

check and diff evaluate identically. Both call the same check_workspace and apply the same exit rules (commands.rs:146, commands.rs:206). They differ only in the clean-case message, crux-config-wizard: workspace clean. versus no diff. Neither writes anything.

2.7.1 The session-boot advisory

The check also runs automatically. The crux-claude-hooks session-start hook calls check_workspace on the current directory at every Claude session boot and, when it finds drift or warnings, pushes the message into the session as additional context (session_start.rs:174). It is filesystem-only and does not touch the daemon.

Set CRUX_HOOK_WIZARD_CHECK=off in the environment to disable it (session_start.rs:172). The rest of the session-start ritual still runs; the same variable also gates the self-check in §2.9.

2.8 The two advisory lints

Beyond drift, check, diff and the boot advisory surface two warnings. Both are advisory in the strict sense: regenerate cannot fix either of them, because both concern free-span text and the composer never rewrites free spans. They do not set drifted, and they do not fail check unless you pass --strict (commands.rs:151).

Free-span duplication. When prose outside the markers substantially restates an enabled profile's body, the usual cause is a hand-written section from before the wizard was adopted; you get:

CLAUDE.md: free-span text restates managed profile 'memory-practices'
(7/16 distinctive lines duplicated, e.g. "When calling `store_fact`, …").
Replace the duplicated prose with a pointer to the managed section —
`regenerate` cannot fix this.

The heuristic is deliberately conservative, so that quoting one rule for context does not trip it. A "distinctive" line is non-blank, not a heading, table row, marker or blockquote, and at least 24 characters (compose.rs:283); comparison normalises away list markers so bullet style does not matter (compose.rs:258). It flags at 3 or more matched distinctive lines, or at 30% or more of a body with at least 4 distinctive lines (compose.rs:202, compose.rs:241). The fix is editorial: delete the duplicated prose and point at the managed section below it.

Composed size. A large CLAUDE.md is paid for on every single session, so the wizard warns when a composed file exceeds a soft byte budget:

CLAUDE.md is 51,200 B (soft budget 49,152 B); free-span text is 18,000 B of
that. Trim free spans or split content — a large file inflates every session
prefix and risks the boot load cap.

The default budget is 49,152 bytes per target (config.rs:76), roughly 48 KB, chosen as a margin under the session boot load cap for dense markdown (config.rs:62). The message splits out how much of the total is free-span text, because that is the part you can do something about. Tune it per workspace in the [limits] block (§2.10).

2.9 The boot self-check

A separate module catches a different failure class: not the files drifting, but the environment drifting. It is pure policy with no I/O, the hook makes the observations and passes them in (selfcheck.rs:28), which is what makes the rules unit-testable and lets the same code back both the boot banner and the CLI.

It raises exactly two warnings (selfcheck.rs:53):

WarningConditionWhy it matters
Hook/daemon version skewThe running hook and the daemon differ in major.minor (selfcheck.rs:63)A stale hook silently drifts from the daemon's boot contract. Patch-level differences are ignored on purpose
Boot banner degradedThe daemon was reachable and reported itself healthy, yet the substantive playbook section failed to render (selfcheck.rs:78)This is the signature of a hook regression suppressing content behind a healthy daemon

The module exists because of a real 2026-07 regression in which a health check string-matched the word degraded against a payload that always contains "degraded": false, permanently suppressing the playbook. The daemon was healthy, the tests were green, and the banner had been a stub for weeks with nothing surfacing it (selfcheck.rs:12). Both conditions are deliberately narrow: an unreachable daemon produces no skew warning, because there is nothing to compare, and a daemon that honestly reports itself degraded produces no banner warning, because a degraded daemon legitimately has no playbook.

Warnings render as a **Crux self-check** section in the boot banner (selfcheck.rs:92), fed by the same hook block and gated by the same CRUX_HOOK_WIZARD_CHECK variable (session_start.rs:198).

2.10 .crux/agent-profile.toml, the committed config

One file, at a fixed path relative to the workspace root (config.rs:117). Commit it. It is the record of which rules this repository agreed to and at which versions.

schema_version = 1
workspace_fingerprint = "blake3:…"

[profiles.memory-practices]
version = 1
enabled_at = "2026-05-19T11:29:50Z"

# … one block per enabled profile …

[targets]
claude_md = "CLAUDE.md"
agents_md = "AGENTS.md"

[limits]                       # optional
claude_md_max_bytes = 49152
agents_md_max_bytes = 49152
KeyMeaning
schema_versionConfig format version, currently 1 (config.rs:91)
workspace_fingerprintBLAKE3 of the workspace's absolute path, stable across runs, distinct per workspace, so one daemon serving several workspaces can tell their records apart (config.rs:177)
[profiles.<name>].versionThe pinned fragment version. A mismatch against the bundled version is drift
[profiles.<name>].enabled_atWhen it was turned on. Preserved across a pin migration
[targets]The output filenames, defaulting to CLAUDE.md and AGENTS.md (config.rs:46)
[limits]Optional soft byte budgets. Omit the block entirely for the defaults (config.rs:68)

The file is saved atomically, temp-file then rename, so an interrupted write leaves the previous config intact (config.rs:137). A config written before [limits] existed still loads and picks up the defaults.

Because the fingerprint is a hash of the absolute path, it changes if the workspace is checked out somewhere else. Nothing in the wizard fails as a result, the fingerprint is an identifier for runtime records, not a validation input, but do not expect it to be stable across machines.

2.11 This is not the daemon's configuration

The names invite confusion and it is worth being blunt about the separation.

The config wizardThe daemon
ConfiguresYour agent's standing instructionsThe corecruxd process
WritesCLAUDE.md, AGENTS.md, .crux/agent-profile.tomlNothing; it reads
Read byClaude Code and other agent harnessescorecruxd at startup
SurfaceProfile fragment names393 CORECRUXD_* environment variables and a YAML file
ReferenceThis chapterChapter 5

The wizard reads no CORECRUXD_ variable and writes none. Setting CORECRUXD_AUTH_MODE has no effect on anything in this chapter, and enabling the memory-practices profile has no effect on a running daemon. The only environment the wizard's own code touches is PATH, HOME and CARGO_HOME, all three solely to locate corecruxctl for the optional hook install (hooks_bridge.rs:34). CRUX_HOOK_WIZARD_CHECK is read by the hook, not by the wizard binary (session_start.rs:172).

A useful way to hold the two apart: the wizard configures the thing that calls the daemon; chapter 5 configures the daemon that answers.

2.12 When regeneration would clobber something you wrote

This is the situation the wizard is most careful about, so it is worth walking through.

Before replacing any managed section, the composer renders what the section should contain and compares it, whitespace-normalised, with what is actually there (compose.rs:107). If they differ, it refuses, names the profile and the file, and writes nothing (compose.rs:31):

error: manual edit detected inside managed section 'memory-practices' in
CLAUDE.md; refuse to overwrite without --force

That refusal is the whole safety property. Your three options, in the order you should consider them:

  1. Keep your edit, move it outside the markers. This is almost always right. The composer only ever touches managed spans, so your text is preserved verbatim anywhere else in the file. Put a workspace-specific exception in a free span immediately after the managed section it qualifies, and note that it is an exception.
  2. Discard your edit and take the bundled version: crux-config-wizard regenerate --force. Use this when the drift is accidental, a stray edit, a bad merge, an older fragment version baked in.
  3. Change the rule at source. If the edit reflects a genuine improvement, it belongs in the fragment, with its version bumped. Every workspace pinned to the old version then gets told, by name, on its next session boot.

Two follow-on points people hit.

--force is per-invocation and covers both targets. It does not become a setting, and there is no way to mark one section as permanently hand-owned. If you find yourself reaching for --force repeatedly, option 1 or option 3 is the answer.

remove deletes the whole section, including anything you put inside it. Disabling a profile drops its span outright (compose.rs:142). Move anything you want to keep into a free span first.

2.13 Using it in CI

crux-config-wizard check           # fails the build if CLAUDE.md is stale
crux-config-wizard check --strict  # also fails on the two advisory lints

check writes nothing, needs no TTY, and needs no daemon. It exits 1 when drifted, 0 when clean, and 0 on a workspace that has never been initialised (commands.rs:146). Adding --strict promotes free-span duplication and oversize to build failures (commands.rs:153).

For provisioning a fresh checkout without prompts:

crux-config-wizard init --non-interactive \
  --profiles=memory-practices,token-conservation,code-grounding --no-hooks

Name the profiles explicitly rather than using all, all pulls in workspace-cuecrux, which is monorepo-specific, and omits code-minimalism (§2.3.1). Use --no-hooks so the run does not depend on a corecruxctl being present (cli.rs:41).

Two ordering notes. --workspace <path> lets one CI job check several repositories without changing directory (cli.rs:20). And run check after your dependency install step, not before, so a bot that regenerated CLAUDE.md in the same job is what you are checking.

2.14 Authoring your own profile

The thirteen bundled fragments are not special; they are just the ones compiled in. A new one is a markdown file with +++-delimited TOML frontmatter in crates/crux-config-wizard/profiles/ (profile.rs:60):

+++
name = "your-name"
version = 1
description = "One line. Shown by `list` and by the init prompt."
targets = ["claude_md", "agents_md"]
order = 60
risk_class = "low"
conflicts_with = []
requires = []
+++

## Your section heading

The rule text that lands in CLAUDE.md and AGENTS.md, verbatim.
FieldRequiredBehaviour
nameyesMust be non-empty; becomes the marker name
versionyesBump on every edit; this is what drives the drift advisory
descriptionyesShown by list and in the interactive prompt
targetsnoDefaults to both files when omitted or empty (profile.rs:84)
ordernoDefaults to 0, so an omitted order sorts first
risk_classnoDefaults to low (profile.rs:48). Informational only
conflicts_withnoParsed and stored; the wizard does not act on it
requiresnoParsed and stored; the wizard does not act on it

Then add the include_str! entry in bundled_raw (profile.rs:95) so the binary embeds it, and add the name to DEFAULT_PROFILES (lib.rs:33) only if it should be part of --profiles=all.

Say plainly what conflicts_with and requires do today: nothing. They are declared on the frontmatter struct (profile.rs:41) and parsed, and no code path reads them. add will happily enable a profile that declares a conflict with an enabled one, and will not pull in a declared requirement. Treat them as documentation for a human reviewer until that changes.

2.15 What the wizard does not do

Stated as plainly as the rest of the chapter.

  • It does not enforce anything. It composes markdown. Whether an agent follows the rules in that markdown is between you and your agent; the wizard has no runtime, no hook into tool calls, and no way to block an action.
  • It does not talk to the daemon. Every command is filesystem-only. check on a machine with no daemon installed works exactly the same.
  • It does not merge. A managed section is replaced wholesale or refused. There is no three-way merge and no per-line resolution.
  • It does not rewrite free spans, ever. This is why the two advisory lints exist as warnings rather than fixes.
  • It does not act on conflicts_with or requires. See §2.14.
  • It does not version your CLAUDE.md. Git does. The wizard versions the fragments; the composed file is an artefact you commit like any other.
  • It does not check that a profile's rules are still true. A fragment naming a command, a path or an endpoint is a claim as of the version that shipped it. code-grounding exists partly to make agents re-verify such claims before acting on them.

Sources