@event4u/agent-config 1.21.0 → 1.22.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agent-src/commands/bug-fix.md +1 -0
- package/.agent-src/commands/bug-investigate.md +1 -0
- package/.agent-src/commands/challenge-me/vision.md +348 -0
- package/.agent-src/commands/challenge-me/with-docs.md +333 -0
- package/.agent-src/commands/challenge-me.md +61 -0
- package/.agent-src/commands/council/default.md +64 -17
- package/.agent-src/commands/create-pr.md +7 -3
- package/.agent-src/commands/grill-me.md +38 -0
- package/.agent-src/commands/judge/steps.md +1 -1
- package/.agent-src/commands/roadmap/ai-council.md +183 -0
- package/.agent-src/commands/roadmap/create.md +6 -1
- package/.agent-src/commands/roadmap/process-full.md +58 -0
- package/.agent-src/commands/roadmap/process-phase.md +69 -0
- package/.agent-src/commands/roadmap/process-step.md +57 -0
- package/.agent-src/commands/roadmap.md +44 -16
- package/.agent-src/commands/threat-model.md +1 -0
- package/.agent-src/contexts/augment-infrastructure.md +1 -1
- package/.agent-src/contexts/communication/rules-auto/slash-command-routing-policy-mechanics.md +53 -18
- package/.agent-src/contexts/execution/roadmap-process-loop.md +125 -0
- package/.agent-src/contexts/skills-and-commands.md +1 -1
- package/.agent-src/rules/improve-before-implement.md +1 -0
- package/.agent-src/rules/invite-challenge.md +71 -0
- package/.agent-src/skills/adversarial-review/SKILL.md +1 -0
- package/.agent-src/skills/ai-council/SKILL.md +132 -8
- package/.agent-src/skills/bug-analyzer/SKILL.md +1 -0
- package/.agent-src/skills/roadmap-management/SKILL.md +7 -7
- package/.agent-src/skills/systematic-debugging/SKILL.md +22 -2
- package/.agent-src/skills/technical-specification/SKILL.md +58 -1
- package/.agent-src/skills/threat-modeling/SKILL.md +1 -0
- package/.agent-src/templates/agent-settings.md +14 -3
- package/.agent-src/templates/command.md +17 -1
- package/.agent-src/templates/roadmaps.md +10 -2
- package/.agent-src/templates/rule.md +2 -0
- package/.agent-src/templates/skill.md +17 -0
- package/.claude-plugin/marketplace.json +9 -2
- package/AGENTS.md +2 -2
- package/CHANGELOG.md +38 -0
- package/README.md +1 -1
- package/config/agent-settings.template.yml +22 -0
- package/docs/architecture.md +2 -2
- package/docs/contracts/command-clusters.md +45 -1
- package/docs/decisions/ADR-003-flat-cluster-subs-and-colon-syntax.md +126 -0
- package/docs/getting-started.md +1 -1
- package/docs/guidelines/agent-infra/naming.md +1 -1
- package/package.json +1 -1
- package/scripts/_phase2_shim_helper.py +1 -1
- package/scripts/council_cli.py +127 -10
- package/scripts/migrate_command_suggestions.py +2 -2
- package/scripts/schemas/command.schema.json +5 -0
- package/scripts/schemas/rule.schema.json +5 -0
- package/scripts/schemas/skill.schema.json +5 -0
- package/scripts/skill_linter.py +1 -1
- package/.agent-src/commands/roadmap/execute.md +0 -109
package/scripts/council_cli.py
CHANGED
|
@@ -63,6 +63,7 @@ def build_members(
|
|
|
63
63
|
*,
|
|
64
64
|
invocation_mode: str | None = None,
|
|
65
65
|
model_overrides: dict[str, str] | None = None,
|
|
66
|
+
siblings_overrides: dict[str, list[str]] | None = None,
|
|
66
67
|
) -> list[ExternalAIClient]:
|
|
67
68
|
"""Construct enabled council members from settings.
|
|
68
69
|
|
|
@@ -73,6 +74,13 @@ def build_members(
|
|
|
73
74
|
`model_overrides` is a per-invocation `{member_name: model_id}`
|
|
74
75
|
map that wins over the per-member `model` in settings. Members not
|
|
75
76
|
listed fall back to the settings value, then the per-client default.
|
|
77
|
+
|
|
78
|
+
`siblings_overrides` is a per-invocation `{member_name: [model, ...]}`
|
|
79
|
+
map that fans the named provider out to multiple sibling models in
|
|
80
|
+
one run (e.g. claude-sonnet-4-5 + claude-opus-4-1). Each model
|
|
81
|
+
becomes its own billable member with independent cost tracking.
|
|
82
|
+
Mutually exclusive with `model_overrides` for the same provider;
|
|
83
|
+
requires `mode=api`; provider must be enabled in settings.
|
|
76
84
|
"""
|
|
77
85
|
ai = (settings.get("ai_council") or {}) if isinstance(settings, dict) else {}
|
|
78
86
|
if not ai.get("enabled"):
|
|
@@ -83,16 +91,34 @@ def build_members(
|
|
|
83
91
|
members_cfg = ai.get("members") or {}
|
|
84
92
|
global_mode = ai.get("mode")
|
|
85
93
|
overrides = model_overrides or {}
|
|
94
|
+
siblings = siblings_overrides or {}
|
|
86
95
|
unknown = set(overrides) - set(members_cfg)
|
|
87
96
|
if unknown:
|
|
88
97
|
raise CouncilDisabledError(
|
|
89
98
|
f"--model targets unknown member(s) {sorted(unknown)!r}; "
|
|
90
99
|
f"known members: {sorted(members_cfg)!r}."
|
|
91
100
|
)
|
|
101
|
+
unknown_sib = set(siblings) - set(members_cfg)
|
|
102
|
+
if unknown_sib:
|
|
103
|
+
raise CouncilDisabledError(
|
|
104
|
+
f"--siblings targets unknown member(s) {sorted(unknown_sib)!r}; "
|
|
105
|
+
f"known members: {sorted(members_cfg)!r}."
|
|
106
|
+
)
|
|
107
|
+
conflict = set(overrides) & set(siblings)
|
|
108
|
+
if conflict:
|
|
109
|
+
raise CouncilDisabledError(
|
|
110
|
+
f"--model and --siblings target the same member(s) {sorted(conflict)!r}; "
|
|
111
|
+
f"pick one per provider per invocation."
|
|
112
|
+
)
|
|
92
113
|
members: list[ExternalAIClient] = []
|
|
93
114
|
for name, cfg in members_cfg.items():
|
|
94
115
|
cfg = cfg or {}
|
|
95
116
|
if not cfg.get("enabled"):
|
|
117
|
+
if name in siblings:
|
|
118
|
+
raise CouncilDisabledError(
|
|
119
|
+
f"--siblings targets member {name!r} but it is not "
|
|
120
|
+
f"enabled in .agent-settings.yml (ai_council.members.{name}.enabled)."
|
|
121
|
+
)
|
|
96
122
|
continue
|
|
97
123
|
mode = resolve_mode(
|
|
98
124
|
name,
|
|
@@ -100,13 +126,17 @@ def build_members(
|
|
|
100
126
|
member_settings=cfg,
|
|
101
127
|
global_mode=global_mode,
|
|
102
128
|
)
|
|
129
|
+
if name in siblings:
|
|
130
|
+
if mode != "api":
|
|
131
|
+
raise CouncilDisabledError(
|
|
132
|
+
f"--siblings requires mode=api for member {name!r} (got {mode!r})."
|
|
133
|
+
)
|
|
134
|
+
for sib_model in siblings[name]:
|
|
135
|
+
members.append(_construct_api_member(name, sib_model))
|
|
136
|
+
continue
|
|
103
137
|
model = overrides.get(name) or cfg.get("model")
|
|
104
|
-
if mode == "api" and name
|
|
105
|
-
members.append(
|
|
106
|
-
api_key=load_anthropic_key()))
|
|
107
|
-
elif mode == "api" and name == "openai":
|
|
108
|
-
members.append(OpenAIClient(model=model or "gpt-4o",
|
|
109
|
-
api_key=load_openai_key()))
|
|
138
|
+
if mode == "api" and name in {"anthropic", "openai"}:
|
|
139
|
+
members.append(_construct_api_member(name, model))
|
|
110
140
|
elif mode == "manual":
|
|
111
141
|
members.append(ManualClient(name=name, model=model or "manual"))
|
|
112
142
|
elif mode == "playwright":
|
|
@@ -125,6 +155,19 @@ def build_members(
|
|
|
125
155
|
return members
|
|
126
156
|
|
|
127
157
|
|
|
158
|
+
def _construct_api_member(name: str, model: str | None) -> ExternalAIClient:
|
|
159
|
+
"""Build an api-mode client for a known provider name."""
|
|
160
|
+
if name == "anthropic":
|
|
161
|
+
return AnthropicClient(model=model or "claude-sonnet-4-5",
|
|
162
|
+
api_key=load_anthropic_key())
|
|
163
|
+
if name == "openai":
|
|
164
|
+
return OpenAIClient(model=model or "gpt-4o",
|
|
165
|
+
api_key=load_openai_key())
|
|
166
|
+
raise CouncilDisabledError(
|
|
167
|
+
f"member {name!r} has no api transport (known: anthropic, openai)."
|
|
168
|
+
)
|
|
169
|
+
|
|
170
|
+
|
|
128
171
|
def build_question(
|
|
129
172
|
*,
|
|
130
173
|
input_path: Path,
|
|
@@ -164,6 +207,29 @@ def format_estimate_table(
|
|
|
164
207
|
# ── subcommands ─────────────────────────────────────────────────────
|
|
165
208
|
|
|
166
209
|
|
|
210
|
+
def _resolve_rounds(args: argparse.Namespace, ai_cfg: dict[str, Any]) -> int:
|
|
211
|
+
"""Resolve effective debate round count from CLI args + settings.
|
|
212
|
+
|
|
213
|
+
Resolution chain (highest priority first):
|
|
214
|
+
1. ``--rounds N`` — explicit user override, any value.
|
|
215
|
+
2. ``--depth deep`` — uses ``ai_council.deep_min_rounds``,
|
|
216
|
+
floored at ``min_rounds`` so the deep tier is monotonic.
|
|
217
|
+
3. ``ai_council.min_rounds`` — default 2.
|
|
218
|
+
|
|
219
|
+
Sub-commands (rule/skill/command) declare ``council_depth: deep``
|
|
220
|
+
in their frontmatter; the host agent reads that and translates it
|
|
221
|
+
to ``--depth deep`` on the CLI invocation. The CLI itself stays
|
|
222
|
+
unaware of frontmatter — the contract is the flag.
|
|
223
|
+
"""
|
|
224
|
+
if getattr(args, "rounds", None) is not None:
|
|
225
|
+
return int(args.rounds)
|
|
226
|
+
min_rounds = int(ai_cfg.get("min_rounds", 2))
|
|
227
|
+
if getattr(args, "depth", "standard") == "deep":
|
|
228
|
+
deep = int(ai_cfg.get("deep_min_rounds", min_rounds))
|
|
229
|
+
return max(deep, min_rounds)
|
|
230
|
+
return min_rounds
|
|
231
|
+
|
|
232
|
+
|
|
167
233
|
def cmd_estimate(
|
|
168
234
|
args: argparse.Namespace,
|
|
169
235
|
*,
|
|
@@ -179,6 +245,7 @@ def cmd_estimate(
|
|
|
179
245
|
settings,
|
|
180
246
|
invocation_mode=args.mode_override,
|
|
181
247
|
model_overrides=_parse_model_overrides(getattr(args, "model", None)),
|
|
248
|
+
siblings_overrides=_parse_siblings_overrides(getattr(args, "siblings", None)),
|
|
182
249
|
)
|
|
183
250
|
if table is None:
|
|
184
251
|
table = load_prices()
|
|
@@ -239,6 +306,7 @@ def cmd_run(
|
|
|
239
306
|
settings,
|
|
240
307
|
invocation_mode=args.mode_override,
|
|
241
308
|
model_overrides=_parse_model_overrides(getattr(args, "model", None)),
|
|
309
|
+
siblings_overrides=_parse_siblings_overrides(getattr(args, "siblings", None)),
|
|
242
310
|
)
|
|
243
311
|
if table is None:
|
|
244
312
|
table = load_prices()
|
|
@@ -271,7 +339,7 @@ def cmd_run(
|
|
|
271
339
|
max_calls=int(cost_cfg.get("max_calls", 10)),
|
|
272
340
|
max_total_usd=float(cost_cfg.get("max_total_usd", 0.0) or 0.0),
|
|
273
341
|
)
|
|
274
|
-
rounds = args
|
|
342
|
+
rounds = _resolve_rounds(args, ai_cfg)
|
|
275
343
|
responses = consult(
|
|
276
344
|
members, question, budget,
|
|
277
345
|
table=table, project=project,
|
|
@@ -339,6 +407,38 @@ def _parse_model_overrides(items: list[str] | None) -> dict[str, str]:
|
|
|
339
407
|
return out
|
|
340
408
|
|
|
341
409
|
|
|
410
|
+
def _parse_siblings_overrides(items: list[str] | None) -> dict[str, list[str]]:
|
|
411
|
+
"""Parse repeated `--siblings name=model1,model2[,...]` flags.
|
|
412
|
+
|
|
413
|
+
Requires ≥ 2 distinct, non-empty models per provider — sibling
|
|
414
|
+
mode without diversity has no purpose. Repeating the same provider
|
|
415
|
+
flag is rejected as ambiguous.
|
|
416
|
+
"""
|
|
417
|
+
out: dict[str, list[str]] = {}
|
|
418
|
+
for raw in items or []:
|
|
419
|
+
if "=" not in raw:
|
|
420
|
+
raise argparse.ArgumentTypeError(
|
|
421
|
+
f"--siblings expects '<member>=<model1>,<model2>[,...]', got {raw!r}."
|
|
422
|
+
)
|
|
423
|
+
name, models_csv = raw.split("=", 1)
|
|
424
|
+
name = name.strip()
|
|
425
|
+
models = [m.strip() for m in models_csv.split(",") if m.strip()]
|
|
426
|
+
if not name or not models:
|
|
427
|
+
raise argparse.ArgumentTypeError(
|
|
428
|
+
f"--siblings member and model list must both be non-empty: {raw!r}."
|
|
429
|
+
)
|
|
430
|
+
if len(set(models)) < 2:
|
|
431
|
+
raise argparse.ArgumentTypeError(
|
|
432
|
+
f"--siblings requires ≥ 2 distinct models for {name!r}, got {models!r}."
|
|
433
|
+
)
|
|
434
|
+
if name in out:
|
|
435
|
+
raise argparse.ArgumentTypeError(
|
|
436
|
+
f"--siblings repeated for member {name!r}; combine into one flag."
|
|
437
|
+
)
|
|
438
|
+
out[name] = models
|
|
439
|
+
return out
|
|
440
|
+
|
|
441
|
+
|
|
342
442
|
def _add_common_input_args(p: argparse.ArgumentParser) -> None:
|
|
343
443
|
p.add_argument("question", type=str,
|
|
344
444
|
help="Path to the question file (text or roadmap).")
|
|
@@ -356,6 +456,16 @@ def _add_common_input_args(p: argparse.ArgumentParser) -> None:
|
|
|
356
456
|
"Wins over `ai_council.members.<name>.model` in "
|
|
357
457
|
".agent-settings.yml; the settings file is not "
|
|
358
458
|
"modified.")
|
|
459
|
+
p.add_argument("--siblings", action="append", default=None, dest="siblings",
|
|
460
|
+
metavar="MEMBER=MODEL1,MODEL2[,...]",
|
|
461
|
+
help="Fan one provider out to ≥ 2 sibling models in a "
|
|
462
|
+
"single run, e.g. --siblings anthropic=claude-sonnet-4-5,"
|
|
463
|
+
"claude-opus-4-1. Each model becomes its own billable "
|
|
464
|
+
"member with independent cost tracking. Mutually "
|
|
465
|
+
"exclusive with --model for the same provider; "
|
|
466
|
+
"requires the provider to be enabled with mode=api. "
|
|
467
|
+
"Single-provider degraded-run strategy per ai-council "
|
|
468
|
+
"skill.")
|
|
359
469
|
p.add_argument("--original-ask", default="",
|
|
360
470
|
help="The user's framing sentence (flows into handoff).")
|
|
361
471
|
|
|
@@ -377,9 +487,16 @@ def build_parser() -> argparse.ArgumentParser:
|
|
|
377
487
|
p_run.add_argument("--confirm", action="store_true",
|
|
378
488
|
help="Required to actually invoke the council.")
|
|
379
489
|
p_run.add_argument("--rounds", type=int, default=None,
|
|
380
|
-
help="Number of debate rounds (1-3).
|
|
381
|
-
"
|
|
382
|
-
"(or 2 if unset).")
|
|
490
|
+
help="Number of debate rounds (1-3). Explicit override; "
|
|
491
|
+
"wins over --depth. Defaults to ai_council.min_rounds "
|
|
492
|
+
"in .agent-settings.yml (or 2 if unset).")
|
|
493
|
+
p_run.add_argument("--depth", choices=["standard", "deep"], default="standard",
|
|
494
|
+
help="Reasoning-depth tier. 'deep' floors rounds at "
|
|
495
|
+
"ai_council.deep_min_rounds (max'd with min_rounds) "
|
|
496
|
+
"for architecture, refactoring, or bug-diagnosis "
|
|
497
|
+
"artefacts. Set by the host agent when the consuming "
|
|
498
|
+
"rule/skill/command declares council_depth: deep. "
|
|
499
|
+
"Overridden by explicit --rounds.")
|
|
383
500
|
|
|
384
501
|
p_ren = sub.add_parser("render", help="Re-render a saved responses JSON.")
|
|
385
502
|
p_ren.add_argument("responses",
|
|
@@ -29,7 +29,7 @@ INELIGIBLE: dict[str, str] = {
|
|
|
29
29
|
"copilot-agents-init": "Project init — only deliberately during onboarding.",
|
|
30
30
|
"copilot-agents-optimize": "Maintenance refactor; only when the maintainer chooses to run it.",
|
|
31
31
|
"do-and-judge": "Subagent orchestration — overlaps /work and judge skills; keep explicit.",
|
|
32
|
-
"do-in-steps": "Subagent orchestration — overlaps /work and /roadmap
|
|
32
|
+
"do-in-steps": "Subagent orchestration — overlaps /work and /roadmap:process-*; keep explicit.",
|
|
33
33
|
"fix-portability": "Package-internal — only the event4u/agent-config repo runs this.",
|
|
34
34
|
"fix-references": "Package-internal — only the event4u/agent-config repo runs this.",
|
|
35
35
|
"judge": "Sibling of /review-changes — eligibility routed there; keep this explicit.",
|
|
@@ -89,7 +89,7 @@ ELIGIBLE: dict[str, tuple[str, str]] = {
|
|
|
89
89
|
"review-changes": ("self-review my changes, judge this diff before PR", "uncommitted or staged changes pre-PR"),
|
|
90
90
|
"review-routing": ("who should review this, suggest reviewers for this PR", "PR open without assigned reviewers"),
|
|
91
91
|
"roadmap-create": ("create a roadmap for X, plan this work as a roadmap", "multi-phase work without an existing agents/roadmaps/*.md"),
|
|
92
|
-
"roadmap-execute": ("
|
|
92
|
+
"roadmap-execute": ("process the roadmap, work through the roadmap autonomously, finish this phase", "existing agents/roadmaps/*.md referenced in the prompt"),
|
|
93
93
|
"rule-compliance-audit": ("audit my rules, check rule trigger quality", "maintainer working on .augment/rules/ files"),
|
|
94
94
|
"tests-create": ("write tests for these changes, add tests for this branch", "code changes on the branch without matching test changes"),
|
|
95
95
|
"tests-execute": ("run the tests, execute the test suite", "code changes pending verification"),
|
|
@@ -49,6 +49,11 @@
|
|
|
49
49
|
"pattern": "^[0-9]+\\.[0-9]+\\.[0-9]+$",
|
|
50
50
|
"description": "Semver release in which this command became a shim (e.g. '1.15.0')."
|
|
51
51
|
},
|
|
52
|
+
"council_depth": {
|
|
53
|
+
"type": "string",
|
|
54
|
+
"enum": ["deep"],
|
|
55
|
+
"description": "Optional reasoning-depth marker for AI Council invocations triggered by this command. The only accepted value is 'deep'; omit the key for default depth (setting 'standard' is rejected — every frontmatter byte counts against the context window, and 'standard' is the implicit default). 'deep' instructs the host agent to pass --depth deep to council_cli, which floors rounds at max(ai_council.deep_min_rounds, ai_council.min_rounds). Use for architecture, refactoring, or bug-diagnosis commands. See .agent-src.uncompressed/skills/ai-council/SKILL.md."
|
|
56
|
+
},
|
|
52
57
|
"suggestion": {
|
|
53
58
|
"type": "object",
|
|
54
59
|
"additionalProperties": false,
|
|
@@ -47,6 +47,11 @@
|
|
|
47
47
|
"enum": ["1", "2a", "2b", "3", "safety-floor", "mechanical-already", "kernel", "tier-1", "tier-2"],
|
|
48
48
|
"description": "Hardening tier. Legacy values (1/2a/2b/3/safety-floor/mechanical-already) accepted; new router-canonical values (kernel/tier-1/tier-2) introduced by road-to-kernel-and-router.md Phase 4."
|
|
49
49
|
},
|
|
50
|
+
"council_depth": {
|
|
51
|
+
"type": "string",
|
|
52
|
+
"enum": ["deep"],
|
|
53
|
+
"description": "Optional reasoning-depth marker for AI Council invocations triggered while this rule is active. The only accepted value is 'deep'; omit the key for default depth (setting 'standard' is rejected — every frontmatter byte counts against the context window, and 'standard' is the implicit default). 'deep' instructs the host agent to pass --depth deep to council_cli, which floors rounds at max(ai_council.deep_min_rounds, ai_council.min_rounds). Use for rules that gate architecture, refactoring, or bug-diagnosis flows. See .agent-src.uncompressed/skills/ai-council/SKILL.md."
|
|
54
|
+
},
|
|
50
55
|
"triggers": {
|
|
51
56
|
"type": "array",
|
|
52
57
|
"items": {
|
|
@@ -42,6 +42,11 @@
|
|
|
42
42
|
"enum": ["senior"],
|
|
43
43
|
"description": "Optional tier marker. `senior` opts the skill into the Senior-Tier Required Structure check (Context-First lead, Related Skills, Proactive Triggers, Output Artifacts) per .agent-src.uncompressed/rules/skill-quality.md."
|
|
44
44
|
},
|
|
45
|
+
"council_depth": {
|
|
46
|
+
"type": "string",
|
|
47
|
+
"enum": ["deep"],
|
|
48
|
+
"description": "Optional reasoning-depth marker for AI Council invocations triggered by this skill. The only accepted value is 'deep'; omit the key for default depth (setting 'standard' is rejected — every frontmatter byte counts against the context window, and 'standard' is the implicit default). 'deep' instructs the host agent to pass --depth deep to council_cli, which floors rounds at max(ai_council.deep_min_rounds, ai_council.min_rounds). Use for architecture, refactoring, or bug-diagnosis skills. See .agent-src.uncompressed/skills/ai-council/SKILL.md."
|
|
49
|
+
},
|
|
45
50
|
"execution": {
|
|
46
51
|
"type": "object",
|
|
47
52
|
"additionalProperties": false,
|
package/scripts/skill_linter.py
CHANGED
|
@@ -1042,7 +1042,7 @@ def _lint_command_suggestion_block(text: str) -> List[Issue]:
|
|
|
1042
1042
|
suggestion = data.get("suggestion")
|
|
1043
1043
|
if suggestion is None:
|
|
1044
1044
|
issues.append(Issue(
|
|
1045
|
-
"
|
|
1045
|
+
"error", "missing_suggestion_block",
|
|
1046
1046
|
"Command frontmatter is missing the 'suggestion' block — required by "
|
|
1047
1047
|
"road-to-context-aware-command-suggestion Phase 2.",
|
|
1048
1048
|
))
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
name: roadmap:execute
|
|
3
|
-
cluster: roadmap
|
|
4
|
-
sub: execute
|
|
5
|
-
skills: [agent-docs-writing]
|
|
6
|
-
description: Read and interactively execute a roadmap from agents/roadmaps/
|
|
7
|
-
disable-model-invocation: true
|
|
8
|
-
suggestion:
|
|
9
|
-
eligible: true
|
|
10
|
-
trigger_description: "execute the roadmap, work through the roadmap step by step"
|
|
11
|
-
trigger_context: "existing agents/roadmaps/*.md referenced in the prompt"
|
|
12
|
-
---
|
|
13
|
-
|
|
14
|
-
# /roadmap execute
|
|
15
|
-
## Instructions
|
|
16
|
-
|
|
17
|
-
### 1. Find the roadmap
|
|
18
|
-
|
|
19
|
-
- List all roadmap files: `agents/roadmaps/*.md` (project root) and `app/Modules/*/agents/roadmaps/*.md` (modules).
|
|
20
|
-
- Exclude `template.md`.
|
|
21
|
-
- If only one roadmap exists → use it (confirm with user).
|
|
22
|
-
- If multiple exist → present a numbered list and let the user choose.
|
|
23
|
-
- If none exist → tell the user and suggest running `roadmap-create`.
|
|
24
|
-
|
|
25
|
-
### 2. Read and understand the roadmap
|
|
26
|
-
|
|
27
|
-
- Read the full roadmap file.
|
|
28
|
-
- Identify the **phases** and **steps/tasks** within each phase.
|
|
29
|
-
- Determine which steps are already completed (look for checkboxes `[x]`, status markers, or "done" notes).
|
|
30
|
-
- Present a summary to the user:
|
|
31
|
-
> "Roadmap: {title}"
|
|
32
|
-
> "Phase 1: {name} — 3/5 Schritte erledigt"
|
|
33
|
-
> "Phase 2: {name} — noch nicht begonnen"
|
|
34
|
-
> "Next open step: {step description}"
|
|
35
|
-
|
|
36
|
-
### 3. Resolve quality cadence (read once, before any step runs)
|
|
37
|
-
|
|
38
|
-
Read `roadmap.quality_cadence` from `.agent-settings.yml`:
|
|
39
|
-
|
|
40
|
-
| Value | When the project's quality pipeline runs |
|
|
41
|
-
|---|---|
|
|
42
|
-
| `end_of_roadmap` (default) | Once, in step 7 — before archiving |
|
|
43
|
-
| `per_phase` | Once after every completed phase, plus step 7 |
|
|
44
|
-
| `per_step` | After every completed step, plus step 7 (legacy verbose) |
|
|
45
|
-
|
|
46
|
-
Missing key, unreadable file, or unknown value → fall back to `end_of_roadmap`.
|
|
47
|
-
Cite the resolved cadence once in step 2's summary so the user can override it.
|
|
48
|
-
|
|
49
|
-
The Iron Law `verify-before-complete` still applies — fresh quality
|
|
50
|
-
output is mandatory before any "roadmap complete" claim, regardless of
|
|
51
|
-
cadence. Step checkboxes and `agents/roadmaps-progress.md` are ALWAYS
|
|
52
|
-
updated in the same response per `roadmap-progress-sync`; cadence only
|
|
53
|
-
gates the *quality pipeline*, not progress tracking.
|
|
54
|
-
|
|
55
|
-
### 4. Execute step by step
|
|
56
|
-
|
|
57
|
-
For each open step:
|
|
58
|
-
|
|
59
|
-
1. **Summarize** what needs to be done (in the user's language).
|
|
60
|
-
2. **Analyze** the codebase to understand what's needed for this step.
|
|
61
|
-
3. **Present a plan** — what files to change, what approach to take.
|
|
62
|
-
4. **Ask for confirmation**: "Should I implement this step?"
|
|
63
|
-
- If yes → implement, mark the step `[x]` in the roadmap file.
|
|
64
|
-
- If no / skip → move to the next step.
|
|
65
|
-
- If the user wants to stop → stop and summarize progress.
|
|
66
|
-
|
|
67
|
-
### 5. After each step
|
|
68
|
-
|
|
69
|
-
- Update the roadmap file: mark the completed step `[x]` (or `[~]` / `[-]`).
|
|
70
|
-
- Regenerate `agents/roadmaps-progress.md` — `./agent-config roadmap:progress`.
|
|
71
|
-
- **Quality pipeline** — run only when `quality_cadence: per_step`.
|
|
72
|
-
Otherwise skip and proceed.
|
|
73
|
-
- Ask: "Continue with the next step?"
|
|
74
|
-
|
|
75
|
-
### 6. After all steps in a phase
|
|
76
|
-
|
|
77
|
-
- Summarize what was accomplished in the phase.
|
|
78
|
-
- **Quality pipeline** — run when `quality_cadence: per_phase` (or `per_step`).
|
|
79
|
-
Skip when `end_of_roadmap`.
|
|
80
|
-
- Ask: "Phase {N} complete. Continue with Phase {N+1}?"
|
|
81
|
-
|
|
82
|
-
### 7. When done (or stopped)
|
|
83
|
-
|
|
84
|
-
- Summarize total progress: steps completed, steps remaining.
|
|
85
|
-
- Update the roadmap file with the current status.
|
|
86
|
-
- Regenerate the dashboard one last time so it matches the final state.
|
|
87
|
-
- **If ALL steps are done** → run the project's quality pipeline now
|
|
88
|
-
(this is the `verify-before-complete` evidence gate; required for
|
|
89
|
-
every cadence value, including `end_of_roadmap`). On green, trigger
|
|
90
|
-
the completion & archiving workflow from the `roadmap-management`
|
|
91
|
-
skill. On red, stop, surface the failures, do not archive.
|
|
92
|
-
|
|
93
|
-
### Rules
|
|
94
|
-
|
|
95
|
-
- **Commits are governed by [`commit-policy`](../rules/commit-policy.md).**
|
|
96
|
-
By default: only apply local changes and update the roadmap file — no commits.
|
|
97
|
-
- If the roadmap **does not** contain explicit commit steps → never commit, never ask.
|
|
98
|
-
- If the roadmap **does** contain explicit commit steps:
|
|
99
|
-
- **Non-autonomous** (`personal.autonomy: off`, or `auto` before opt-in) →
|
|
100
|
-
ask before each commit step.
|
|
101
|
-
- **Autonomous** (`personal.autonomy: on`, or `auto` after opt-in) →
|
|
102
|
-
pre-scan the roadmap **before starting**, ask **once** upfront whether
|
|
103
|
-
to execute the listed commit steps, then proceed silently per the answer.
|
|
104
|
-
- **Push, merge, branch, PR, tag** stay permission-gated by [`scope-control`](../rules/scope-control.md#git-operations--permission-gated).
|
|
105
|
-
- **Always ask before implementing** a step — never auto-execute.
|
|
106
|
-
- **Quality cadence** is set by `roadmap.quality_cadence` (see step 3).
|
|
107
|
-
Step 7 always runs the pipeline before archival regardless of cadence.
|
|
108
|
-
- If a step is unclear or too large, suggest breaking it down further.
|
|
109
|
-
- If a step reveals a problem not covered in the roadmap, flag it to the user.
|