원클릭으로
authority-enforcer
Validates and enforces agent authority boundaries during wave execution and review panels
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
메뉴
Validates and enforces agent authority boundaries during wave execution and review panels
Codex 또는 Claude로 설치 이 Prompt를 복사해 Codex, Claude 또는 다른 어시스턴트에 붙여 넣으면 Skill 페이지를 검토하고 설치를 진행할 수 있습니다.
SOC 직업 분류 기준
| name | authority-enforcer |
| description | Validates and enforces agent authority boundaries during wave execution and review panels |
| triggers | ["authority","boundary","domain","enforce","validate","filter"] |
| token_cost | low |
| summary | Loads authority matrix, validates agent boundaries, filters out-of-domain critiques. Used by wave-executor and review-panel to prevent conflicts. |
Validates and enforces agent authority boundaries during wave execution and review panels. Prevents agent conflicts by ensuring domain ownership is respected.
Load and parse the authority matrix to establish domain ownership rules.
Input: None (uses hardcoded path)
Output: AuthorityMatrix object
Procedure:
1. Read `.planning/config/authority-matrix.yaml`
2. Parse YAML into structured object
3. Store in memory: agent_id → AgentConfig mapping
4. Build reverse index: domain → primary_agent_id
Input: AuthorityMatrix
Output: ValidationReport
Checks:
1. All agent IDs exist in agent-registry
2. No domain is assigned to more than one agent as "exclusive"
3. Flag overlapping domains for conflict resolution
4. Verify deferred_by arrays are valid
Validation Algorithm:
def validate_matrix(matrix):
errors = []
domain_owners = {}
for agent_id, config in matrix.agents.items():
# Check 1: Agent exists in registry
if not registry.has_agent(agent_id):
errors.append(f"Unknown agent: {agent_id}")
# Check 2: No duplicate exclusive domains
for domain in config.exclusive_domains:
if domain in domain_owners:
errors.append(
f"Domain conflict: '{domain}' assigned to both "
f"{domain_owners[domain]} and {agent_id}"
)
else:
domain_owners[domain] = agent_id
return ValidationReport(valid=len(errors) == 0, errors=errors)
Check if an agent is authorized to critique or act on a specific topic.
validateBoundaryInput:
agent_id: string # Agent requesting action
topic: string # Topic/domain being addressed
active_agents: string[] # List of currently active agents
Output:
authorized: boolean # Whether agent can proceed
domain_owner: string|null # Owner of this domain (if any)
reason: string # Explanation of decision
def validate_boundary(agent_id, topic, active_agents):
# Mode check: skip validation if authority enforcement is disabled
if not profile.authority_enforcement:
return {
authorized: True,
domain_owner: None,
reason: "Authority enforcement disabled by control mode"
}
# Load agent's exclusive domains from matrix
agent_domains = matrix.get_domains(agent_id)
# Check 1: Agent owns this topic
if topic in agent_domains:
return {
authorized: True,
domain_owner: agent_id,
reason: "Agent has exclusive authority over this domain"
}
# Check 2: Another agent owns this topic
for active_agent in active_agents:
if active_agent == agent_id:
continue
active_domains = matrix.get_domains(active_agent)
if topic in active_domains:
return {
authorized: False,
domain_owner: active_agent,
reason: f"{active_agent} has exclusive authority; respect domain owner"
}
# Check 3: No owner for this topic
return {
authorized: True,
domain_owner: None,
reason: "Topic has no exclusive owner; general domain"
}
Topics are matched using keyword normalization:
Normalization Rules:
- Case-insensitive matching
- Hyphens and underscores equivalent ("ci-cd" == "ci_cd")
- Substring matching for compound topics:
"api-security" matches both "api" and "security"
Specificity Scoring:
- Exact match: score 10
- Substring match: score 5
- Related domain: score 2
- No match: score 0
Inject authority constraints into agent prompts to prevent conflicts proactively.
injectAuthorityConstraintsInput:
agent_id: string
base_prompt: string
active_agents: string[]
Output:
enhanced_prompt: string
def inject_authority_constraints(agent_id, base_prompt, active_agents):
constraints = []
# Step 1: Add agent's own authority
own_domains = matrix.get_domains(agent_id)
if own_domains:
constraints.append(
f"## Your Authority\\n\\n"
f"You have EXCLUSIVE AUTHORITY over these domains:\\n"
+ "\\n".join(f"- {d}" for d in own_domains)
+ "\\n\\nWhen active, other agents must respect your judgment in these areas."
)
# Step 2: Add deference rules for other active agents
for other_agent in active_agents:
if other_agent == agent_id:
continue
other_domains = matrix.get_domains(other_agent)
if other_domains:
agent_name = matrix.get_name(other_agent)
constraints.append(
f"\\n## Domain Ownership Required\\n\\n"
f"{agent_name} ({other_agent}) has exclusive authority over:\\n"
+ "\\n".join(f"- {d}" for d in other_domains)
+ "\\n\\nDO NOT critique or override their findings in these domains."
)
# Step 3: Mode-specific constraints
if profile.read_only:
constraints.append(
"\n## Advisory Mode Active\n\n"
"You are in ADVISORY mode. Analyze and suggest improvements "
"but DO NOT modify any files. Present your suggestions as a "
"structured list of proposed changes with rationale."
)
if profile.file_scope_restriction:
constraints.append(
"\n## Surgical Mode — File Scope Restriction\n\n"
"You may ONLY modify files explicitly listed in this plan's "
"`files_modified` field. Do not create, edit, or delete any other files. "
"If a task requires touching unlisted files, stop and escalate."
)
if not profile.human_approval_required:
# Omit the escalation protocol section from injected constraints
pass # Do not append the standard "Human Approval Required" block
else:
# Step 3b: Inject escalation format instructions
# When human approval is required, agents must use structured <escalation> blocks
# for any out-of-scope decisions. Format defined in escalation-protocol.yaml.
escalation_instructions = (
"\n## Escalation Protocol\n\n"
"When you encounter a decision that falls outside your autonomous scope "
"(architecture changes, unplanned dependencies, out-of-scope files, schema changes, "
"API contract changes, deletions, infrastructure changes, or quality gate overrides), "
"you MUST use a structured escalation block in your output.\n\n"
"**Format** — wrap in `<escalation>` tags with these required fields:\n\n"
"```\n"
"<escalation>\n"
"severity: info | warning | blocker\n"
"type: architecture | dependency | scope | schema | api | deletion | infrastructure | quality\n"
"decision: What decision is needed (one sentence)\n"
"context: Why you encountered this (2-3 sentences)\n"
"alternatives: What you would do if authorized (optional)\n"
"affected_files: Files that would be modified (optional)\n"
"</escalation>\n"
"```\n\n"
"**Severity guide:**\n"
"- `info` — observation only, you can continue working\n"
"- `warning` — notable concern, you continue but it will be highlighted\n"
"- `blocker` — you MUST stop the blocked action and work on other in-scope tasks\n\n"
"**Do not skip this.** Ad-hoc text descriptions of out-of-scope issues are not "
"sufficient. The wave-executor parses `<escalation>` blocks for automated routing.\n\n"
"Reference: `.planning/config/escalation-protocol.yaml`"
)
constraints.append(escalation_instructions)
# Step 3c: Add control mode context line
control_mode_name = profile.control_mode_name if hasattr(profile, 'control_mode_name') else "guarded"
constraints.append(
f"\n## Active Control Mode: {control_mode_name}\n\n"
f"Escalation behavior follows the `{control_mode_name}` profile. "
"See `.planning/config/escalation-protocol.yaml` for severity routing rules."
)
# Step 4: Combine with base prompt
if constraints:
enhanced = "\\n\\n".join(constraints) + "\\n\\n---\\n\\n" + base_prompt
else:
enhanced = base_prompt
return enhanced
## Your Authority
You have EXCLUSIVE AUTHORITY over these domains:
- security
- owasp
- vulnerability-assessment
- pentest
When active, other agents must respect your judgment in these areas.
## Domain Ownership Required
Backend Architect (engineering-backend-architect) has exclusive authority over:
- backend-architecture
- database-design
- api-design
DO NOT critique or override their findings in these domains.
---
[Original prompt content...]
Note: Constraint injection is the first line of defense. Post-execution boundary verification (Section 11) is the second line. Both are required for full authority enforcement.
Filter findings during review synthesis to remove out-of-domain critiques.
filterFindingsInput:
findings: Finding[] # List of review findings
active_agents: string[] # Agents present in review panel
Output:
filtered_findings: Finding[]
removed_findings: Finding[] # With reasons
Finding:
reviewer: string # Agent ID who made the finding
criterion: string # What was checked
severity: enum # BLOCKER | WARNING | NOTE
message: string # Finding description
domain: string # Inferred domain (auto-detected)
def filter_findings(findings, active_agents):
# Mode check: skip filtering if domain filtering is disabled
if not profile.domain_filtering:
return findings, [] # Return all findings, nothing removed
filtered = []
removed = []
# Build domain ownership map from active agents
domain_ownership = {}
for agent in active_agents:
for domain in matrix.get_domains(agent):
domain_ownership[domain] = agent
for finding in findings:
# Step 1: Detect domain from criterion or message
finding_domain = detect_domain(finding.criterion, finding.message)
# Step 2: Check if domain has an owner in active agents
if finding_domain in domain_ownership:
owner = domain_ownership[finding_domain]
# Step 3: Check if reviewer IS the owner
if finding.reviewer == owner:
filtered.append(finding)
else:
# Step 4: Check severity override rule
if finding.severity == "BLOCKER":
# BLOCKER from any agent overrides domain ownership
filtered.append(finding)
finding.notes = (
f"[OVERRIDE] Out-of-domain BLOCKER kept per severity rule "
f"(domain owner: {owner})"
)
else:
# Filter out non-BLOCKER findings from non-owners
removed.append({
**finding,
removal_reason: (
f"Out-of-domain critique filtered — "
f"{owner} is domain authority for '{finding_domain}'"
)
})
else:
# No owner for this domain, keep finding
filtered.append(finding)
return filtered, removed
authority-enforcer is the CANONICAL OWNER of domain detection. All consumers (review-panel, review-evaluators, wave-executor) MUST delegate to detect_domain here — they must NOT reimplement or fork keyword lists.
Keyword source of truth: .planning/config/authority-matrix.yaml under each domain's keywords: field. Do NOT hardcode keyword lists in this function — load from the matrix at runtime so one schema edit propagates to every consumer.
Concrete conditions (explicit if/else — no "when appropriate"):
.planning/config/authority-matrix.yaml exists AND parses AND contains a domains: map with keywords: entries:
domain_keywords = {d.name: d.keywords for d in matrix.domains}criterion + " " + message text."general" AND emit a DEBUG log domain_detection: no keyword match for finding "{criterion_preview}" so the "everything falls to general" failure mode from LEGION-47-174 is observable.Built-in fallback registry (used only when the matrix is unreadable). This list MUST mirror every domain declared in authority-matrix.yaml — if the matrix adds a domain, add it here too in the same PR. No # ... etc:
BUILT_IN_DOMAIN_KEYWORDS = {
"security": [
"security", "vulnerability", "pentest", "owasp", "auth",
"authn", "authz", "encrypt", "decrypt", "sanitize", "injection",
"xss", "csrf", "ssrf", "token", "session", "cookie", "jwt",
"credential", "secret", "password", "hash", "tls", "ssl",
],
"performance": [
"performance", "optimization", "latency", "throughput", "slow",
"benchmark", "profile", "memory leak", "cpu", "hot path", "n+1",
"cache", "queue depth", "p95", "p99",
],
"accessibility": [
"accessibility", "a11y", "wcag", "screen reader", "aria",
"keyboard navigation", "color contrast", "focus ring", "alt text",
],
"api-design": [
"api", "endpoint", "rest", "graphql", "rpc", "grpc", "contract",
"schema", "openapi", "swagger", "versioning", "pagination",
],
"database": [
"database", "schema", "migration", "index", "query plan", "sql",
"nosql", "postgres", "mysql", "mongo", "transaction", "deadlock",
"foreign key", "constraint",
],
"frontend": [
"frontend", "ui", "component", "render", "hydration", "css",
"layout", "responsive", "react", "vue", "svelte", "dom", "bundle",
],
"backend": [
"backend", "service", "handler", "controller", "middleware",
"background job", "worker", "queue", "rate limit", "retry",
],
"infrastructure": [
"infrastructure", "ci", "cd", "pipeline", "deploy", "docker",
"kubernetes", "k8s", "terraform", "helm", "env var",
"configuration", "observability", "logging", "metrics", "tracing",
],
"testing": [
"test", "testing", "unit test", "integration test", "e2e",
"fixture", "mock", "stub", "coverage", "flaky",
],
"design": [
"design", "brand", "typography", "spacing", "visual hierarchy",
"design system", "token", "palette", "icon", "layout grid",
],
"marketing": [
"marketing", "campaign", "content", "copy", "seo", "growth",
"conversion", "ctr", "engagement", "audience", "channel",
],
"mobile": [
"ios", "android", "swift", "swiftui", "kotlin", "jetpack",
"react native", "flutter", "mobile", "app store", "play store",
],
}
def detect_domain(criterion, message, matrix=None, logger=None):
"""
Detect domain from criterion + message text.
Canonical owner: authority-enforcer. Consumers MUST call this function —
they must NOT reimplement keyword matching. Keyword source of truth is
.planning/config/authority-matrix.yaml (domains.<name>.keywords).
"""
text = f"{criterion} {message}".lower()
# Step 1: Prefer keywords loaded from authority-matrix.yaml
if matrix and getattr(matrix, "domains", None):
domain_keywords = {
d.name: list(d.keywords or []) for d in matrix.domains
}
else:
if logger:
logger.warn(
"authority-matrix.yaml unavailable or missing domain "
"keywords; falling back to built-in domain registry"
)
domain_keywords = BUILT_IN_DOMAIN_KEYWORDS
# Step 2: Score domains by keyword hits
scores = {}
for domain, keywords in domain_keywords.items():
score = sum(1 for kw in keywords if kw and kw.lower() in text)
if score > 0:
scores[domain] = score
# Step 3: Return highest-scoring domain; first-declared wins ties
if scores:
ordered = list(domain_keywords.keys())
return max(scores, key=lambda d: (scores[d], -ordered.index(d)))
# Step 4: No match — observable "general" classification
if logger:
preview = (criterion or "")[:80]
logger.debug(
f"domain_detection: no keyword match for finding \"{preview}\"; "
f"returning 'general'"
)
return "general"
Consumer contract (binding):
review-panel MUST call authority-enforcer.detect_domain(...). It MUST NOT define its own keyword list. Any private re-implementation is a P1 regression and must be deleted.review-evaluators MUST call authority-enforcer.detect_domain(...) before filtering findings.authority-matrix.yaml FIRST, then mirror the keyword list into BUILT_IN_DOMAIN_KEYWORDS above in the same commit. CI cross-reference check (see scripts/audit/) enforces parity.Integration Point: Agent spawning
When: Before spawning agents for a wave
Action:
1. Load authority matrix
2. Build domain ownership map from selected agents
3. For each agent:
- Load personality file
- Inject authority constraints via injectAuthorityConstraints()
- Include escalation format instructions (from escalation-protocol.yaml)
- Spawn with enhanced prompt
Integration Point: Post-execution boundary verification
When: Immediately after agent completes a task (before escalation detection)
Action:
1. Run Section 11 Post-Execution Boundary Check
2. Record result (PASS/WARN/ENFORCED) in execution tracker
3. If ENFORCED, revert out-of-scope files before proceeding
4. If WARN, append violation details to SUMMARY.md
Reference: Section 11 of this skill
Integration Point: Escalation detection
When: After agent completes a task (wave-executor Section 5.5)
Action:
1. Wave-executor scans agent output for <escalation> blocks
2. Also processes any escalation blocks generated by Section 11 boundary verification
3. Validates escalation block format against escalation-protocol.yaml
4. Routes by severity according to control mode behavior
5. Records escalations in SUMMARY.md Escalations section
Reference: .planning/config/escalation-protocol.yaml
Integration Point: Finding synthesis
When: After all reviewers submit findings
Action:
1. Collect all findings from reviewers
2. Get list of agents on review panel
3. Call filterFindings() to remove out-of-domain critiques
4. Log removed findings for transparency
5. Synthesize remaining findings into final report
Integration Point: Team assembly
When: Building team for a task
Action:
1. Query agent-registry for candidate agents
2. Check for domain conflicts in proposed team
3. Warn if multiple agents claim same exclusive domain
4. Suggest resolution based on specificity hierarchy
When two agents both claim authority over a topic:
Resolution Steps:
1. Check Specificity Hierarchy:
- More specific domain beats general domain
- Example: "laravel" beats "backend-architecture"
2. Check Division Priority:
- Testing-division overrides for verification topics
- Engineering-division overrides for implementation topics
3. Default to Explicit Assignment:
- Use authority-matrix.yaml as source of truth
- If still ambiguous, require human decision
All authority decisions MUST be logged:
- Timestamp
- Active agents
- Topic in question
- Decision (authorized/domain-owned)
- Domain owner (if applicable)
- Reason
Log Location: `.planning/logs/authority-decisions-{date}.log`
| Error | Cause | Resolution |
|---|---|---|
| Unknown agent in matrix | Agent ID typo or removed agent | Check agent-registry, update matrix |
| Duplicate domain assignment | Two agents claim same exclusive domain | Assign to more specific agent, mark other as secondary |
| Missing authority-matrix.yaml | File deleted or moved | Regenerate from template |
| Circular domain ownership | Agent A yields ownership to B while B yields ownership to A | Fix deferred_by arrays in matrix |
# Validate authority matrix integrity
node bin/gsd-tools.cjs validate-authority-matrix
# Output: ValidationReport with errors/warnings
// 1. Load authority matrix
const matrix = loadAuthorityMatrix('.planning/config/authority-matrix.yaml');
const validation = validateMatrix(matrix);
if (!validation.valid) {
throw new Error(`Invalid matrix: ${validation.errors.join(', ')}`);
}
// 2. Build active agents list
const activeAgents = [
'engineering-security-engineer',
'engineering-backend-architect',
'testing-qa-verification-specialist'
];
// 3. Inject constraints into prompts (with mode profile)
const modeProfile = resolvedSettings.modeProfile; // from workflow-common-core
for (const agentId of activeAgents) {
const basePrompt = loadAgentPersonality(agentId);
const enhancedPrompt = injectAuthorityConstraints(
agentId,
basePrompt,
activeAgents,
modeProfile // NEW: pass resolved mode profile
);
// Spawn agent with enhancedPrompt
}
// 4. During review, filter findings
const findings = collectFindingsFromReviewers();
const { filtered, removed } = filterFindings(findings, activeAgents);
// 5. Log removed findings for transparency
logRemovedFindings(removed);
// 6. Synthesize final report from filtered findings
const report = synthesizeFindings(filtered);
| Version | Date | Changes |
|---|---|---|
| 1.0 | 2026-03-05 | Initial authority enforcer with boundary validation, prompt injection, and finding filtering |
| 1.1 | 2026-03-06 | Added Mode Profile Loading (Section 10) — control mode flag integration |
| 1.2 | 2026-03-31 | Added Post-Execution Boundary Verification (Section 11) — runtime enforcement after agent execution |
Receive the pre-resolved control mode profile from workflow-common-core's Settings Resolution Protocol. The profile is resolved ONCE at invocation start and passed to all authority-enforcer calls — the authority-enforcer does NOT read control-modes.yaml directly.
The resolved profile is a set of 5 boolean flags passed by the caller (wave-executor or review-panel):
| Flag | Type | Effect on Authority Enforcer |
|---|---|---|
authority_enforcement | boolean | When false, skip Section 2 (Boundary Validation) entirely — all agents are authorized |
domain_filtering | boolean | When false, skip Section 4 (Finding Filtering) — all findings are kept regardless of domain ownership |
human_approval_required | boolean | When false, suppress escalation prompts in Section 3 (Prompt Injection) — agents do not remind about human approval |
file_scope_restriction | boolean | When true, add file-scope constraint to Section 3 injected prompts — agents may ONLY modify files in plan files_modified |
read_only | boolean | When true, add read-only constraint to Section 3 injected prompts — agents suggest but do not execute changes |
If no profile is provided (caller does not pass it), default to the guarded profile:
authority_enforcement: true, domain_filtering: true, human_approval_required: truefile_scope_restriction: false, read_only: falseThis ensures backward compatibility — existing callers (including review-panel) that do not yet pass a profile get the same behavior as before.
All earlier sections check flags before executing their logic:
Section 2 (Boundary Validation): if not profile.authority_enforcement: return { authorized: true, reason: "authority enforcement disabled by control mode" }
Section 3 (Prompt Injection): if profile.read_only: append "CONSTRAINT: You are in advisory mode. Suggest changes but do NOT modify any files." if profile.file_scope_restriction: append "CONSTRAINT: You may ONLY modify files listed in the plan's files_modified field." if not profile.human_approval_required: omit the escalation protocol reminder from injected constraints
Section 4 (Finding Filtering): if not profile.domain_filtering: return all findings unfiltered
Section 11 (Post-Execution Boundary Verification): if control_mode is "autonomous" or "advisory": skip verification entirely
Runtime enforcement that verifies agents stayed within their authorized scope after execution completes. Called by wave-executor after each agent finishes.
This verification runs after every agent execution during /legion:build, regardless of control mode. The enforcement action differs by mode:
| Control Mode | Detection | Action on Violation |
|---|---|---|
autonomous | Skip verification entirely | None |
guarded | Detect out-of-scope file modifications | Warn in SUMMARY.md, add escalation block, continue |
advisory | Not applicable (read-only agents) | None |
surgical | Detect out-of-scope file modifications | Revert out-of-scope changes, log violation, continue with in-scope work only |
Post-Execution Boundary Check:
Input:
- agent_id: the agent that just completed
- plan: the PLAN.md that was being executed
- control_mode: from settings.json
Step 1: Skip check if not applicable
- If control_mode is "autonomous" or "advisory": return PASS, skip all checks
- If plan has no files_modified field: return PASS with warning "Plan lacks files_modified — cannot verify boundaries"
Step 2: Detect actual file modifications
- Run: git diff --name-only HEAD (or compare against pre-execution snapshot)
- Collect: list of files actually modified by this agent's execution
Step 3: Compare against authorized scope
- authorized_files = plan.files_modified (from PLAN.md frontmatter)
- actual_files = files detected in Step 2
- out_of_scope = actual_files - authorized_files (set difference)
- If out_of_scope is empty: return PASS
Step 4: Classify violations
For each out-of-scope file:
- severity = "high" if file is in plan.files_forbidden
- severity = "high" if file is a config/infrastructure file (.env, CI/CD, package.json)
- severity = "medium" if file is a source file outside the plan's scope
- severity = "low" if file is a test file or documentation file
Step 5: Enforce based on control mode
If control_mode is "guarded":
a. Log violation to SUMMARY.md:
## ⚠️ Boundary Violation Detected
Agent `{agent_id}` modified files outside authorized scope:
| File | Severity | In files_forbidden? |
|------|----------|-------------------|
| {file} | {severity} | {yes/no} |
Authorized scope: {files_modified list}
b. Add escalation block:
<escalation>
severity: warning
type: scope
decision: Agent {agent_id} modified {count} files outside plan scope
context: The following files were not in the plan's files_modified list: {file_list}. Review these changes and decide whether to keep or revert them.
affected_files: {file_list}
</escalation>
c. Do NOT revert — changes are preserved for human review
d. Return WARN
If control_mode is "surgical":
a. For each out-of-scope file:
- Run: git checkout HEAD -- {file} (revert to pre-execution state)
b. Log reversion to SUMMARY.md:
## 🔒 Surgical Mode: Out-of-Scope Changes Reverted
Agent `{agent_id}` attempted to modify files outside authorized scope.
Reverted {count} files: {file_list}
In-scope changes preserved: {authorized_files that were modified}
c. Return ENFORCED
Step 6: Return result
- PASS: no violations detected
- WARN: violations detected, logged, preserved (guarded mode)
- ENFORCED: violations detected, reverted (surgical mode)
The wave-executor calls this procedure at a specific point in its execution flow:
Wave Execution Flow (updated):
1. Inject agent personality (existing)
2. Inject authority constraints (existing Section 3)
3. Execute agent task (existing)
4. >>> NEW: Run Post-Execution Boundary Check <<<
5. Record execution results (existing)
6. Store outcome to memory (existing)
The boundary check result (PASS/WARN/ENFORCED) is included in the execution tracker's outcome record. WARN results increment the importance score by +1 (cross-scope work signal). ENFORCED results set outcome to "partial" (some work was discarded).
git diff --name-only HEAD which compares against the last commit. This may include changes from prior agents in the same wave — acceptable as a best-effort check.DEPRECATED compatibility shim; workflow-common-core is canonical for all conventions referenced here
Interprets --just-* and --skip-* command flags for /legion:build and /legion:review, validates flag combinations against rules, and resolves the matching team template from intent-teams.yaml. Use when the user passes intent flags to build or review commands, asks about flag combinations, or needs to filter agent teams by intent.
Dev-QA loop engine with structured feedback, fix routing, and user escalation for /legion:review
Executes wave-structured plans with personality-injected agents — parallel or sequential per CLI adapter
Maps all 48 Legion agents by division, capability, and task type for intelligent team assembly
Engine for /legion:map. Analyzes an existing codebase, generates CODEBASE.md for backward-compatible architecture context, and writes .planning/codebase/ index artifacts consumed by /legion:start, /plan, /build, /review, /status, and /quick.