feat: add message bus (.msg/) to codex team-lifecycle skill

Align codex version with Claude version's team_msg message bus for
frontend pipeline UI integration:

- Phase 2: create .msg/ dir, write meta.json with pipeline_stages/roles,
  init messages.jsonl with session event
- Phase 4: log task completion events, update role_state in meta.json
- Phase 5: update meta.json status to completed, log shutdown event
- SKILL.md: document .msg/ in session directory and add schema reference
This commit is contained in:
catlog22
2026-03-04 16:35:07 +08:00
parent e9f8a72343
commit 64e772f9b8
4 changed files with 246 additions and 2 deletions

View File

@@ -272,6 +272,9 @@ Execution timeout reached for task ${agent.taskId}. Please:
For each completed agent, extract TASK_COMPLETE data and update state.
```javascript
// Message counter for NDJSON log
let msgCounter = getLastMsgCounter("<session-dir>/.msg/messages.jsonl") + 1
for (const agent of spawnedAgents) {
const output = results.status[agent.agentId]?.completed
if (!output) continue // handled in timeout section
@@ -307,6 +310,26 @@ for (const agent of spawnedAgents) {
// Close agent
close_agent({ id: agent.agentId })
// Log to message bus
logToMessageBus("<session-dir>", msgCounter++, {
from: task.owner,
type: "impl_complete",
summary: `${task.id} completed: ${taskResult.summary || task.status}`,
data: {
task_id: task.id,
status: task.status,
artifact: task.artifact_path,
discuss_verdict: task.discuss_verdict
}
})
// Update role_state in meta.json
updateMetaRoleState("<session-dir>", task.owner, {
status: task.status,
task_id: task.id,
completed_at: task.completed_at
})
// Route by consensus verdict
if (taskResult.discuss_verdict === "consensus_blocked") {
handleConsensusBlocked(task, taskResult)
@@ -714,6 +737,95 @@ result = wait([reviewer]) -> close_agent(reviewer)
---
## Message Bus Helpers
Helper functions for writing to `.msg/messages.jsonl` and updating `.msg/meta.json`. These maintain compatibility with the Claude version's `team_msg` tool format.
### logToMessageBus
Append an NDJSON event to `messages.jsonl`:
```javascript
function logToMessageBus(sessionDir, counter, { from, to, type, summary, data }) {
const msg = {
id: `MSG-${String(counter).padStart(3, '0')}`,
ts: new Date().toISOString(),
from: from || "coordinator",
to: to || "coordinator",
type: type || "message",
summary: summary || `${type} from ${from}`,
data: data || {}
}
// Append to NDJSON log
appendToFile(`${sessionDir}/.msg/messages.jsonl`, JSON.stringify(msg) + "\n")
}
```
### updateMetaRoleState
Update role-specific state in `meta.json`:
```javascript
function updateMetaRoleState(sessionDir, role, stateData) {
const metaPath = `${sessionDir}/.msg/meta.json`
const meta = JSON.parse(Read(metaPath))
if (!meta.role_state) meta.role_state = {}
meta.role_state[role] = {
...meta.role_state[role],
...stateData,
_updated_at: new Date().toISOString()
}
meta.updated_at = new Date().toISOString()
Write(metaPath, JSON.stringify(meta, null, 2))
}
```
### getLastMsgCounter
Read the last message counter from `messages.jsonl`:
```javascript
function getLastMsgCounter(logPath) {
try {
const content = Read(logPath)
const lines = content.trim().split("\n").filter(Boolean)
if (lines.length === 0) return 0
const lastMsg = JSON.parse(lines[lines.length - 1])
return parseInt(lastMsg.id.replace("MSG-", ""), 10)
} catch {
return 0
}
}
```
### meta.json Schema
The `.msg/meta.json` file follows this schema (compatible with Claude version's `team_msg state_update`):
```json
{
"status": "active | paused | completed",
"pipeline_mode": "<mode>",
"pipeline_stages": ["role1", "role2", "..."],
"roles": ["coordinator", "role1", "role2", "..."],
"team_name": "lifecycle",
"role_state": {
"<role>": {
"status": "completed",
"task_id": "TASK-ID",
"completed_at": "<ISO8601>",
"_updated_at": "<ISO8601>"
}
},
"updated_at": "<ISO8601>"
}
```
---
## Next Phase
When pipeline completes (all tasks done, no paused checkpoint), proceed to [Phase 5: Completion Report](05-completion-report.md).