@hanzlaa/rcode 4.10.0 → 4.10.2
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/package.json +1 -1
- package/rcode/agents/rcode-haitham.md +1 -0
- package/rcode/agents/rcode-hanzla.md +1 -0
- package/rcode/agents/rcode-omar.md +1 -0
- package/rcode/agents/rcode-waleed.md +1 -0
- package/rcode/agents/rcode-yousef.md +1 -0
- package/rcode/bin/lib/council-panel.cjs +32 -22
- package/rcode/references/planner-playbook.md +18 -0
- package/rcode/workflows/council.md +20 -4
- package/rcode/workflows/do.md +45 -0
- package/rcode/workflows/execute-sprint.md +51 -3
- package/rcode/workflows/map-codebase.md +11 -4
- package/rcode/workflows/plan.md +1 -1
- package/server/lib/html/client/views/DecisionsView.js +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hanzlaa/rcode",
|
|
3
|
-
"version": "4.10.
|
|
3
|
+
"version": "4.10.2",
|
|
4
4
|
"description": "rcode — the AI team that never forgets. Persistent memory, specialist agents, and slash commands for AI IDEs. Works in Claude Code, Cursor, Gemini, VS Code, and Antigravity.",
|
|
5
5
|
"main": "cli/index.js",
|
|
6
6
|
"bin": {
|
|
@@ -19,6 +19,7 @@ color: cyan
|
|
|
19
19
|
@.rcode/references/response-style.md
|
|
20
20
|
@.rcode/references/codebase-grounding.md
|
|
21
21
|
@.rcode/references/karpathy-guidelines.md
|
|
22
|
+
@.rcode/references/persona-executor-mode.md
|
|
22
23
|
@.rcode/references/persona-engineer-shared.md
|
|
23
24
|
@.rcode/skills/agents/haitham-frontend/SKILL.md
|
|
24
25
|
|
|
@@ -17,6 +17,7 @@ color: green
|
|
|
17
17
|
@.rcode/references/response-style.md
|
|
18
18
|
@.rcode/references/codebase-grounding.md
|
|
19
19
|
@.rcode/references/karpathy-guidelines.md
|
|
20
|
+
@.rcode/references/persona-executor-mode.md
|
|
20
21
|
@.rcode/references/persona-engineer-shared.md
|
|
21
22
|
|
|
22
23
|
# Omar (عمر) — Software Engineer (generalist)
|
|
@@ -17,6 +17,7 @@ color: green
|
|
|
17
17
|
@.rcode/references/agent-shared-rules.md
|
|
18
18
|
@.rcode/references/codebase-grounding.md
|
|
19
19
|
@.rcode/references/karpathy-guidelines.md
|
|
20
|
+
@.rcode/references/persona-executor-mode.md
|
|
20
21
|
@.rcode/skills/agents/waleed-architect/SKILL.md
|
|
21
22
|
|
|
22
23
|
## Grounding rule (mandatory)
|
|
@@ -18,6 +18,7 @@ color: blue
|
|
|
18
18
|
@.rcode/references/response-style.md
|
|
19
19
|
@.rcode/references/codebase-grounding.md
|
|
20
20
|
@.rcode/references/karpathy-guidelines.md
|
|
21
|
+
@.rcode/references/persona-executor-mode.md
|
|
21
22
|
@.rcode/references/persona-engineer-shared.md
|
|
22
23
|
@.rcode/skills/agents/yousef-backend/SKILL.md
|
|
23
24
|
|
|
@@ -404,11 +404,21 @@ function normalize(question) {
|
|
|
404
404
|
.trim();
|
|
405
405
|
}
|
|
406
406
|
|
|
407
|
+
function escapeRegExp(s) {
|
|
408
|
+
return s.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
|
|
409
|
+
}
|
|
410
|
+
|
|
411
|
+
function matchesKeyword(text, word) {
|
|
412
|
+
// Word-boundary match, not substring — avoids collisions like
|
|
413
|
+
// "storage" containing "rag" (#1034 follow-up).
|
|
414
|
+
return new RegExp('\\b' + escapeRegExp(word) + '\\b').test(text);
|
|
415
|
+
}
|
|
416
|
+
|
|
407
417
|
function scoreAgent(agentId, normalizedQuestion) {
|
|
408
418
|
const keywords = KEYWORDS[agentId] || [];
|
|
409
419
|
let score = 0;
|
|
410
420
|
for (const { word, weight } of keywords) {
|
|
411
|
-
if (normalizedQuestion
|
|
421
|
+
if (matchesKeyword(normalizedQuestion, word)) score += weight;
|
|
412
422
|
}
|
|
413
423
|
const names = AGENT_NAMES[agentId] || [];
|
|
414
424
|
for (const name of names) {
|
|
@@ -419,30 +429,30 @@ function scoreAgent(agentId, normalizedQuestion) {
|
|
|
419
429
|
}
|
|
420
430
|
|
|
421
431
|
function applyPriorityBoosts(scores, normalizedQuestion) {
|
|
422
|
-
if (SADIQ_TRIGGERS.some((t) => normalizedQuestion
|
|
432
|
+
if (SADIQ_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
423
433
|
scores.sadiq = (scores.sadiq || 0) + 5;
|
|
424
434
|
}
|
|
425
|
-
if (PM_TRIGGERS.some((t) => normalizedQuestion
|
|
435
|
+
if (PM_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
426
436
|
scores['hussain-pm'] = (scores['hussain-pm'] || 0) + 3;
|
|
427
437
|
}
|
|
428
|
-
if (MARKET_TRIGGERS.some((t) => normalizedQuestion
|
|
438
|
+
if (MARKET_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
429
439
|
scores.mariam = (scores.mariam || 0) + 6; // Mariam leads market questions
|
|
430
440
|
scores['hussain-pm'] = (scores['hussain-pm'] || 0) + 3; // PM follows for scoping
|
|
431
441
|
}
|
|
432
442
|
// Domain boosts — lift the right technical expert when signal is clear
|
|
433
|
-
if (FE_TRIGGERS.some((t) => normalizedQuestion
|
|
443
|
+
if (FE_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
434
444
|
scores.haitham = (scores.haitham || 0) + 4;
|
|
435
445
|
}
|
|
436
|
-
if (BE_TRIGGERS.some((t) => normalizedQuestion
|
|
446
|
+
if (BE_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
437
447
|
scores.yousef = (scores.yousef || 0) + 4;
|
|
438
448
|
}
|
|
439
|
-
if (ML_TRIGGERS.some((t) => normalizedQuestion
|
|
449
|
+
if (ML_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
440
450
|
scores.zayd = (scores.zayd || 0) + 4;
|
|
441
451
|
}
|
|
442
|
-
if (DEPLOY_TRIGGERS.some((t) => normalizedQuestion
|
|
452
|
+
if (DEPLOY_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
443
453
|
scores.khalid = (scores.khalid || 0) + 4;
|
|
444
454
|
}
|
|
445
|
-
if (QUALITY_TRIGGERS.some((t) => normalizedQuestion
|
|
455
|
+
if (QUALITY_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t))) {
|
|
446
456
|
scores.fatima = (scores.fatima || 0) + 4;
|
|
447
457
|
}
|
|
448
458
|
return scores;
|
|
@@ -453,16 +463,16 @@ function applyPriorityBoosts(scores, normalizedQuestion) {
|
|
|
453
463
|
* Returns: 'fe' | 'be' | 'ml' | 'deploy' | 'quality' | 'market' | 'strategic' | 'general'
|
|
454
464
|
*/
|
|
455
465
|
function detectDomain(normalizedQuestion, scores) {
|
|
456
|
-
const isMarket = MARKET_TRIGGERS.some((t) => normalizedQuestion
|
|
466
|
+
const isMarket = MARKET_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t));
|
|
457
467
|
if (isMarket) return 'market';
|
|
458
468
|
|
|
459
|
-
const isStrategic = SADIQ_TRIGGERS.some((t) => normalizedQuestion
|
|
469
|
+
const isStrategic = SADIQ_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t));
|
|
460
470
|
|
|
461
|
-
const feTrigger = FE_TRIGGERS.some((t) => normalizedQuestion
|
|
462
|
-
const beTrigger = BE_TRIGGERS.some((t) => normalizedQuestion
|
|
463
|
-
const mlTrigger = ML_TRIGGERS.some((t) => normalizedQuestion
|
|
464
|
-
const deployTrigger = DEPLOY_TRIGGERS.some((t) => normalizedQuestion
|
|
465
|
-
const qualityTrigger = QUALITY_TRIGGERS.some((t) => normalizedQuestion
|
|
471
|
+
const feTrigger = FE_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t));
|
|
472
|
+
const beTrigger = BE_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t));
|
|
473
|
+
const mlTrigger = ML_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t));
|
|
474
|
+
const deployTrigger = DEPLOY_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t));
|
|
475
|
+
const qualityTrigger = QUALITY_TRIGGERS.some((t) => matchesKeyword(normalizedQuestion, t));
|
|
466
476
|
|
|
467
477
|
// Multiple technical domains present — fall back to top-scoring agent
|
|
468
478
|
const technicalCount = [feTrigger, beTrigger, mlTrigger, deployTrigger, qualityTrigger].filter(Boolean).length;
|
|
@@ -566,12 +576,12 @@ function explainSelection(question, opts = {}) {
|
|
|
566
576
|
const panel = selectPanel(question, opts);
|
|
567
577
|
return {
|
|
568
578
|
question, normalized, scores, panel, domain,
|
|
569
|
-
sadiq_triggered: SADIQ_TRIGGERS.some((t) => normalized
|
|
570
|
-
pm_triggered: PM_TRIGGERS.some((t) => normalized
|
|
571
|
-
fe_triggered: FE_TRIGGERS.some((t) => normalized
|
|
572
|
-
be_triggered: BE_TRIGGERS.some((t) => normalized
|
|
573
|
-
ml_triggered: ML_TRIGGERS.some((t) => normalized
|
|
574
|
-
deploy_triggered: DEPLOY_TRIGGERS.some((t) => normalized
|
|
579
|
+
sadiq_triggered: SADIQ_TRIGGERS.some((t) => matchesKeyword(normalized, t)),
|
|
580
|
+
pm_triggered: PM_TRIGGERS.some((t) => matchesKeyword(normalized, t)),
|
|
581
|
+
fe_triggered: FE_TRIGGERS.some((t) => matchesKeyword(normalized, t)),
|
|
582
|
+
be_triggered: BE_TRIGGERS.some((t) => matchesKeyword(normalized, t)),
|
|
583
|
+
ml_triggered: ML_TRIGGERS.some((t) => matchesKeyword(normalized, t)),
|
|
584
|
+
deploy_triggered: DEPLOY_TRIGGERS.some((t) => matchesKeyword(normalized, t)),
|
|
575
585
|
};
|
|
576
586
|
}
|
|
577
587
|
|
|
@@ -74,6 +74,7 @@ depends_on: [sprint-id, ...]
|
|
|
74
74
|
files_modified: [paths...]
|
|
75
75
|
autonomous: true | false # false if has checkpoints
|
|
76
76
|
requirements: [REQ-01, REQ-02] # MUST NOT be empty
|
|
77
|
+
owner: yousef # OPTIONAL — see below
|
|
77
78
|
|
|
78
79
|
must_haves:
|
|
79
80
|
truths: [...] # Observable outcomes from user perspective
|
|
@@ -82,6 +83,8 @@ must_haves:
|
|
|
82
83
|
---
|
|
83
84
|
```
|
|
84
85
|
|
|
86
|
+
**`owner:` field.** If this plan is grounded in a council session (a `.planning/council-sessions/council-*.md` file is referenced in `<context>` as the authoritative decision), set `owner:` to the id of that session's lead/highest-consensus technical persona for THIS sprint's dominant work — one of `haitham`, `hanzla`, `omar`, `waleed`, `yousef` (the engineer personas with execute permission; `sadiq`/`fatima`/others are advisory-only and never valid here). Pick by domain match: a sprint whose `files_modified` is mostly `src/routes|services|models` → `yousef` (backend); mostly `src/components|pages` → `haitham` (frontend); architecture-level, cross-cutting → `waleed`; general/full-stack with no clear split → `hanzla`. If there was no council session, or the domain split is genuinely ambiguous, omit `owner:` entirely — `execute-sprint.md` defaults to the generic `rcode-executor` when the field is absent. Do not guess an owner just to fill the field; an absent `owner:` is the correct, safe default.
|
|
87
|
+
|
|
85
88
|
## Dependency Graph Rules
|
|
86
89
|
|
|
87
90
|
**For each story:**
|
|
@@ -170,6 +173,19 @@ requirements: [...]
|
|
|
170
173
|
must_haves: {truths, artifacts, key_links}
|
|
171
174
|
---
|
|
172
175
|
|
|
176
|
+
## Sprint {phase}.{plan}: {one-line sprint goal, plain English, no jargon}
|
|
177
|
+
|
|
178
|
+
{2-4 sentence plain-English recap: what this sprint builds and why, written for someone who will never open the XML tags below}
|
|
179
|
+
|
|
180
|
+
**Tasks:**
|
|
181
|
+
1. {task 1 title, plain English — copy the <title> text verbatim, no XML}
|
|
182
|
+
2. {task 2 title}
|
|
183
|
+
3. {task N title}
|
|
184
|
+
|
|
185
|
+
_Below this line is the execution prompt the agent reads — task bodies, read-first file lists, verification commands. Not meant for skimming._
|
|
186
|
+
|
|
187
|
+
---
|
|
188
|
+
|
|
173
189
|
<objective>...</objective>
|
|
174
190
|
<execution_context>
|
|
175
191
|
@.rcode/workflows/execute-sprint.md
|
|
@@ -192,6 +208,8 @@ must_haves: {truths, artifacts, key_links}
|
|
|
192
208
|
<output>Create `.planning/phases/{phase-dir}/{phase}-{plan}-SUMMARY.md`</output>
|
|
193
209
|
```
|
|
194
210
|
|
|
211
|
+
**Summary block cost/rule:** the plain-English recap above the `---` divider is 1 title line + 2-4 sentences + a numbered list of task titles you're already writing for each `<title>` tag — copy, don't re-derive. Do not summarize `<action>` bodies, do not restate `<verify>` commands, do not add anything not already stated elsewhere in the file. If a sprint has more than ~10 tasks, list only the first 8 titles plus `...and N more (see tasks below)` rather than growing the summary unboundedly.
|
|
212
|
+
|
|
195
213
|
## Common Planning Mistakes to Avoid
|
|
196
214
|
|
|
197
215
|
1. **Empty requirements:** Every plan MUST list requirement IDs from ROADMAP. No empty requirements field.
|
|
@@ -274,7 +274,18 @@ Selected: {panel agents}
|
|
|
274
274
|
Excluded (0 score): {agents with score=0, comma-separated}
|
|
275
275
|
```
|
|
276
276
|
|
|
277
|
-
**
|
|
277
|
+
**Inline yolo override (checked before `config.mode`):** council can be invoked directly by a user OR dispatched by `/rcode-do` after it already detected yolo intent (literal `--auto` flag, persisted `config.mode: yolo`, or natural-language phrasing like "yolo mode" / "autonomous mode" / "without pausing" — see `do.md`'s `parse_args` step). Check `$ARGUMENTS` for the same signal here, since council can run standalone and never pass through `do.md`:
|
|
278
|
+
|
|
279
|
+
```bash
|
|
280
|
+
INLINE_YOLO=false
|
|
281
|
+
if echo "$ARGUMENTS" | grep -qiE '(--auto\b|\byolo\b|\bautonomous(ly)? mode\b|\bno pauses?\b|\bwithout (asking|stopping|pausing)\b)'; then
|
|
282
|
+
INLINE_YOLO=true
|
|
283
|
+
fi
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
**If `INLINE_YOLO=true` OR `config.mode === 'yolo'`:** print the panel one-liner and proceed without confirmation.
|
|
287
|
+
|
|
288
|
+
**Else (`config.mode === 'guided'` and no inline signal):** confirm with the user:
|
|
278
289
|
|
|
279
290
|
```
|
|
280
291
|
Panel for this question: <comma-separated display names>
|
|
@@ -283,8 +294,6 @@ Proceed? [Y/n]
|
|
|
283
294
|
|
|
284
295
|
Use the AskUserQuestion tool (not raw stdin) for the confirmation.
|
|
285
296
|
|
|
286
|
-
**If `config.mode === 'yolo'`:** print the panel one-liner and proceed without confirmation.
|
|
287
|
-
|
|
288
297
|
## Step 4 — Spawn the panel in parallel (two rounds)
|
|
289
298
|
|
|
290
299
|
### Round 1 — Independent perspectives
|
|
@@ -619,5 +628,12 @@ node .rcode/bin/rcode-tools.cjs state record-session
|
|
|
619
628
|
|
|
620
629
|
## Next Up
|
|
621
630
|
|
|
622
|
-
- `/rcode-plan
|
|
631
|
+
Check `project-status` before suggesting `/rcode-plan`:
|
|
632
|
+
|
|
633
|
+
```bash
|
|
634
|
+
PROJECT_STATUS=$(node .rcode/bin/rcode-tools.cjs project-status 2>/dev/null || echo uninitialized)
|
|
635
|
+
```
|
|
636
|
+
|
|
637
|
+
- If `PROJECT_STATUS` is `real` (a phase already exists): `/rcode-plan {phase-number}` — plan implementation based on the council's recommendation
|
|
638
|
+
- Otherwise (`uninstalled`/`uninitialized`/`stub`, no phase exists yet): `/rcode-add-phase` — create a phase for this work first, then `/rcode-plan` will work
|
|
623
639
|
- `/rcode-decisions` — review decisions the council produced
|
package/rcode/workflows/do.md
CHANGED
|
@@ -28,6 +28,12 @@ if [[ "$ARGUMENTS" == *"--auto"* ]]; then
|
|
|
28
28
|
AUTO_MODE=true
|
|
29
29
|
QUESTION=$(echo "$ARGUMENTS" | sed 's/--auto[[:space:]]*//' | xargs)
|
|
30
30
|
fi
|
|
31
|
+
# Natural-language yolo intent — users say "on yolo mode" / "yolo mode" /
|
|
32
|
+
# "in autonomous mode" in free text far more often than they type --auto.
|
|
33
|
+
# Detect it the same way as the literal flag (#1034/#1035 follow-up).
|
|
34
|
+
if echo "$ARGUMENTS" | grep -qiE '(\byolo\b|\bautonomous(ly)? mode\b|\bno pauses?\b|\bwithout (asking|stopping|pausing)\b)'; then
|
|
35
|
+
AUTO_MODE=true
|
|
36
|
+
fi
|
|
31
37
|
# Also auto-dispatch in yolo mode
|
|
32
38
|
CONFIG_MODE=$(node .rcode/bin/rcode-tools.cjs config-get mode 2>/dev/null || echo "guided")
|
|
33
39
|
if [[ "$CONFIG_MODE" == "yolo" ]]; then
|
|
@@ -143,6 +149,45 @@ LAST_SHIPPED_VERSION=$(grep -m1 -oE 'v[0-9]+\.[0-9]+' .planning/MILESTONES.md 2>
|
|
|
143
149
|
These flags drive the greenfield guard AND the explicit_intent_check below. `.planning/` existing alone is not enough — we need to know whether the methodology chain has actually run (PRD → milestone → epics → phases) AND which milestone is currently open.
|
|
144
150
|
</step>
|
|
145
151
|
|
|
152
|
+
<step name="compound_chain_preflight" priority="first-match">
|
|
153
|
+
**Detect compound/chained requests and preflight the whole chain before dispatching step one.**
|
|
154
|
+
|
|
155
|
+
`/rcode-do` is a single-dispatch router by design — it normally picks ONE command and hands off. But real input often chains several actions in one sentence (e.g. "scan and init my project & get council decision on X and plan and execute on yolo mode"). If the router just dispatches to the first-matched command and lets each downstream skill discover its own missing prerequisites, the user sees red errors scattered mid-flight instead of one clear picture up front (issue #1034/#1035).
|
|
156
|
+
|
|
157
|
+
**Detection:** `$QUESTION` matches this step if it contains 2+ pipeline-stage signals joined by `and`/`&`/`then`/`,`. Pipeline-stage signals: `scan`/`map`, `init`, `council`/`decide`/`architect`, `plan`, `execute`/`build`/`implement`/`yolo`.
|
|
158
|
+
|
|
159
|
+
**If detected, run one consolidated readiness check before dispatching anything:**
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
PROJECT_STATUS=$(node .rcode/bin/rcode-tools.cjs project-status 2>/dev/null || echo uninitialized)
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
Using `$PROJECT_STATUS`, `$HAS_PRD`, `$HAS_PHASES` (already computed in `check_project`), and any `--agents=` list the user named, build the ordered stage list implied by the request and check each stage's precondition against state already on hand — do not re-derive it per stage, and do not spawn anything yet:
|
|
166
|
+
|
|
167
|
+
| Stage (if requested) | Precondition | If unmet |
|
|
168
|
+
|---|---|---|
|
|
169
|
+
| scan/map | none | always runnable |
|
|
170
|
+
| init | none — auto-init guard already ran | always runnable |
|
|
171
|
+
| council | none, BUT if the user passed an explicit `--agents=` list, validate every id against the roster now: `sadiq, hussain-pm, waleed, ahmed-hassani, nasser, layla, zahra, haitham, yousef, zayd, fatima, khalid, mariam, noor` | flag unknown ids and show the valid list in the preflight report — do not let council fail on this mid-run |
|
|
172
|
+
| plan | a phase must exist (`$PROJECT_STATUS == real` OR `$HAS_PHASES == true`) after council — since council alone does not create a phase | note that `/rcode-add-phase` will run between council and plan to create one |
|
|
173
|
+
| execute | a plan (SPRINT.md) must exist for the phase — this is always true after a successful plan stage in the same chain | n/a within a single chain |
|
|
174
|
+
|
|
175
|
+
Print one consolidated block before touching any subagent:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
179
|
+
rcode ► CHAIN PREFLIGHT
|
|
180
|
+
━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━
|
|
181
|
+
Detected stages: {ordered list, e.g. scan → init → council → add-phase → plan → execute}
|
|
182
|
+
{✓ or ⚠ per stage, with the one-line reason for any ⚠}
|
|
183
|
+
{if --agents had unknown ids: "⚠ Unknown agent id(s): {ids}. Valid: {roster list}. Continuing with the corrected/auto-selected panel."}
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
Then dispatch the stages in order via the `Skill` tool, one at a time, re-using this preflight's state instead of letting each stage rediscover it. If a stage's precondition is genuinely unmet and nothing in the chain fixes it (e.g. user asked to `plan` but not `council`/`add-phase` and no phase exists), stop before dispatching that stage and tell the user which single command to run first — do not let it fail loudly mid-chain.
|
|
187
|
+
|
|
188
|
+
This step does not replace `greenfield_guard` or `explicit_intent_check` below — it only applies when a *chain* is detected. Single-verb requests fall through to those steps as before.
|
|
189
|
+
</step>
|
|
190
|
+
|
|
146
191
|
<step name="greenfield_guard" priority="first-match">
|
|
147
192
|
**Block methodology inversion.**
|
|
148
193
|
|
|
@@ -12,9 +12,28 @@ Read config.yaml for planning behavior settings.
|
|
|
12
12
|
|
|
13
13
|
<available_agent_types>
|
|
14
14
|
Valid rcode subagent types (use exact names — do not fall back to 'general-purpose'):
|
|
15
|
-
- rcode-executor — Executes plan tasks, commits, creates SUMMARY.md
|
|
15
|
+
- rcode-executor — Executes plan tasks, commits, creates SUMMARY.md (default)
|
|
16
|
+
- rcode-haitham / rcode-hanzla / rcode-omar / rcode-waleed / rcode-yousef — same execution contract as rcode-executor (via `@.rcode/references/persona-executor-mode.md`), used ONLY when `owner:` in SPRINT.md frontmatter names one of them (see `owner_agent_resolution` below)
|
|
16
17
|
</available_agent_types>
|
|
17
18
|
|
|
19
|
+
<step name="owner_agent_resolution">
|
|
20
|
+
**Resolve which agent actually executes this plan.**
|
|
21
|
+
|
|
22
|
+
Read the `owner:` field from the SPRINT.md frontmatter (set by `/rcode-plan` from the council decision's lead persona, when one exists — see `plan.md`'s `owner_field` step). This is a plain frontmatter read, not a new tool call.
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
SPRINT_OWNER=$(grep -m1 '^owner:' .planning/phases/XX-name/{phase}-{plan}-SPRINT.md 2>/dev/null | sed 's/^owner:[[:space:]]*//' | tr -d '"' | xargs)
|
|
26
|
+
VALID_OWNERS="haitham hanzla omar waleed yousef"
|
|
27
|
+
if [[ -n "$SPRINT_OWNER" ]] && echo "$VALID_OWNERS" | grep -qw "$SPRINT_OWNER"; then
|
|
28
|
+
EXEC_AGENT="rcode-${SPRINT_OWNER}"
|
|
29
|
+
else
|
|
30
|
+
EXEC_AGENT="rcode-executor"
|
|
31
|
+
fi
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Use `$EXEC_AGENT` as the `subagent_type` in every Task spawn below (Pattern A, Pattern B subagent route). No other change to the spawn prompt is needed — the persona file's own conditional clause tells it to load the full executor playbook when it sees `subagent_type` = itself and a SPRINT.md path in the prompt. If `$EXEC_AGENT` is a persona and that persona is not installed (agent file missing), fall back to `rcode-executor` and note the fallback in SUMMARY.md's Deviations section — do not fail the sprint over this.
|
|
35
|
+
</step>
|
|
36
|
+
|
|
18
37
|
<process>
|
|
19
38
|
|
|
20
39
|
<preflight name="dependency_check">
|
|
@@ -122,9 +141,9 @@ grep -n "type=\"checkpoint" .planning/phases/XX-name/{phase}-{plan}-SPRINT.md
|
|
|
122
141
|
| Verify-only | B (segmented) | Segments between checkpoints. After none/human-verify → SUBAGENT. After decision/human-action → MAIN |
|
|
123
142
|
| Decision | C (main) | Execute entirely in main context |
|
|
124
143
|
|
|
125
|
-
**Pattern A:** init_agent_tracking → capture `EXPECTED_BASE=$(git rev-parse HEAD)` → spawn Task(subagent_type="
|
|
144
|
+
**Pattern A:** init_agent_tracking → capture `EXPECTED_BASE=$(git rev-parse HEAD)` → run `owner_agent_resolution` to get `$EXEC_AGENT` → spawn Task(subagent_type="$EXEC_AGENT", model=executor_model) with prompt: execute plan at [path], autonomous, all tasks + SUMMARY + commit, follow deviation/auth rules, report: plan name, tasks, SUMMARY path, commit hash → track agent_id → wait → update tracking → report. **Include `isolation="worktree"` only if `workflow.use_worktrees` is not `false`** (read via `config-get workflow.use_worktrees`). **When using `isolation="worktree"`, include a `<worktree_branch_check>` block in the prompt** instructing the executor to run `git merge-base HEAD {EXPECTED_BASE}` and, if the result differs from `{EXPECTED_BASE}`, reset the branch base with `git reset --soft {EXPECTED_BASE}` before starting work. This corrects a known issue on Windows where `EnterWorktree` creates branches from `main` instead of the feature branch HEAD.
|
|
126
145
|
|
|
127
|
-
**Post-install namespace fallback:** If `Task(subagent_type="rcode-executor")` fails
|
|
146
|
+
**Post-install namespace fallback:** If `Task(subagent_type="$EXEC_AGENT")` fails with "Agent type not found": if `$EXEC_AGENT` was a persona (not `rcode-executor`), retry once with `subagent_type="rcode-executor"` (the persona may not be installed in this project) and note the fallback in SUMMARY.md. If `rcode-executor` itself fails "Agent type not found", the runtime has not yet registered the agent (requires IDE reload after install) — retry with `subagent_type="rihal-executor"`. If that also fails, fall back to Pattern C (execute in main context) and log `[execute-sprint] ${EXEC_AGENT} not available — reload IDE or executing in main context`.
|
|
128
147
|
|
|
129
148
|
**Pattern B:** Execute segment-by-segment. Autonomous segments: spawn subagent for assigned tasks only (no SUMMARY/commit). Checkpoints: main context. After all segments: aggregate, create SUMMARY, commit. See segment_execution.
|
|
130
149
|
|
|
@@ -363,6 +382,35 @@ TASK_COMMIT=$(git rev-parse --short HEAD)
|
|
|
363
382
|
TASK_COMMITS+=("Task ${TASK_NUM}: ${TASK_COMMIT}")
|
|
364
383
|
```
|
|
365
384
|
|
|
385
|
+
**5.5. Sync dashboard state (closes the manual/`--wave N` state-sync gap):**
|
|
386
|
+
|
|
387
|
+
The dashboard reads task status from `.rcode/state.json`'s `phases[].sprints[].stories[]`, not from SUMMARY.md or git. `state story move` only works on a story that's already registered — and the planner does not register stories into state.json when it writes SPRINT.md (see `#590` fallback in `scanner.js`). Without this step, a task that is fully committed and tested still shows "todo" on the dashboard until the ENTIRE phase's status flips to complete, which is silently wrong for any partial/single-wave run (`--wave N`, a manually re-run single plan, a checkpoint-interrupted resume).
|
|
388
|
+
|
|
389
|
+
Run this after every task's commit, not just at the end of the plan:
|
|
390
|
+
|
|
391
|
+
```bash
|
|
392
|
+
# Ensure the parent sprint is marked active (idempotent — no-op if already started)
|
|
393
|
+
node ".rcode/bin/rcode-tools.cjs" state sprint start --sprint "${SPRINT_ID}" >/dev/null 2>&1
|
|
394
|
+
|
|
395
|
+
# Try to move the story directly by its SPRINT.md task id first
|
|
396
|
+
MOVE_RESULT=$(node ".rcode/bin/rcode-tools.cjs" state story move --id "${TASK_ID}" --status done 2>&1)
|
|
397
|
+
if echo "$MOVE_RESULT" | grep -qi "not found"; then
|
|
398
|
+
# Story was never registered (planner doesn't pre-register) — register it now.
|
|
399
|
+
# state story add assigns ids in {sprint}.{N} sequence matching the order
|
|
400
|
+
# tasks are added, which matches SPRINT.md's own <task id> numbering as
|
|
401
|
+
# long as tasks are committed in the order they appear in the file.
|
|
402
|
+
node ".rcode/bin/rcode-tools.cjs" state story add --sprint "${SPRINT_ID}" --title "${TASK_TITLE}" >/dev/null 2>&1
|
|
403
|
+
node ".rcode/bin/rcode-tools.cjs" state story move --id "${TASK_ID}" --status done >/dev/null 2>&1
|
|
404
|
+
fi
|
|
405
|
+
```
|
|
406
|
+
|
|
407
|
+
Non-fatal: if either `rcode-tools.cjs` call fails for a reason other than "not found" (e.g. state.json corrupted), log a one-line warning and continue — dashboard staleness is not a reason to fail a task that verified and committed successfully.
|
|
408
|
+
|
|
409
|
+
When the whole plan finishes (all tasks done), mark the sprint complete too:
|
|
410
|
+
```bash
|
|
411
|
+
node ".rcode/bin/rcode-tools.cjs" state sprint complete --sprint "${SPRINT_ID}" >/dev/null 2>&1
|
|
412
|
+
```
|
|
413
|
+
|
|
366
414
|
**6. Check for untracked generated files:**
|
|
367
415
|
```bash
|
|
368
416
|
git status --short | grep '^??'
|
|
@@ -52,13 +52,20 @@ End with closure banner + top findings summary:
|
|
|
52
52
|
If `$ARGUMENTS` is empty or contains only `--help` or `-h`:
|
|
53
53
|
|
|
54
54
|
```
|
|
55
|
-
/rcode-map-codebase <
|
|
55
|
+
/rcode-map-codebase <a short description of the codebase or why you're mapping it>
|
|
56
56
|
```
|
|
57
57
|
|
|
58
|
-
|
|
58
|
+
The description isn't used to scope or filter what gets mapped — all 4 mapper
|
|
59
|
+
agents (tech, architecture, conventions, concerns) always cover the whole
|
|
60
|
+
codebase regardless of what you write here. It exists as an intentional
|
|
61
|
+
non-empty confirmation, not a topic filter — `/rcode-scan --focus <topic>` is
|
|
62
|
+
the command for a narrower, single-topic pass.
|
|
63
|
+
|
|
64
|
+
**Examples (any of these work identically — the text just needs to be non-empty):**
|
|
59
65
|
```
|
|
60
|
-
/rcode-map-codebase
|
|
61
|
-
/rcode-map-codebase
|
|
66
|
+
/rcode-map-codebase full codebase
|
|
67
|
+
/rcode-map-codebase onboarding a new engineer, need the full picture
|
|
68
|
+
/rcode-map-codebase before a major refactor
|
|
62
69
|
```
|
|
63
70
|
|
|
64
71
|
STOP — do not proceed.
|
package/rcode/workflows/plan.md
CHANGED
|
@@ -81,7 +81,7 @@ PROJECT_STATUS=$(node .rcode/bin/rcode-tools.cjs project-status 2>/dev/null || e
|
|
|
81
81
|
If `PROJECT_STATUS` is `uninstalled`, `uninitialized`, or `stub`:
|
|
82
82
|
|
|
83
83
|
```
|
|
84
|
-
Project not initialized. Run /rcode-
|
|
84
|
+
Project not initialized for planning. Run /rcode-new-project (full roadmap) or /rcode-add-phase (if you just want to add one phase), then return here.
|
|
85
85
|
```
|
|
86
86
|
|
|
87
87
|
Stop. Do not proceed until `project-status` returns `real`.
|
|
@@ -28,7 +28,7 @@ export function DecisionsView() {
|
|
|
28
28
|
if (!decisions.length) {
|
|
29
29
|
return html`
|
|
30
30
|
<div id="view-decisions" class="view active">
|
|
31
|
-
<div class="view-title">Decisions (ADRs)</div>
|
|
31
|
+
<div class="view-title">Decisions (Architecture Decision Records — ADRs)</div>
|
|
32
32
|
<div class="empty">
|
|
33
33
|
No decisions recorded yet.
|
|
34
34
|
<div class="empty-action">Decisions made during /rcode-council appear here</div>
|
|
@@ -47,7 +47,7 @@ export function DecisionsView() {
|
|
|
47
47
|
|
|
48
48
|
return html`
|
|
49
49
|
<div id="view-decisions" class="view active">
|
|
50
|
-
<div class="view-title">Decisions (ADRs)</div>
|
|
50
|
+
<div class="view-title">Decisions (Architecture Decision Records — ADRs)</div>
|
|
51
51
|
<div class="filter-bar">
|
|
52
52
|
<input
|
|
53
53
|
class="filter-input"
|