@automagik/genie 4.260420.9 → 4.260420.10
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/dist/genie.js +43 -11
- package/package.json +1 -1
- package/plugins/genie/.claude-plugin/plugin.json +1 -1
- package/plugins/genie/package.json +1 -1
- package/skills/dream/SKILL.md +2 -2
- package/skills/genie/SKILL.md +36 -3
- package/skills/genie/reference/lifecycle.md +1 -1
- package/skills/genie-hacks/SKILL.md +3 -3
- package/skills/pm/SKILL.md +3 -3
- package/skills/report/SKILL.md +2 -2
- package/skills/trace/SKILL.md +1 -1
- package/skills/work/SKILL.md +3 -3
package/dist/genie.js
CHANGED
|
@@ -495,22 +495,29 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
|
|
|
495
495
|
SELECT e.state FROM executors e
|
|
496
496
|
JOIN agents a ON a.current_executor_id = e.id
|
|
497
497
|
WHERE a.id = ${agentId}
|
|
498
|
-
`;return rows.length>0?rows[0].state:"offline"}async function listAgents(filters){let sql=await getConnection(),rows;if(filters?.team&&filters?.role)rows=await sql`
|
|
498
|
+
`;return rows.length>0?rows[0].state:"offline"}async function listAgents(filters){let sql=await getConnection(),includeArchived=filters?.includeArchived??!1,rows;if(filters?.team&&filters?.role)rows=await sql`
|
|
499
499
|
SELECT id, started_at, role, custom_name, team, native_agent_id, native_color,
|
|
500
500
|
native_team_enabled, parent_session_id, current_executor_id, reports_to, title, created_at, updated_at
|
|
501
|
-
FROM agents
|
|
501
|
+
FROM agents
|
|
502
|
+
WHERE team = ${filters.team} AND role = ${filters.role}
|
|
503
|
+
AND (${includeArchived} OR state IS DISTINCT FROM 'archived')
|
|
502
504
|
`;else if(filters?.team)rows=await sql`
|
|
503
505
|
SELECT id, started_at, role, custom_name, team, native_agent_id, native_color,
|
|
504
506
|
native_team_enabled, parent_session_id, current_executor_id, reports_to, title, created_at, updated_at
|
|
505
|
-
FROM agents
|
|
507
|
+
FROM agents
|
|
508
|
+
WHERE team = ${filters.team}
|
|
509
|
+
AND (${includeArchived} OR state IS DISTINCT FROM 'archived')
|
|
506
510
|
`;else if(filters?.role)rows=await sql`
|
|
507
511
|
SELECT id, started_at, role, custom_name, team, native_agent_id, native_color,
|
|
508
512
|
native_team_enabled, parent_session_id, current_executor_id, reports_to, title, created_at, updated_at
|
|
509
|
-
FROM agents
|
|
513
|
+
FROM agents
|
|
514
|
+
WHERE role = ${filters.role}
|
|
515
|
+
AND (${includeArchived} OR state IS DISTINCT FROM 'archived')
|
|
510
516
|
`;else rows=await sql`
|
|
511
517
|
SELECT id, started_at, role, custom_name, team, native_agent_id, native_color,
|
|
512
518
|
native_team_enabled, parent_session_id, current_executor_id, reports_to, title, created_at, updated_at
|
|
513
519
|
FROM agents
|
|
520
|
+
WHERE (${includeArchived} OR state IS DISTINCT FROM 'archived')
|
|
514
521
|
`;return rows.map(rowToAgentIdentity)}var init_agent_registry=__esm(()=>{init_audit();init_db();init_tmux()});function normalizeValue(v){if(v===void 0||v===null)return;if(v==="")return;if(v==="inherit")return;return v}function resolveField(agent,field,ctx){return resolveFieldWithSource(agent,field,ctx).value}function resolveFieldWithSource(agent,field,ctx){let agentVal=normalizeValue(agent[field]);if(agentVal!==void 0)return{value:agentVal,source:"explicit"};if(ctx.parent){let parentVal=normalizeValue(ctx.parent.fields[field]);if(parentVal!==void 0)return{value:parentVal,source:`parent:${ctx.parent.name}`}}if(ctx.workspaceDefaults){let wsVal=normalizeValue(ctx.workspaceDefaults[field]);if(wsVal!==void 0)return{value:wsVal,source:"workspace"}}return{value:BUILTIN_DEFAULTS[field],source:"built-in"}}function computeEffectiveDefaults(workspaceDefaults){if(!workspaceDefaults)return{...BUILTIN_DEFAULTS};let result2={...BUILTIN_DEFAULTS};for(let key of Object.keys(BUILTIN_DEFAULTS)){let wsVal=normalizeValue(workspaceDefaults[key]);if(wsVal!==void 0)result2[key]=wsVal}return result2}var BUILTIN_DEFAULTS,RESOLVED_FIELDS;var init_defaults=__esm(()=>{BUILTIN_DEFAULTS={model:"opus",promptMode:"append",color:"blue",effort:"high",thinking:"enabled",permissionMode:"bypassPermissions"},RESOLVED_FIELDS=["model"]});var exports_js_yaml={};__export(exports_js_yaml,{types:()=>types3,safeLoadAll:()=>safeLoadAll,safeLoad:()=>safeLoad,safeDump:()=>safeDump,loadAll:()=>loadAll,load:()=>load2,dump:()=>dump,default:()=>jsYaml,YAMLException:()=>YAMLException,Type:()=>Type,Schema:()=>Schema,JSON_SCHEMA:()=>JSON_SCHEMA,FAILSAFE_SCHEMA:()=>FAILSAFE_SCHEMA,DEFAULT_SCHEMA:()=>DEFAULT_SCHEMA,CORE_SCHEMA:()=>CORE_SCHEMA});function isNothing(subject){return typeof subject>"u"||subject===null}function isObject(subject){return typeof subject==="object"&&subject!==null}function toArray(sequence){if(Array.isArray(sequence))return sequence;else if(isNothing(sequence))return[];return[sequence]}function extend(target,source){var index,length,key,sourceKeys;if(source){sourceKeys=Object.keys(source);for(index=0,length=sourceKeys.length;index<length;index+=1)key=sourceKeys[index],target[key]=source[key]}return target}function repeat(string,count){var result2="",cycle;for(cycle=0;cycle<count;cycle+=1)result2+=string;return result2}function isNegativeZero(number){return number===0&&Number.NEGATIVE_INFINITY===1/number}function formatError(exception,compact){var where="",message=exception.reason||"(unknown reason)";if(!exception.mark)return message;if(exception.mark.name)where+='in "'+exception.mark.name+'" ';if(where+="("+(exception.mark.line+1)+":"+(exception.mark.column+1)+")",!compact&&exception.mark.snippet)where+=`
|
|
515
522
|
|
|
516
523
|
`+exception.mark.snippet;return message+" "+where}function YAMLException$1(reason,mark){if(Error.call(this),this.name="YAMLException",this.reason=reason,this.mark=mark,this.message=formatError(this,!1),Error.captureStackTrace)Error.captureStackTrace(this,this.constructor);else this.stack=Error().stack||""}function getLine(buffer2,lineStart,lineEnd,position,maxLineLength){var head="",tail="",maxHalfLength=Math.floor(maxLineLength/2)-1;if(position-lineStart>maxHalfLength)head=" ... ",lineStart=position-maxHalfLength+head.length;if(lineEnd-position>maxHalfLength)tail=" ...",lineEnd=position+maxHalfLength-tail.length;return{str:head+buffer2.slice(lineStart,lineEnd).replace(/\t/g,"\u2192")+tail,pos:position-lineStart+head.length}}function padStart(string,max){return common2.repeat(" ",max-string.length)+string}function makeSnippet(mark,options){if(options=Object.create(options||null),!mark.buffer)return null;if(!options.maxLength)options.maxLength=79;if(typeof options.indent!=="number")options.indent=1;if(typeof options.linesBefore!=="number")options.linesBefore=3;if(typeof options.linesAfter!=="number")options.linesAfter=2;var re=/\r?\n|\r|\0/g,lineStarts=[0],lineEnds=[],match,foundLineNo=-1;while(match=re.exec(mark.buffer))if(lineEnds.push(match.index),lineStarts.push(match.index+match[0].length),mark.position<=match.index&&foundLineNo<0)foundLineNo=lineStarts.length-2;if(foundLineNo<0)foundLineNo=lineStarts.length-1;var result2="",i,line,lineNoLength=Math.min(mark.line+options.linesAfter,lineEnds.length).toString().length,maxLineLength=options.maxLength-(options.indent+lineNoLength+3);for(i=1;i<=options.linesBefore;i++){if(foundLineNo-i<0)break;line=getLine(mark.buffer,lineStarts[foundLineNo-i],lineEnds[foundLineNo-i],mark.position-(lineStarts[foundLineNo]-lineStarts[foundLineNo-i]),maxLineLength),result2=common2.repeat(" ",options.indent)+padStart((mark.line-i+1).toString(),lineNoLength)+" | "+line.str+`
|
|
@@ -635,10 +642,13 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
|
|
|
635
642
|
`,added}async function fireAgent(teamName,agentName){let config=await getTeam(teamName);if(!config)throw Error(`Team "${teamName}" not found.`);let idx=config.members.indexOf(agentName);if(idx===-1)return!1;config.members.splice(idx,1),await(await getConnection())`
|
|
636
643
|
UPDATE teams SET members = ${JSON.stringify(config.members)}
|
|
637
644
|
WHERE name = ${teamName}
|
|
638
|
-
`;try{await killWorkersByName(agentName)}catch{}return!0}async function removeWorktree(worktreePath){if(!worktreePath||!existsSync21(worktreePath))return;try{await $3`git worktree remove --force ${worktreePath}`.quiet()}catch{try{await rm2(worktreePath,{recursive:!0,force:!0})}catch{}}}async function cleanupTeamTmuxSession(tmuxSessionName,teamName){if(!tmuxSessionName)return;try{if(!await findSessionByName(tmuxSessionName))return;let windows=await listWindows(tmuxSessionName),teamWindow=await findWindowByName(tmuxSessionName,teamName);if(tmuxSessionName===teamName||windows.length===1&&windows[0]?.name===teamName)await killSession(tmuxSessionName);else if(teamWindow)await executeTmux2(`kill-window -t '${teamWindow.id}'`)}catch{}}async function archiveTeam(teamName){let config=await getTeam(teamName);if(!config)return!1;let killResults=await Promise.allSettled(config.members.map((member)=>killWorkersByName(member,teamName)));for(let i2=0;i2<killResults.length;i2++)if(killResults[i2].status==="rejected")console.error(` Failed to kill member "${config.members[i2]}": ${killResults[i2].reason}`);
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
645
|
+
`;try{await killWorkersByName(agentName)}catch{}return!0}async function removeWorktree(worktreePath){if(!worktreePath||!existsSync21(worktreePath))return;try{await $3`git worktree remove --force ${worktreePath}`.quiet()}catch{try{await rm2(worktreePath,{recursive:!0,force:!0})}catch{}}}async function cleanupTeamTmuxSession(tmuxSessionName,teamName){if(!tmuxSessionName)return;try{if(!await findSessionByName(tmuxSessionName))return;let windows=await listWindows(tmuxSessionName),teamWindow=await findWindowByName(tmuxSessionName,teamName);if(tmuxSessionName===teamName||windows.length===1&&windows[0]?.name===teamName)await killSession(tmuxSessionName);else if(teamWindow)await executeTmux2(`kill-window -t '${teamWindow.id}'`)}catch{}}async function archiveTeam(teamName){let config=await getTeam(teamName);if(!config)return!1;let killResults=await Promise.allSettled(config.members.map((member)=>killWorkersByName(member,teamName)));for(let i2=0;i2<killResults.length;i2++)if(killResults[i2].status==="rejected")console.error(` Failed to kill member "${config.members[i2]}": ${killResults[i2].reason}`);await cleanupTeamTmuxSession(config.tmuxSessionName??teamName,teamName);let sql=await getConnection(),archivedAgents=0,updated=!1;if(await sql.begin(async(tx)=>{if((await tx`
|
|
646
|
+
UPDATE teams SET status = 'archived', archived_at = now(), updated_at = now()
|
|
647
|
+
WHERE name = ${teamName}
|
|
648
|
+
`).count===0)return;updated=!0,archivedAgents=(await tx`
|
|
649
|
+
UPDATE agents SET state = 'archived', updated_at = now()
|
|
650
|
+
WHERE team = ${teamName} AND state IS DISTINCT FROM 'archived'
|
|
651
|
+
`).count??0}),!updated)return!1;return recordAuditEvent("team",teamName,"archived",getActor(),{repo:config.repo,archivedAgents}).catch(()=>{}),!0}async function unarchiveTeam(teamName){let config=await getTeam(teamName);if(!config)return!1;let restoredStatus="done";if((await(await getConnection())`
|
|
642
652
|
UPDATE teams SET status = ${restoredStatus}, archived_at = NULL, updated_at = now()
|
|
643
653
|
WHERE name = ${teamName}
|
|
644
654
|
`).count===0)return!1;return recordAuditEvent("team",teamName,"unarchived",getActor(),{repo:config.repo,restoredStatus}).catch(()=>{}),!0}async function disbandTeam(teamName){let config=await getTeam(teamName);if(!config)return!1;try{await deleteNativeTeam(teamName)}catch{}for(let member of config.members)try{await killWorkersByName(member,teamName)}catch{}await removeWorktree(config.worktreePath),await cleanupTeamTmuxSession(config.tmuxSessionName??teamName,teamName);let sql=await getConnection(),disbanded=!1;if(await sql.begin(async(tx)=>{if(config.wishSlug)try{let wishFile=`.genie/wishes/${config.wishSlug}/WISH.md`,parent=await tx`
|
|
@@ -647,10 +657,13 @@ ${bin} set-option -w pane-active-border-style "fg=$COLOR"
|
|
|
647
657
|
LIMIT 1
|
|
648
658
|
`;if(parent.length>0){let parentId=parent[0].id,inProgress=await tx`
|
|
649
659
|
SELECT id FROM tasks WHERE parent_id = ${parentId} AND status = 'in_progress'
|
|
650
|
-
`;if(inProgress.length>0){let ids=inProgress.map((r)=>r.id);await tx`UPDATE tasks SET status = 'ready', started_at = NULL, updated_at = now() WHERE id = ANY(${ids})`,await tx`DELETE FROM task_actors WHERE task_id = ANY(${ids}) AND role = 'assignee'`,console.log(` Reset ${ids.length} in-progress group(s) for wish "${config.wishSlug}"`)}}}catch{}disbanded=(await tx`
|
|
660
|
+
`;if(inProgress.length>0){let ids=inProgress.map((r)=>r.id);await tx`UPDATE tasks SET status = 'ready', started_at = NULL, updated_at = now() WHERE id = ANY(${ids})`,await tx`DELETE FROM task_actors WHERE task_id = ANY(${ids}) AND role = 'assignee'`,console.log(` Reset ${ids.length} in-progress group(s) for wish "${config.wishSlug}"`)}}}catch{}if(disbanded=(await tx`
|
|
651
661
|
UPDATE teams SET status = 'archived', archived_at = now(), updated_at = now()
|
|
652
662
|
WHERE name = ${teamName}
|
|
653
|
-
`).count>0
|
|
663
|
+
`).count>0,disbanded)await tx`
|
|
664
|
+
UPDATE agents SET state = 'archived', updated_at = now()
|
|
665
|
+
WHERE team = ${teamName} AND state IS DISTINCT FROM 'archived'
|
|
666
|
+
`}),!disbanded)return!1;return recordAuditEvent("team",teamName,"disbanded",getActor(),{repo:config.repo}).catch(()=>{}),await pruneStaleWorktrees(config.repo),!0}async function pruneStaleWorktrees(_repoPath){let sql=await getConnection(),rows=await sql`SELECT name, worktree_path FROM teams`;for(let row of rows)if(row.worktree_path&&!existsSync21(row.worktree_path)){try{await deleteNativeTeam(row.name)}catch{}await sql`DELETE FROM teams WHERE name = ${row.name}`}}async function updateTeamConfig(name,config){await(await getConnection())`
|
|
654
667
|
UPDATE teams SET
|
|
655
668
|
repo = ${config.repo},
|
|
656
669
|
base_branch = ${config.baseBranch},
|
|
@@ -1310,7 +1323,26 @@ Stopping inbox watcher...`),stopInboxWatcher2(handle),process.exit(0)};process.o
|
|
|
1310
1323
|
INSERT INTO task_actors (task_id, actor_type, actor_id, role)
|
|
1311
1324
|
VALUES (${child.id}, 'local', ${assignee}, 'assignee')
|
|
1312
1325
|
ON CONFLICT (task_id, actor_type, actor_id, role) DO UPDATE SET created_at = now()
|
|
1313
|
-
`,{status:"in_progress",assignee,dependsOn:deps.map((d)=>d.group_name),startedAt:now.toISOString()}}async function completeGroup(slug,groupName,cwd){let sql=await getConnection(),repoPath=resolveRepoPath(cwd),parent=await findParent(sql,slug,repoPath);if(!parent)throw Error(`Group "${groupName}" not found in wish "${slug}"`);let child=await findGroup(sql,parent.id,groupName);if(!child)throw Error(`Group "${groupName}" not found in wish "${slug}"`);if(child.status
|
|
1326
|
+
`,{status:"in_progress",assignee,dependsOn:deps.map((d)=>d.group_name),startedAt:now.toISOString()}}async function completeGroup(slug,groupName,cwd){let sql=await getConnection(),repoPath=resolveRepoPath(cwd),parent=await findParent(sql,slug,repoPath);if(!parent)throw Error(`Group "${groupName}" not found in wish "${slug}"`);let child=await findGroup(sql,parent.id,groupName);if(!child)throw Error(`Group "${groupName}" not found in wish "${slug}"`);if(child.status==="done"){let[actors2,deps2]=await Promise.all([sql`
|
|
1327
|
+
SELECT actor_id FROM task_actors WHERE task_id = ${child.id} AND role = 'assignee' LIMIT 1
|
|
1328
|
+
`,sql`
|
|
1329
|
+
SELECT t.group_name FROM task_dependencies td
|
|
1330
|
+
JOIN tasks t ON t.id = td.depends_on_id
|
|
1331
|
+
WHERE td.task_id = ${child.id}
|
|
1332
|
+
`]);return{status:"done",assignee:actors2.length>0?actors2[0].actor_id:void 0,dependsOn:deps2.map((d)=>d.group_name),startedAt:toISO(child.started_at),completedAt:toISO(child.ended_at)??toISO(child.updated_at)}}if(child.status==="blocked"){let blockers=(await sql`
|
|
1333
|
+
SELECT t.group_name, t.status
|
|
1334
|
+
FROM task_dependencies td
|
|
1335
|
+
JOIN tasks t ON t.id = td.depends_on_id
|
|
1336
|
+
WHERE td.task_id = ${child.id}
|
|
1337
|
+
AND t.status != 'done'
|
|
1338
|
+
`).map((d)=>`${d.group_name} (${d.status})`).join(", ");throw Error(`Cannot complete group "${groupName}": blocked on unmet dependencies: ${blockers||"unknown"}`)}if(child.status==="ready"){let assignee=process.env.GENIE_AGENT_NAME||"auto-recovered",startNow=new Date;if(await sql`
|
|
1339
|
+
UPDATE tasks SET status = 'in_progress', started_at = COALESCE(started_at, ${startNow}), updated_at = ${startNow}
|
|
1340
|
+
WHERE id = ${child.id}
|
|
1341
|
+
`,await sql`
|
|
1342
|
+
INSERT INTO task_actors (task_id, actor_type, actor_id, role)
|
|
1343
|
+
VALUES (${child.id}, 'local', ${assignee}, 'assignee')
|
|
1344
|
+
ON CONFLICT (task_id, actor_type, actor_id, role) DO UPDATE SET created_at = now()
|
|
1345
|
+
`,console.warn(`\u26A0 Group "${groupName}" was \`ready\` (dispatch-bypass); auto-transitioned to \`in_progress\` before completion.`),child.status="in_progress",!child.started_at)child.started_at=startNow}if(child.status!=="in_progress")throw Error(`Cannot complete group "${groupName}": must be in_progress (currently ${child.status})`);let now=new Date;await sql`
|
|
1314
1346
|
UPDATE tasks SET status = 'done', ended_at = ${now}, updated_at = ${now}
|
|
1315
1347
|
WHERE id = ${child.id}
|
|
1316
1348
|
`,await sql`
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "genie",
|
|
3
|
-
"version": "4.260420.
|
|
3
|
+
"version": "4.260420.10",
|
|
4
4
|
"description": "Human-AI partnership for Claude Code. Share a terminal, orchestrate workers, evolve together. Brainstorm ideas, turn them into wishes, execute with /work, validate with /review, and ship as one team.",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Namastex Labs"
|
package/skills/dream/SKILL.md
CHANGED
|
@@ -87,7 +87,7 @@ genie team hire qa # for QA loop on dev
|
|
|
87
87
|
- Same-layer wishes dispatch in parallel.
|
|
88
88
|
- Dispatch workers via `genie work <agent> <slug>#<group>` — gets state tracking for free.
|
|
89
89
|
- Parallel groups within a wish dispatched simultaneously.
|
|
90
|
-
3. Monitor via `genie
|
|
90
|
+
3. Monitor via `genie wish status <slug>`. Mark groups done via `genie wish done <slug>#<group>` (and, when PG tasks exist, `genie task done #<seq>`).
|
|
91
91
|
4. **Track progress (v4):** as each wish starts execution, move its child task:
|
|
92
92
|
```bash
|
|
93
93
|
genie task move #<wish-seq> --to build --comment "Execution started"
|
|
@@ -192,4 +192,4 @@ When PG is available, the dream run is fully tracked in the task system:
|
|
|
192
192
|
- Do not expand scope beyond what WISH.md defines.
|
|
193
193
|
- Always write DREAM-REPORT.md, even if all wishes BLOCKED.
|
|
194
194
|
- Poll CI status instead of sleeping — never use `sleep` in CI retry loops.
|
|
195
|
-
- Use `genie
|
|
195
|
+
- Use `genie wish done`, `genie wish status`, and `genie wish reset` for wish-group state; use `genie task …` subcommands for PG task tracking. The two namespaces are distinct — do not substitute one for the other.
|
package/skills/genie/SKILL.md
CHANGED
|
@@ -74,14 +74,23 @@ Then invoke the skill using the Skill tool, or run the command via Bash.
|
|
|
74
74
|
|
|
75
75
|
## Operational Command Mapping
|
|
76
76
|
|
|
77
|
-
When the user's intent is **operational**, map natural language to genie CLI commands
|
|
77
|
+
When the user's intent is **operational**, map natural language to genie CLI commands. **The CLI has two distinct lifecycle namespaces — don't confuse them:**
|
|
78
|
+
|
|
79
|
+
- **`genie wish …`** — wish-group state (progress, reset, done per `<slug>#<group>`). Source of truth for execution waves.
|
|
80
|
+
- **`genie task …`** — PG task lifecycle (checkout, move, comment, done per `#<seq>`). Source of truth for backlog + board.
|
|
78
81
|
|
|
79
82
|
| User says | Command |
|
|
80
83
|
|-----------|---------|
|
|
81
84
|
| "check team status" / "how's the team" | `genie team ls` |
|
|
82
85
|
| "spawn an engineer" / "start an engineer" | `genie spawn engineer` |
|
|
83
86
|
| "list agents" / "show agents" | `genie ls` |
|
|
84
|
-
| "show wish progress" / "status of [slug]" |
|
|
87
|
+
| **"show wish progress" / "status of [slug]"** | **`genie wish status <slug>`** (NOT `genie task status` — that verb does not exist) |
|
|
88
|
+
| "mark wish group done" | `genie wish done <slug>#<group>` |
|
|
89
|
+
| "reset a stuck group" | `genie wish reset <slug>#<group>` |
|
|
90
|
+
| "list all wishes" | `genie wish list` |
|
|
91
|
+
| "show my tasks" / "backlog" | `genie task list` |
|
|
92
|
+
| "claim a task" / "start working on #N" | `genie task checkout #<seq>` |
|
|
93
|
+
| "mark task done" | `genie task done #<seq>` |
|
|
85
94
|
| "kill agent X" / "stop X" | `genie kill X` or `genie stop X` |
|
|
86
95
|
| "send message to X" | `genie send 'msg' --to X` |
|
|
87
96
|
| "create a team for X" | `genie team create X --repo .` |
|
|
@@ -89,7 +98,29 @@ When the user's intent is **operational**, map natural language to genie CLI com
|
|
|
89
98
|
|
|
90
99
|
## CLI Commands (live)
|
|
91
100
|
|
|
92
|
-
|
|
101
|
+
Top-level verb listing — consult this on every session after `genie update` (see Rules):
|
|
102
|
+
|
|
103
|
+
!`genie --help 2>/dev/null`
|
|
104
|
+
|
|
105
|
+
## Verb Anatomy (subcommand trees)
|
|
106
|
+
|
|
107
|
+
Top-level `--help` shows namespaces but hides their subcommands. These four namespaces carry 80% of orchestration traffic — re-read after any CLI version bump, because verbs migrate (`genie task status` → `genie wish status` happened in 4.260420.x).
|
|
108
|
+
|
|
109
|
+
### `genie wish` — wish-group lifecycle
|
|
110
|
+
|
|
111
|
+
!`genie wish --help 2>/dev/null`
|
|
112
|
+
|
|
113
|
+
### `genie task` — PG task lifecycle
|
|
114
|
+
|
|
115
|
+
!`genie task --help 2>/dev/null`
|
|
116
|
+
|
|
117
|
+
### `genie team` — team lifecycle
|
|
118
|
+
|
|
119
|
+
!`genie team --help 2>/dev/null`
|
|
120
|
+
|
|
121
|
+
### `genie agent` — agent lifecycle
|
|
122
|
+
|
|
123
|
+
!`genie agent --help 2>/dev/null`
|
|
93
124
|
|
|
94
125
|
## Reference
|
|
95
126
|
|
|
@@ -107,3 +138,5 @@ For questions about the wish lifecycle, skill descriptions, or how genie works,
|
|
|
107
138
|
- For prompt refinement, suggest `/refine`.
|
|
108
139
|
- NEVER use the Agent tool to spawn agents — use `genie spawn` instead.
|
|
109
140
|
- NEVER use TeamCreate/TeamDelete — use `genie team create` / `genie team disband`.
|
|
141
|
+
- **Wish progress uses `genie wish status <slug>` — NOT `genie task status`.** The `task` subcommand has no `status` verb; it will error with `unknown command 'status'`. `genie task` is for PG tasks (`list`, `show`, `checkout`, `move`, `done`, `comment`, `block`).
|
|
142
|
+
- **After any `genie update` / version bump, re-read `genie wish --help` and `genie task --help` before typing yesterday's verbs.** Verb namespaces evolve (`genie done`, `genie wish done`, `genie task done` all exist and do different things). Muscle memory is a landmine; the live `--help` output in the sections above is the only source of truth.
|
|
@@ -39,7 +39,7 @@ This creates a git worktree, hires default agents (team-lead, engineer, reviewer
|
|
|
39
39
|
```bash
|
|
40
40
|
genie team ls # List all teams
|
|
41
41
|
genie team ls my-feature # Show team members
|
|
42
|
-
genie
|
|
42
|
+
genie wish status my-feature-slug # Wish group progress
|
|
43
43
|
genie agent log team-lead # Unified log
|
|
44
44
|
genie agent log team-lead --raw # Raw pane output
|
|
45
45
|
```
|
|
@@ -69,8 +69,8 @@ The canonical hacks live in the docs at `genie/hacks.mdx`. Below is the embedded
|
|
|
69
69
|
genie team create api-v2 --repo . --wish api-v2
|
|
70
70
|
|
|
71
71
|
# Monitor both
|
|
72
|
-
genie
|
|
73
|
-
genie
|
|
72
|
+
genie wish status auth-refactor
|
|
73
|
+
genie wish status api-v2
|
|
74
74
|
|
|
75
75
|
# Cross-team messaging
|
|
76
76
|
genie agent send 'auth-refactor is done, you can proceed' --to api-v2-team-lead
|
|
@@ -227,7 +227,7 @@ The canonical hacks live in the docs at `genie/hacks.mdx`. Below is the embedded
|
|
|
227
227
|
|
|
228
228
|
# Check team status
|
|
229
229
|
genie team ls my-team
|
|
230
|
-
genie
|
|
230
|
+
genie wish status my-wish-slug
|
|
231
231
|
|
|
232
232
|
# Unstick a blocked group
|
|
233
233
|
genie wish reset my-wish-slug#2
|
package/skills/pm/SKILL.md
CHANGED
|
@@ -342,8 +342,8 @@ genie team disband <name>
|
|
|
342
342
|
```bash
|
|
343
343
|
genie agent spawn <role>
|
|
344
344
|
genie work <slug>
|
|
345
|
-
genie
|
|
346
|
-
genie
|
|
345
|
+
genie wish status <slug>
|
|
346
|
+
genie wish done <slug>#<group>
|
|
347
347
|
genie wish reset <slug>#<group>
|
|
348
348
|
```
|
|
349
349
|
|
|
@@ -368,7 +368,7 @@ genie task move #42 --to build
|
|
|
368
368
|
genie team create rate-limiting --repo . --wish rate-limiting
|
|
369
369
|
|
|
370
370
|
# 5. Monitor: track progress
|
|
371
|
-
genie
|
|
371
|
+
genie wish status rate-limiting
|
|
372
372
|
genie events summary --today
|
|
373
373
|
|
|
374
374
|
# 6. Review: validate work
|
package/skills/report/SKILL.md
CHANGED
|
@@ -246,7 +246,7 @@ genie agent send 'Trace: genie work dispatches engineers but they start idle. Ch
|
|
|
246
246
|
|
|
247
247
|
# 3. Capture evidence
|
|
248
248
|
# Screenshot of idle engineer pane showing empty ❯ prompt
|
|
249
|
-
# Output of: genie
|
|
249
|
+
# Output of: genie wish status <slug> showing "in_progress" but no actual progress
|
|
250
250
|
|
|
251
251
|
# 4. Create GitHub issue with all findings
|
|
252
252
|
gh issue create --title "bug: genie work dispatch — engineers spawn idle without initial task prompt" --body "$(cat <<'EOF'
|
|
@@ -259,7 +259,7 @@ protocolRouter.sendMessage fails silently under concurrent dispatch (4/6 enginee
|
|
|
259
259
|
|
|
260
260
|
## Evidence
|
|
261
261
|
- [Screenshot: idle engineer pane]
|
|
262
|
-
- genie
|
|
262
|
+
- genie wish status shows in_progress but engineers at empty prompt
|
|
263
263
|
- Native inbox files: engineer-1 through engineer-4 have no dispatch message
|
|
264
264
|
|
|
265
265
|
## Steps to Reproduce
|
package/skills/trace/SKILL.md
CHANGED
|
@@ -66,7 +66,7 @@ An engineer reports that `genie work` dispatches engineers but they sit idle. Th
|
|
|
66
66
|
genie agent spawn tracer
|
|
67
67
|
|
|
68
68
|
# 2. Send the symptoms
|
|
69
|
-
genie agent send 'Trace: genie work dispatches engineers but they start idle at the prompt. No task received. genie
|
|
69
|
+
genie agent send 'Trace: genie work dispatches engineers but they start idle at the prompt. No task received. genie wish status shows in_progress but nothing happens. Check dispatch.ts workDispatchCommand and protocol-router.ts sendMessage.' --to tracer
|
|
70
70
|
|
|
71
71
|
# 3. Wait for findings
|
|
72
72
|
sleep 60 && genie agent log tracer --raw
|
package/skills/work/SKILL.md
CHANGED
|
@@ -112,7 +112,7 @@ Depends-on: <group refs or "none">
|
|
|
112
112
|
## State Management
|
|
113
113
|
|
|
114
114
|
- **Workers signal** completion via `genie agent send` to the leader when a group is done.
|
|
115
|
-
- **Leader tracks** state via `genie
|
|
115
|
+
- **Leader tracks** wish-group state via `genie wish status <slug>` and marks groups complete via `genie wish done <slug>#<group>` (and, when PG tasks exist, `genie task done #<seq>`).
|
|
116
116
|
- Workers do NOT call `genie task done` — that is the leader's responsibility after verifying the work.
|
|
117
117
|
- If a group gets stuck, the leader can use `genie wish reset <ref>` to retry.
|
|
118
118
|
|
|
@@ -150,11 +150,11 @@ genie work fix-dispatch-initial-prompt
|
|
|
150
150
|
# 🔧 Dispatching work to engineer for "fix-dispatch-initial-prompt#1"
|
|
151
151
|
|
|
152
152
|
# 2. Monitor (ALWAYS sleep 60 between checks)
|
|
153
|
-
sleep 60 && genie
|
|
153
|
+
sleep 60 && genie wish status fix-dispatch-initial-prompt
|
|
154
154
|
# Output: Group 1: 🔄 in_progress
|
|
155
155
|
|
|
156
156
|
# 3. Check again
|
|
157
|
-
sleep 60 && genie
|
|
157
|
+
sleep 60 && genie wish status fix-dispatch-initial-prompt
|
|
158
158
|
# Output: Group 1: ✅ done — Progress: 1/1 done
|
|
159
159
|
|
|
160
160
|
# 4. All groups done → local review
|