Config location: .workflow/config.json → guard section
{
"guard": {
"enabled": false,
"mode": "allow",
"paths": []
}
}
Enforcement: The workflow-guard hook (PreToolUse on Write/Edit) reads this config
and blocks operations targeting files outside boundaries. Requires hooks level >= full.
Output boundary: ALL file writes MUST target .workflow/config.json (guard section) only. NEVER modify hook files, .claude/settings.json, or source code.
Phase Gates (MANDATORY, BLOCKING)
GATE 1: Parse → Config Read
- REQUIRED: Subcommand parsed (on/off/status/allow/deny/remove/clear) or defaulted to
status. - BLOCKED if: invalid subcommand provided.
GATE 2: Config Read → Execute
- REQUIRED:
.workflow/config.jsonread successfully or initialized with empty guard section. - BLOCKED if: file unreadable and cannot be created (E001).
GATE 3: Execute → Confirm
- REQUIRED: Config mutation applied (for on/off/allow/deny) or status displayed (for status).
- REQUIRED: Mode-switch request_user_input answered (for allow↔deny transitions with existing paths).
- BLOCKED if: user declines mode switch.
Step 1: Parse subcommand
Extract from $ARGUMENTS:
on/off/status/allow <path>/deny <path>- If no subcommand, default to
status
Step 2: Read config
Read .workflow/config.json. If file missing, initialize with empty guard section.
Step 3: Execute subcommand
status:
- Display: enabled/disabled, mode (allow/deny), paths list
- Check if workflow-guard hook is active (read
.claude/settings.jsonfor hook presence) - If guard enabled but hook not active, warn: "⚠ PathGuard enabled but workflow-guard hook not installed. Run
maestro hooks level fullto activate."
on:
- Set
guard.enabled = true - If
guard.pathsis empty, set default:["src/", "tests/", ".workflow/"] - Check hook level, warn if < full
- Write config
off:
- Set
guard.enabled = false - Preserve existing paths and mode
- Write config
allow <path>:
- Normalize path to forward slashes, ensure trailing slash for directories
- If
guard.modeisdeny, request_user_input: "Switching from deny to allow mode will clear existing paths ({N} paths). Continue?" — abort if user declines. Clearguard.paths(mode switch invalidates previous path list). - Set
guard.mode = "allow" - Add path to
guard.paths(deduplicate) - Set
guard.enabled = trueif not already - Write config
deny <path>:
- Normalize path to forward slashes, ensure trailing slash for directories
- If
guard.modeisallow, request_user_input: "Switching from allow to deny mode will clear existing paths ({N} paths). Continue?" — abort if user declines. Clearguard.paths(mode switch invalidates previous path list). - Set
guard.mode = "deny" - Add path to
guard.paths(deduplicate) - Set
guard.enabled = trueif not already (symmetric withallow: adding a deny path auto-enables the guard) - Write config
remove <path>:
- Normalize path
- Remove from
guard.paths(if present) - Write config
clear:
- Set
guard.paths = [] - Write config
Step 4: Confirm
Display updated guard configuration.