# Ooda Config

> View, modify, and validate config.json settings via slash commands.

- **Type:** Skill
- **Install:** `agentstack add skill-mataeil-ooda-loop-ooda-config`
- **Verified:** Yes — security-reviewed for prompt injection and unsafe behavior
- **Seller:** [mataeil](https://agentstack.voostack.com/s/mataeil)
- **Installs:** 0
- **Category:** [Cloud & Infrastructure](https://agentstack.voostack.com/c/cloud-infrastructure)
- **Latest version:** 0.1.0
- **License:** MIT
- **Upstream author:** [mataeil](https://github.com/mataeil)
- **Source:** https://github.com/mataeil/OODA-loop/tree/main/skills/ooda-config

## Install

```sh
agentstack add skill-mataeil-ooda-loop-ooda-config
```

Requires the [AgentStack CLI](https://agentstack.voostack.com/docs/cli). Works with Claude Code, Cursor, and any MCP-compatible agent.

## About

# 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: . 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}

1. Validate N is 0–3; fail fast otherwise.
2. If N == 3, print explicit warning and require a typed confirmation 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,  →  ("")`.

---

## 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/.json`).

Back up config.json. Insert into `config.domains`:
```json
{ "weight": , "state_file": "", "primary_skill": "",
  "chain": [], "branch_prefix": "auto//", "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": "", "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.`. Not found or already disabled → print message and exit.
Back up. Set `enabled: false` (soft-delete — data retained). Write + validate.
Print: `Domain disabled:   (re-enable by setting enabled: true)`

---

## Step E — domain list

Print a table: name, status (enabled/disabled), weight, primary_skill, state_file.
Footer: `Total:  domains,  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.

1. Look up the domain in `config.domains`. Not found → `Domain not found: ` and exit.
2. Derive the lens path: `agent/state//lens.json` (or `lens_file` field if present in config).
3. If lens.json does not exist → `No lens data for . Run a cycle first.` and exit.
4. 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.

1. Look up the domain in `config.domains`. Not found → `Domain not found: ` and exit.
2. Derive the lens path the same way as Step H.
3. If lens.json does not exist → `No lens file found for . Nothing to reset.` and exit.
4. Ask for confirmation: `Reset lens for ? This clears all accumulated evidence. (yes/no)`
   Any answer other than "yes" → `Cancelled.` and exit.
5. Back up the existing lens file to `lens.json.bak` in the same directory before overwriting.
   Print: `  Backed up: .bak`
6. 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_signals` breaks the next lens update):
   `{ "schema_version": "1.0.0", "domain": "", "reset_at": "",
      "focus_items": [], "learned_thresholds": [], "discovered_signals": [],
      "deprecated_items": [], "evidence": [] }`
7. Print: `Lens reset:   (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, ` for each:

1. config.json exists and is readable
2. Parses as valid JSON
3. `schema_version` field present
4. `project.name`, `project.locale`, `project.timezone` all present
5. `safety.halt_file`, `safety.confidence_threshold`, `safety.max_prs_per_cycle` present
6. Value ranges: `confidence_threshold` in [0.0, 1.0]; `max_prs_per_cycle` >= 1; `min_cycle_interval_minutes` >= 1
7. If present, `health_check_timeout_seconds` is a number in [2, 30]
8. If present, `test_timeout_seconds` is a number >= 10
9. If present, `deploy_monitor_timeout_seconds` is a number >= 60
10. If present, `deploy_health_wait_seconds` is a number >= 5
11. If present, `deploy_workflow_inputs` is a plain object (not array, not null)
12. If present, `safety.lock_timeout_minutes` is a number >= 1
13. At least one domain defined
14. Each domain has `weight`, `primary_skill`, `state_file`, and `status`
    (or legacy `enabled` — warn `[WARN] domain {name}: no status field; evolve
    treats enabled:true as status:"active"` instead of failing)
15. Every active domain's (`status == "active"`, or legacy `enabled: true`)
    `primary_skill` is in `safety.skill_allowlist`
16. `progressive_complexity.current_level` is 0–3
17. No sensitive field holds a raw token (must use `$ENV_VAR` form)
18. At least one domain has `fallback: true` (confidence gate escape)
19. No duplicate `branch_prefix` values across domains
20. `signals.health_alert_bonus` should be  0 and `action_queue_decay_amount` in (0, 1]
23. If `implementation.enabled`, `progressive_complexity.current_level` must be 3
24. `memory.working_memory_size` >= 5 (minimum for pattern detection)
25. If `saturation` block present, `warn_threshold  passed,  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
```

## Source & license

This open-source skill is cataloged on AgentStack and links to its original source — we do not rehost the code.

- **Author:** [mataeil](https://github.com/mataeil)
- **Source:** [mataeil/OODA-loop](https://github.com/mataeil/OODA-loop)
- **License:** MIT

Install and usage instructions live in the source repository linked above.

## Pricing

- **Free** — Free

## Security capabilities

Automated source analysis of v0.1.0 — what this tool can access:

- **Network access:** no
- **Filesystem access:** no
- **Shell / process execution:** no
- **Environment & secrets:** no
- **Dynamic code execution:** no

*"Yes" means the capability is present in the source — more access means more to trust, not that it is unsafe.*


## Versions

- **0.1.0** — security scan: passed — Imported from the upstream source.

## Links

- Listing page: https://agentstack.voostack.com/l/skill-mataeil-ooda-loop-ooda-config
- Seller: https://agentstack.voostack.com/s/mataeil
- Browse the marketplace: https://agentstack.voostack.com/browse

---
Listed on AgentStack — the marketplace for AI agent skills and MCP servers. Every listing is security-reviewed. Creators keep 70%.
