Ooda config
Autonomous operations layer for Claude Code — opens small reviewable PRs for your live side project and re-orients from which ones you merge or reject. HALT file + hard cost cap; you stay in command.
npx -y skills add mataeil/OODA-loop --skill ooda-configAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 5 stars5 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
View, modify, and validate config.json settings via slash commands.
SKILL.md
18.0 KB, as published. Nobody here has run it
ooda-config: Configuration Management CLI
View, modify, and validate config.json without editing JSON by hand.
All writes: back up to config.json.bak, then re-parse to confirm valid JSON.
Step 0: HALT + Preflight
Read config.safety.halt_file (default agent/safety/HALT).
If that path exists: HALT: <reason>. ooda-config aborted. — stop.
If config.json is missing and subcommand is not validate:
config.json not found. Run /ooda-setup to create one. — stop.
Parse the user's invocation to one of: show | level | domain add | domain remove | domain list | safety | validate | lens review | lens reset | action {list|approve|defer|reject|prioritize} | mode/season | rotation {show|reset} | context show | rollback {cycle} | auto-merge {on|off}.
Unknown subcommand → print the Usage block and exit.
Step A — show
Print a compact summary: schema_version, project fields, domain list with weight/skill/enabled status, current progressive_complexity level and name, and key safety values (halt_file presence, confidence_threshold, max_prs_per_cycle).
Step B — level {N}
- Validate N is 0–3; fail fast otherwise.
- If N == 3, print explicit warning and require a typed confirmation phrase:
Only accept the exact phrase[DANGER] Level 3 enables AUTONOMOUS mode: - The agent autonomously writes code and opens PRs (no prompt). - By DEFAULT those are DRAFT PRs you review and merge — nothing reaches main without your click. (You stay in command.) - Auto-merge is a SEPARATE opt-in: only if you ALSO run `/ooda-config auto-merge on` (safety.enable_auto_merge=true) will it merge LOW-RISK PRs by itself — non-protected paths, <= auto_merge_max_files / auto_merge_max_lines, tests green — with a post-merge health check that auto-reverts + HALTs on failure. It stays OFF until you flip it. - Only the HALT file or the daily cost cap can stop a running cycle. Type "enable autonomous" to confirm (anything else cancels):enable autonomous. Any other response:Cancelled. - Back up config.json.
- Set
progressive_complexity.current_level = Nandimplementation.enabled = (N == 3). - Write + validate JSON. Print:
Level changed: <old> → <N> ("<name>").
Step C — domain add {name}
Ask the user in sequence for: weight (float, default 1.0), primary_skill (must start with "/"),
state_file path (default agent/state/<name>.json).
Back up config.json. Insert into config.domains:
{ "weight": <w>, "state_file": "<path>", "primary_skill": "<skill>",
"chain": [], "branch_prefix": "auto/<name>/", "fallback": true,
"enabled": true, "status": "active" }
(status is the field evolve's filters treat as authoritative — a domain
without it would never be selected. enabled is kept for back-compat; evolve
treats a domain with enabled: true and NO status field as "active".)
Create empty state file if absent ({ "schema_version": "1.0.0", "domain": "<name>", "last_run": null }).
Append primary_skill to safety.skill_allowlist if not already present.
Write + validate. Print confirmation showing state file status and allowlist change.
Step D — domain remove {name}
Look up config.domains.<name>. Not found or already disabled → print message and exit.
Back up. Set enabled: false (soft-delete — data retained). Write + validate.
Print: Domain disabled: <name> (re-enable by setting enabled: true)
Step E — domain list
Print a table: name, status (enabled/disabled), weight, primary_skill, state_file.
Footer: Total: <N> domains, <enabled_count> enabled.
If config.domains is empty: No domains configured.
Step F — safety
Print the full safety section as a labeled key-value block: halt_file (with presence indicator), confidence_threshold, min_cycle_interval_minutes, max_prs_per_cycle, max_files_per_pr, max_lines_per_pr, first_cycle_observe_only, protected_paths list, and skill_allowlist.
Step G — validate
The full check list (1–27) is defined ONCE in "Step G — validate (extended)" below — that section is canonical. (An earlier 17-check copy of this list lived here and drifted from the extended one; never maintain two lists.)
Lens Management
Step H — lens review {domain}
Show the lens snapshot for the named domain.
- Look up the domain in
config.domains. Not found →Domain not found: <name>and exit. - Derive the lens path:
agent/state/<name>/lens.json(orlens_filefield if present in config). - If lens.json does not exist →
No lens data for <name>. Run a cycle first.and exit. - Print the full contents of lens.json as a labeled key-value block, including all evidence trail entries (timestamps, sources, confidence deltas).
Step I — lens reset {domain}
Wipe the lens snapshot for the named domain, forcing a fresh start on the next cycle.
- Look up the domain in
config.domains. Not found →Domain not found: <name>and exit. - Derive the lens path the same way as Step H.
- If lens.json does not exist →
No lens file found for <name>. Nothing to reset.and exit. - Ask for confirmation:
Reset lens for <name>? This clears all accumulated evidence. (yes/no)Any answer other than "yes" →Cancelled.and exit. - Back up the existing lens file to
lens.json.bakin the same directory before overwriting. Print:Backed up: <lens_path>.bak - Overwrite lens.json with the FULL empty schema (every array evolve 5-E reads
must exist — a reset file missing
focus_items/learned_thresholds/discovered_signalsbreaks the next lens update):{ "schema_version": "1.0.0", "domain": "<name>", "reset_at": "<ISO timestamp>", "focus_items": [], "learned_thresholds": [], "discovered_signals": [], "deprecated_items": [], "evidence": [] } - Print:
Lens reset: <name> (evidence cleared, backup saved, next cycle starts fresh)
Action Queue Management
Step J — action list
Print pending actions from agent/state/evolve/action_queue.json:
[Action Queue] {pending_count} pending, {completed_count} completed
| # | ID | Title | RICE | Age | Status |
|---|--------|------------------------------|-------|------|---------|
| 1 | a15-1 | Update context.json names | 50400 | 3.2d | pending |
| 2 | a17-1 | Pipeline FTS index | 25200 | 3.0d | approved |
Show effective_rice (with decay applied) and age since extracted_at.
Step K — action approve {id}
Set action status to "approved". Approved items are prioritized over pending
items in dev-cycle selection regardless of RICE score.
1. Find action by id in action_queue.pending
2. If not found: "Action not found: {id}" — exit
3. Set status = "approved", approved_at = now
4. Boost effective_rice by 20% (item.effective_rice *= 1.2)
5. Print "Approved: {title} (effective RICE: {new_rice})"
Step L — action defer {id} [days]
Defer an action for N days (default 7). Deferred items are excluded from dev-cycle selection until their defer period expires.
1. Find action by id
2. Set status = "deferred", deferred_until = now + N days
3. Print "Deferred: {title} until {date} ({N} days)"
Step M — action reject {id} [reason]
Move action to completed with status "rejected_by_human".
1. Find action by id
2. Move to completed array with status = "rejected_by_human", reason = reason
3. Print "Rejected: {title} — {reason or 'no reason given'}"
Step N — action prioritize {id}
Move action to top of queue by setting effective_rice above current highest.
1. Find action by id
2. Set effective_rice = max(all pending effective_rice) + 1.0
3. Re-sort pending by effective_rice descending
4. Print "Prioritized: {title} → top of queue (RICE: {new_rice})"
Step O — mode {name} (alias: season {name})
Switch season/phase mode. Mode overrides domain weights, disables selected domains for the season, and may bump signal bonuses. Changes take effect on the NEXT cycle (they are read in-memory at Step 1-A; disk config.json is updated so /ooda-status shows the current mode).
1. Read config.season_modes.modes
2. If modes not configured: "No season modes defined. Add season_modes to config.json." — exit
3. If {name} not in modes: "Unknown mode: {name}. Available: {list}" — exit
4. Back up config.json
5. Set config.season_modes.current_mode = {name}
6. Set config.season_modes.enabled = true (in case it was false)
7. Print applied overrides:
- weight_overrides: {domain: multiplier}
- disabled_domains: [...]
- signal_bonuses: {signal: value}
8. Write + validate JSON
9. Print "Season mode changed: {old} → {name}"
Step O1 — season list
List all defined modes with a one-line summary.
1. Read config.season_modes.modes
2. For each mode: print "- {name}: {len(weight_overrides)} weights, {len(disabled_domains)} disabled, {len(signal_bonuses)} signal bonuses"
3. Print: "Current: {current_mode}" (or "(season_modes disabled)" if enabled=false)
Step O2 — season show
Print the full active-mode overrides applied to the current scoring table.
1. Read config.season_modes
2. If not enabled: print "Season modes disabled." — exit
3. For the current_mode:
- Print "Mode: {current_mode}"
- Print weight_overrides with the previous weights for comparison:
" service_health: config=2.0 -> mode=1.0 (effective)"
- Print disabled_domains: " disabled: [competitors]"
- Print signal_bonuses: " signal bonuses: {health_alert_bonus: +5.0}"
Step P — rotation show {domain}
Show the rotation list and current cursor for a domain.
1. Look up domain in config.domains
2. If no `rotation` field: "Domain '{name}' has no rotation list." — exit
3. Read cursor from agent/state/{domain}/rotation_cursor.json (missing = cursor 0)
4. Print the rotation list with an arrow at the current cursor position:
[thumbnail-editor, dashboard -> stats, billing]
5. Print: "Next focus_item: {list[cursor]}"
Step P1 — rotation reset {domain}
Reset the rotation cursor to 0 for a domain.
1. Look up domain in config.domains
2. If no `rotation` field: "Domain '{name}' has no rotation list." — exit
3. Back up agent/state/{domain}/rotation_cursor.json to .bak (if present)
4. Write {"cursor": 0, "last_updated": now, "focus_item": rotation_list[0]}
5. Print: "Rotation cursor reset: {domain} -> 0 ({first_focus_item})"
Step Q — context show
Print the current active_context config + the loaded blob contents.
1. Read config.active_context
2. If no active_context.path: "No active_context configured." — exit
3. Try to read the file at that path:
- If missing: "active_context file missing: {path}"
- If malformed JSON: "active_context file is not valid JSON"
- If OK: print path, mtime age, refresh_skill (if any), refresh_interval_hours,
and the blob contents (pretty-printed, cap at 80 lines)
Step R — rollback {cycle}
Revert the repo + state to a recorded checkpoint. Checkpoints are written by
evolve 4-C2 when safety.enable_rollback (or safety.enable_auto_merge) is on.
1. Read agent/state/evolve/checkpoints.json. If missing/empty:
"No checkpoints recorded. Set safety.enable_rollback=true to enable." — exit.
2. Find the checkpoint where checkpoint.cycle == {cycle}.
If not found: "No checkpoint for cycle {cycle}. Available: {cycles}" — exit.
3. Confirm (typed phrase): print
"Roll back to cycle {cycle} (commit {sha})? This reverts every commit since
then and restores state. Type 'rollback {cycle}' to confirm:"
Accept ONLY the exact phrase; anything else: "Cancelled." — exit.
4. Re-check the HALT file.
5. Revert the repo. CAUTION: `git revert {sha}..HEAD` reverts each commit in the
range and **fails on any merge commit in that range** (it needs `-m`, and a
mixed range can't take a single `-m`) — leaving main HALF-reverted. This is
safe only on a linear history; auto-merge uses `--squash` precisely to keep it
linear. If the range may contain `--merge` merge commits, prefer `--hard`.
# default (linear history, e.g. squash-merged auto-merges):
git revert --no-edit {checkpoint.commit_sha}..HEAD
git push origin HEAD
# robust fallback / operator `--hard` (destructive — warn first):
git reset --hard {checkpoint.commit_sha} && git push --force origin HEAD
6. Restore confidence.json and action_queue.json pending items from
checkpoint.state_snapshot.
7. Create the HALT file: "Manual rollback to cycle {cycle} ({sha}). Delete to resume."
8. Print "Rolled back to cycle {cycle} ({sha}). HALT created — review, then
delete the HALT file to resume."
Step S — auto-merge {on|off}
Toggle the autonomous low-risk auto-merge opt-in (config.safety.enable_auto_merge,
default off). This is the SINGLE switch that lets evolve merge PRs on its own.
1. Parse on|off. Unknown → print Usage and exit.
2. Turning ON:
- Require progressive_complexity.current_level == 3, else:
"Auto-merge needs Level 3. Run /ooda-config level 3 first." — exit.
- Print the gates and require a typed phrase:
"[DANGER] Auto-merge will let the agent merge LOW-RISK PRs without your click:
non-protected paths, <= {auto_merge_max_files} files / {auto_merge_max_lines}
lines, tests green. A post-merge health check auto-reverts + HALTs on
failure. Larger/protected changes still wait for you.
Type 'enable auto-merge' to confirm:" (accept only the exact phrase)
3. Back up config.json. Set safety.enable_auto_merge = (on ? true : false).
Write + validate JSON.
4. Print "Auto-merge: {enabled|disabled}." When enabled, also print the active
low-risk thresholds so the operator sees the blast-radius bound.
Step G — validate (extended)
Run checks in order; print [PASS] or [FAIL] <reason> for each:
- config.json exists and is readable
- Parses as valid JSON
schema_versionfield presentproject.name,project.locale,project.timezoneall presentsafety.halt_file,safety.confidence_threshold,safety.max_prs_per_cyclepresent- Value ranges:
confidence_thresholdin [0.0, 1.0];max_prs_per_cycle>= 1;min_cycle_interval_minutes>= 1 - If present,
health_check_timeout_secondsis a number in [2, 30] - If present,
test_timeout_secondsis a number >= 10 - If present,
deploy_monitor_timeout_secondsis a number >= 60 - If present,
deploy_health_wait_secondsis a number >= 5 - If present,
deploy_workflow_inputsis a plain object (not array, not null) - If present,
safety.lock_timeout_minutesis a number >= 1 - At least one domain defined
- Each domain has
weight,primary_skill,state_file, andstatus(or legacyenabled— warn[WARN] domain {name}: no status field; evolve treats enabled:true as status:"active"instead of failing) - Every active domain's (
status == "active", or legacyenabled: true)primary_skillis insafety.skill_allowlist progressive_complexity.current_levelis 0–3- No sensitive field holds a raw token (must use
$ENV_VARform) - At least one domain has
fallback: true(confidence gate escape) - No duplicate
branch_prefixvalues across domains signals.health_alert_bonusshould be <= 2× max domain weight (monopoly risk)memory.contrarian_check_intervalis in range [1, 100]memory.action_queue_decay_days> 0 andaction_queue_decay_amountin (0, 1]- If
implementation.enabled,progressive_complexity.current_levelmust be 3 memory.working_memory_size>= 5 (minimum for pattern detection)- If
saturationblock present,warn_threshold < boost_threshold < halt_threshold - If
safety.enable_auto_mergeis true,progressive_complexity.current_levelmust be 3 - If present,
safety.auto_merge_max_files<=safety.max_files_per_prandsafety.auto_merge_max_lines<=safety.max_lines_per_pr(the low-risk bar must be tighter than the hard PR cap) - If
eval.enabledis true,eval.modelis a non-empty string andeval.grade_onis a non-empty list containing none offutile/error/observe(never spend an eval call on a no-value cycle)
Final: Validation: <N> passed, <M> failed
On any failure append: Run /ooda-config show to review your settings.
Usage
/ooda-config show Print current config summary
/ooda-config level {0-3} Change progressive complexity level
/ooda-config domain add {name} Add a new domain (interactive)
/ooda-config domain remove {name} Disable a domain (soft-delete)
/ooda-config domain list List all domains with status
/ooda-config safety Show full safety settings
/ooda-config validate Validate config.json structure and values
/ooda-config lens review {domain} Show lens.json for a domain with evidence trails
/ooda-config lens reset {domain} Wipe lens.json for a domain (start fresh)
/ooda-config action list List pending actions with RICE and age
/ooda-config action approve {id} Approve action for priority execution
/ooda-config action defer {id} [N] Defer action for N days (default 7)
/ooda-config action reject {id} Reject action with optional reason
/ooda-config action prioritize {id} Move action to top of queue
/ooda-config mode {name} Switch season/phase mode (alias: `season {name}`)
/ooda-config season list List available season modes
/ooda-config season show Show current mode overrides in detail
/ooda-config rotation show {d} Show rotation list + cursor for a domain
/ooda-config rotation reset {d} Reset rotation cursor to 0
/ooda-config context show Show active_context path + blob contents
/ooda-config auto-merge {on|off} Toggle low-risk autonomous merge (Level 3, opt-in)
/ooda-config rollback {cycle} Revert repo + state to a recorded checkpoint