@sergeychuvayev/claude-fleet 0.6.0 → 0.7.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/README.md +24 -2
- package/managed.js +38 -6
- package/package.json +1 -1
- package/public/app.js +9 -2
- package/public/styles.css +6 -0
- package/tasks.js +14 -3
- package/teams.js +14 -1
package/README.md
CHANGED
|
@@ -412,7 +412,11 @@ In **New agent**, choose **Software delivery** to give a brief to a Manager back
|
|
|
412
412
|
Product, Developer, Reviewer and QA roles. Choose **Customize team…** to save your own
|
|
413
413
|
team: rename/add/remove roles, write their instructions, select a Claude model per role,
|
|
414
414
|
and choose allowed tools. Built-in teams are copied; existing custom teams can be edited.
|
|
415
|
-
|
|
415
|
+
Choose **Quick task** for small, clearly scoped changes: a Sonnet manager, one developer,
|
|
416
|
+
and one independent QA verifier, with two implementation attempts and a $3 usage cap.
|
|
417
|
+
**Software delivery** keeps the thorough review-and-QA workflow. **No team · single agent**
|
|
418
|
+
avoids orchestration entirely when you just need one agent. Existing initiatives keep
|
|
419
|
+
their original team snapshot. The original Bug fix preset remains available.
|
|
416
420
|
|
|
417
421
|
One role is the manager and at least one separate role is a required verifier. A third
|
|
418
422
|
role owns the work. Fleet adds delegation and operator-question tools to the manager;
|
|
@@ -431,7 +435,7 @@ not a guarantee that their evaluation is correct or that later work cannot regre
|
|
|
431
435
|
|
|
432
436
|
Delegations run sequentially in the shared initiative worktree. After an interruption,
|
|
433
437
|
the saved task board survives and unfinished delegations are marked interrupted. Message
|
|
434
|
-
the Manager to resume.
|
|
438
|
+
the Manager to resume. Software delivery starts with three implementation attempts per task and
|
|
435
439
|
$10 in reported SDK usage; **Adjust limits** changes them explicitly while idle. The SDK
|
|
436
440
|
budget is an execution cutoff, not a billing guarantee: usage is reported at turn end,
|
|
437
441
|
and a killed runtime may not report its final spend. Each turn also has a 100-turn SDK
|
|
@@ -442,3 +446,21 @@ snapshots live with the initiative in `sessions.json`. This version supports mod
|
|
|
442
446
|
available through the Claude Agent SDK, up to eight roles per team, and 100 tasks per
|
|
443
447
|
initiative. It finishes at a local branch ready for review; it does not automatically
|
|
444
448
|
publish or merge changes.
|
|
449
|
+
|
|
450
|
+
### Inspect individual agents
|
|
451
|
+
|
|
452
|
+
Select a subagent row beneath a managed initiative to inspect its assignment, actual
|
|
453
|
+
model, status, elapsed time, attempt, tool steps, and report. Expand **Input and output**
|
|
454
|
+
to see a tool's recorded payload. The inspector is read-only; send direction and answer
|
|
455
|
+
approvals through the manager. Tool history keeps the most recent 200 steps with bounded
|
|
456
|
+
inputs and outputs. Older runs may have no recorded steps or usage.
|
|
457
|
+
|
|
458
|
+
The inspector shows reported input/output and cache tokens, or SDK progress totals when
|
|
459
|
+
only those are available. Repeated assistant events do not count usage twice. Per-agent
|
|
460
|
+
cost appears only when the SDK explicitly reports it; missing data is not shown as zero.
|
|
461
|
+
Token totals describe recorded usage across messages, not current context size.
|
|
462
|
+
|
|
463
|
+
Task-board reads return compact metadata, so repeatedly checking task state does not
|
|
464
|
+
re-inject all assignments, tool output and reports into the manager's context. The manager
|
|
465
|
+
can request a specific delegation's full assignment/report using the task tool's
|
|
466
|
+
`inspect` action with `delegationId`. Verification gates and saved evidence are unchanged.
|
package/managed.js
CHANGED
|
@@ -359,18 +359,30 @@ class ManagedSessions extends EventEmitter {
|
|
|
359
359
|
const content=event.message.content || []
|
|
360
360
|
d.activity=content.filter(b=>b.type==='tool_use').map(b=>b.name).join(', ') || d.activity
|
|
361
361
|
d.model=event.message.model || d.model
|
|
362
|
+
this.delegationUsage(d,run,event.message)
|
|
362
363
|
const output=content.filter(b=>b.type==='text').map(b=>b.text).join('\n')
|
|
363
364
|
if (output) d.output=output.slice(0,24000)
|
|
364
365
|
// The one place a sub-agent's own tool calls are kept at all: as steps on its
|
|
365
366
|
// delegation, never as messages (every branch above stays guarded by
|
|
366
|
-
// `!event.parent_tool_use_id`).
|
|
367
|
+
// `!event.parent_tool_use_id`). Inputs and results are bounded for inspection.
|
|
367
368
|
for (const block of content) if (block.type==='tool_use') this.stepStarted(d,block)
|
|
368
369
|
}
|
|
370
|
+
if (d && event.type==='result' && Number.isFinite(event.total_cost_usd) && event.total_cost_usd>=0) d.costUsd=event.total_cost_usd
|
|
369
371
|
if (d && event.type==='user') {
|
|
370
372
|
for (const block of event.message?.content || []) if (block.type==='tool_result') this.stepFinished(d,block)
|
|
371
373
|
}
|
|
372
374
|
}
|
|
373
|
-
if (event.type
|
|
375
|
+
if (s.taskBoard && event.type==='system' && ['task_progress','task_notification'].includes(event.subtype)) {
|
|
376
|
+
const d=s.taskBoard.delegations.find(d=>d.id===event.tool_use_id)
|
|
377
|
+
if (d && event.usage) {
|
|
378
|
+
d.runtimeUsage ||= {}
|
|
379
|
+
for (const key of ['total_tokens','tool_uses','duration_ms']) {
|
|
380
|
+
const value=event.usage[key]
|
|
381
|
+
if (Number.isFinite(value) && value>=0) d.runtimeUsage[key]=Math.max(d.runtimeUsage[key] || 0,value)
|
|
382
|
+
}
|
|
383
|
+
}
|
|
384
|
+
}
|
|
385
|
+
if (event.type === 'system' && event.subtype === 'init' && !event.parent_tool_use_id) { s.model=event.model; s.status='running' }
|
|
374
386
|
if (event.type === 'stream_event' && !event.parent_tool_use_id) {
|
|
375
387
|
if (event.event.type === 'message_start') { run.assistant=null; run.streamText='' }
|
|
376
388
|
if (event.event.delta?.type === 'text_delta') {
|
|
@@ -398,9 +410,9 @@ class ManagedSessions extends EventEmitter {
|
|
|
398
410
|
if (event.type === 'user' && !event.parent_tool_use_id) {
|
|
399
411
|
for (const block of event.message?.content || []) if (block.type==='tool_result') this.toolFinished(s,run,block)
|
|
400
412
|
}
|
|
401
|
-
if (event.type === 'tool_progress') s.currentTool=event.tool_name
|
|
413
|
+
if (event.type === 'tool_progress' && !event.parent_tool_use_id) s.currentTool=event.tool_name
|
|
402
414
|
if (s.taskBoard && event.type==='system' && event.subtype==='task_notification' && event.tool_use_id && event.status!=='completed') tasks.finish(s,event.tool_use_id,event.summary,true)
|
|
403
|
-
if (event.type === 'result') {
|
|
415
|
+
if (event.type === 'result' && !event.parent_tool_use_id) {
|
|
404
416
|
run.result=true
|
|
405
417
|
if (event.is_error) { s.status='error'; s.error=event.errors?.join('\n') || event.result || 'Claude could not finish this turn.' }
|
|
406
418
|
else if (event.result && !s.messages.some(m=>m.role==='assistant' && m.text===event.result.slice(-24000))) s.messages.push({id:randomUUID(),role:'assistant',text:event.result.slice(-24000),at:Date.now()})
|
|
@@ -441,13 +453,13 @@ class ManagedSessions extends EventEmitter {
|
|
|
441
453
|
entry.result = block.is_error || !QUIET_RESULT.has(entry.tool) ? result.slice(0,MAX_TOOL_RESULT) : null
|
|
442
454
|
}
|
|
443
455
|
// A sub-agent's tool call becomes a step on its delegation rather than a conversation
|
|
444
|
-
// entry:
|
|
456
|
+
// entry: bounded input/output, status and timing, so the operator can see what happened
|
|
445
457
|
// without the console ever rendering it.
|
|
446
458
|
stepStarted(d,block) {
|
|
447
459
|
if (!block.id) return
|
|
448
460
|
d.steps ||= []
|
|
449
461
|
if (d.steps.some(step=>step.id===block.id)) return
|
|
450
|
-
d.steps.push({id:block.id,tool:block.name || 'Tool',target:toolTarget(block.name,block.input),status:'running',at:Date.now(),ms:null})
|
|
462
|
+
d.steps.push({id:block.id,tool:block.name || 'Tool',target:toolTarget(block.name,block.input),input:clampInput(block.input),result:null,status:'running',at:Date.now(),ms:null})
|
|
451
463
|
if (d.steps.length > MAX_DELEGATION_STEPS) { d.steps=d.steps.slice(-MAX_DELEGATION_STEPS); d.stepsTruncated=true }
|
|
452
464
|
}
|
|
453
465
|
stepFinished(d,block) {
|
|
@@ -455,6 +467,26 @@ class ManagedSessions extends EventEmitter {
|
|
|
455
467
|
if (!step || step.status!=='running') return
|
|
456
468
|
step.status=block.is_error ? 'error' : 'done'
|
|
457
469
|
step.ms=Date.now()-step.at
|
|
470
|
+
const result=resultText(block.content)
|
|
471
|
+
step.result=result.slice(0,MAX_TOOL_RESULT)
|
|
472
|
+
step.truncated=result.length>MAX_TOOL_RESULT
|
|
473
|
+
}
|
|
474
|
+
// The SDK can emit multiple blocks for the same assistant message. Count each
|
|
475
|
+
// usage counter only once, accepting later updates without double-counting.
|
|
476
|
+
delegationUsage(d,run,message) {
|
|
477
|
+
if (!message.id || !message.usage) return
|
|
478
|
+
run.delegationUsage ||= new Map()
|
|
479
|
+
const key=JSON.stringify([d.id,message.id])
|
|
480
|
+
const previous=run.delegationUsage.get(key) || {}
|
|
481
|
+
d.usage ||= {}
|
|
482
|
+
for (const field of ['input_tokens','output_tokens','cache_read_input_tokens','cache_creation_input_tokens']) {
|
|
483
|
+
const value=message.usage[field]
|
|
484
|
+
if (!Number.isFinite(value) || value<0) continue
|
|
485
|
+
const next=Math.max(previous[field] || 0,value)
|
|
486
|
+
d.usage[field]=(d.usage[field] || 0)+next-(previous[field] || 0)
|
|
487
|
+
previous[field]=next
|
|
488
|
+
}
|
|
489
|
+
run.delegationUsage.set(key,previous)
|
|
458
490
|
}
|
|
459
491
|
setLimits(id,body) {
|
|
460
492
|
const s=this.get(id)
|
package/package.json
CHANGED
package/public/app.js
CHANGED
|
@@ -234,12 +234,19 @@ function renderChildDetail(s, delegationId) {
|
|
|
234
234
|
const cls = DELEGATION_BADGE[state] || ''
|
|
235
235
|
const label = DELEGATION_LABEL[state] || state
|
|
236
236
|
const steps = full?.steps || []
|
|
237
|
+
const openedSteps=new Set([...document.querySelectorAll('[data-child-step][open]')].map(el=>el.dataset.childStep))
|
|
238
|
+
const focusedStep=document.activeElement?.closest('[data-child-step]')?.dataset.childStep
|
|
239
|
+
const usage=full?.usage
|
|
240
|
+
const usageText=usage ? `${tokens(usage.input_tokens || 0)} input · ${tokens(usage.output_tokens || 0)} output · ${tokens(usage.cache_read_input_tokens || 0)} cache read · ${tokens(usage.cache_creation_input_tokens || 0)} cache write` : full?.runtimeUsage?.total_tokens != null ? `${tokens(full.runtimeUsage.total_tokens)} tokens reported` : 'Token usage not reported'
|
|
241
|
+
const duration=full?.startedAt ? elapsed((full.finishedAt || Date.now())-full.startedAt) : 'Duration unavailable'
|
|
242
|
+
|
|
237
243
|
// Selecting a child tears down the console, so an approval sitting on the owning
|
|
238
244
|
// session would otherwise wait in total silence. A notice only: nothing here can
|
|
239
245
|
// answer it, so it just points the operator back to the row that can.
|
|
240
246
|
const approvalNotice = s.managedStatus === 'approval' ? `<p class="note child-approval-notice">${esc(s.name || s.title || 'This session')} needs your approval to continue. Select its row above to respond — this read-only view can’t.</p>` : ''
|
|
241
|
-
const stepsHtml = steps.length ? `<ol class="child-steps">${steps.map(step => `<li class="child-step" data-status="${esc(step.status)}"><span class="child-step-tool">${esc(step.tool)}</span>${step.target ? `<span class="child-step-target">${esc(step.target)}</span>` : ''}<span class="child-step-state">${esc(STEP_LABEL[step.status] || step.status)}</span><span class="child-step-time">${step.ms != null ? elapsed(step.ms) : step.status === 'running' ? 'running…' : ''}</span></li>`).join('')}</ol>` : `<p class="note">${full ? 'No tool steps recorded.' : 'Loading steps…'}</p>`
|
|
242
|
-
update('detail-content', `<div class="detail-top"><span class="eyebrow">SUB-AGENT · READ ONLY</span><span class="badge ${cls}"><span class="dot"></span>${esc(label)}</span></div>${approvalNotice}<h2>⑂ ${esc(compact.role)}</h2><div class="detail-name">${esc(formatModel(full?.model || compact.model))}</div><section class="detail-section"><h3>Mandate</h3><div class="response">${esc(full ? (full.prompt || 'No mandate recorded.') : 'Loading…')}</div></section><section class="detail-section"><h3>Steps${full?.stepsTruncated ? ' <span>Showing the most recent 200</span>' : ''}</h3>${stepsHtml}</section><section class="detail-section"><h3>Report to the manager</h3><div class="response ${full?.report ? '' : 'missing'}">${esc(full ? (full.report || 'Waiting for this agent’s report.') : 'Loading…')}</div></section>${childDetailError ? `<p class="note">${esc(childDetailError)}</p>` : ''}<p class="note">A sub-agent is not addressable on its own. This is a read-only report back to the manager.</p>`)
|
|
247
|
+
const stepsHtml = steps.length ? `<ol class="child-steps">${steps.map(step => `<li class="child-step" data-status="${esc(step.status)}"><span class="child-step-tool">${esc(step.tool)}</span>${step.target ? `<span class="child-step-target">${esc(step.target)}</span>` : ''}<span class="child-step-state">${esc(STEP_LABEL[step.status] || step.status)}</span><span class="child-step-time">${step.ms != null ? elapsed(step.ms) : step.status === 'running' ? 'running…' : ''}</span>${step.input != null || step.result != null ? `<details class="child-step-detail" data-child-step="${esc(step.id)}" ${openedSteps.has(step.id) ? 'open':''}><summary>Input and output</summary><h4>Input</h4><pre>${esc(step.input == null ? 'Not recorded' : typeof step.input === 'string' ? step.input : JSON.stringify(step.input,null,2))}</pre><h4>Output${step.truncated ? ' · truncated':''}</h4><pre>${esc(step.result ?? 'No result reported yet.')}</pre></details>`:''}</li>`).join('')}</ol>` : `<p class="note">${full ? 'No tool steps recorded.' : 'Loading steps…'}</p>`
|
|
248
|
+
update('detail-content', `<div class="detail-top"><span class="eyebrow">SUB-AGENT · READ ONLY</span><span class="badge ${cls}"><span class="dot"></span>${esc(label)}</span></div>${approvalNotice}<h2>⑂ ${esc(compact.role)}</h2><div class="detail-name">${esc(formatModel(full?.model || compact.model))} · ${esc(duration)}${full?.attempt ? ` · attempt ${full.attempt}` : ''}</div><p class="note">${esc(usageText)}. ${full?.costUsd != null ? `Reported cost: ${esc(money(full.costUsd) || '$0.00')}` : 'Per-agent cost not reported'}.</p><section class="detail-section"><h3>Mandate</h3><div class="response">${esc(full ? (full.prompt || 'No mandate recorded.') : 'Loading…')}</div></section><section class="detail-section"><h3>Steps${full?.stepsTruncated ? ' <span>Showing the most recent 200</span>' : ''}</h3>${stepsHtml}</section><section class="detail-section"><h3>Report to the manager</h3><div class="response ${full?.report ? '' : 'missing'}">${esc(full ? (full.report || 'Waiting for this agent’s report.') : 'Loading…')}</div></section>${childDetailError ? `<p class="note">${esc(childDetailError)}</p>` : ''}<p class="note">A sub-agent is not addressable on its own. This is a read-only report back to the manager.</p>`)
|
|
249
|
+
if(focusedStep) document.querySelector(`[data-child-step="${CSS.escape(focusedStep)}"]>summary`)?.focus({preventScroll:true})
|
|
243
250
|
}
|
|
244
251
|
// The list payload only ever carries id/role/model/status for a delegation; its steps,
|
|
245
252
|
// mandate and report live on the session detail route, fetched independently of the
|
package/public/styles.css
CHANGED
|
@@ -516,3 +516,9 @@ body[data-modal]{overflow:hidden}
|
|
|
516
516
|
/* Selecting a child hides the console, so a pending approval on the owning session
|
|
517
517
|
would otherwise go unnoticed; this is the one visible sign it is still waiting. */
|
|
518
518
|
.child-approval-notice{color:var(--text);background:color-mix(in srgb,var(--stale) 14%,transparent);border:1px solid var(--stale);border-radius:6px;padding:10px 12px;margin-bottom:17px}
|
|
519
|
+
|
|
520
|
+
/* Drill into a tool without expanding every payload in the agent inspector. */
|
|
521
|
+
.child-step-detail{grid-column:1/-1;min-width:0}
|
|
522
|
+
.child-step-detail summary{cursor:pointer;color:var(--muted);padding:4px 0}
|
|
523
|
+
.child-step-detail pre{white-space:pre-wrap;overflow-wrap:anywhere;max-height:320px;overflow:auto;font-size:12px}
|
|
524
|
+
.child-step-detail h4{margin:10px 0 4px;font-size:12px}
|
package/tasks.js
CHANGED
|
@@ -6,7 +6,18 @@ function ledger(s) {return s.taskBoard ||= {tasks:[],delegations:[]}}
|
|
|
6
6
|
function taskFor(s,id) {const task=ledger(s).tasks.find(t=>t.id===id);if(!task)fail('Task not found. Read the Fleet task board.');return task}
|
|
7
7
|
function act(s,input) {
|
|
8
8
|
const board=ledger(s)
|
|
9
|
-
|
|
9
|
+
// The durable ledger also powers the inspector. Never send its full transcript
|
|
10
|
+
// back into the manager context on every list call.
|
|
11
|
+
if (input.action==='list') return {
|
|
12
|
+
tasks:board.tasks,
|
|
13
|
+
delegations:board.delegations.map(d=>({id:d.id,taskId:d.taskId,role:d.role,attempt:d.attempt,status:d.status,startedAt:d.startedAt,finishedAt:d.finishedAt})),
|
|
14
|
+
detailHint:'Use inspect with delegationId to read an assignment and report.',
|
|
15
|
+
}
|
|
16
|
+
if (input.action==='inspect') {
|
|
17
|
+
const d=board.delegations.find(d=>d.id===input.delegationId)
|
|
18
|
+
if (!d) fail('Delegation not found. Read the Fleet task board.')
|
|
19
|
+
return {id:d.id,taskId:d.taskId,role:d.role,status:d.status,prompt:d.prompt,report:d.report,output:d.report ? undefined:d.output}
|
|
20
|
+
}
|
|
10
21
|
if (input.action==='create') {
|
|
11
22
|
if (board.tasks.length>=100) fail('This initiative has reached its 100-task limit.')
|
|
12
23
|
const owner=input.owner,team=s.teamSnapshot
|
|
@@ -91,8 +102,8 @@ function progress(s) {
|
|
|
91
102
|
async function sdkServer(s,changed) {
|
|
92
103
|
const {createSdkMcpServer,tool}=await import('@anthropic-ai/claude-agent-sdk')
|
|
93
104
|
const {z}=require('zod/v4')
|
|
94
|
-
return createSdkMcpServer({name:'fleet',version:'1.0.0',tools:[tool('tasks','Read
|
|
95
|
-
action:z.enum(['list','create','block']),title:z.string().optional(),owner:z.string().optional(),criteria:z.array(z.string()).optional(),dependencies:z.array(z.string()).optional(),taskId:z.string().optional(),reason:z.string().optional(),
|
|
105
|
+
return createSdkMcpServer({name:'fleet',version:'1.0.0',tools:[tool('tasks','Read a compact task board; inspect delegation assignments/reports by delegationId; create scoped tasks with criteria and dependencies; record blockers. Fleet records verification from actual agent reports.',{
|
|
106
|
+
action:z.enum(['list','inspect','create','block']),delegationId:z.string().optional(),title:z.string().optional(),owner:z.string().optional(),criteria:z.array(z.string()).optional(),dependencies:z.array(z.string()).optional(),taskId:z.string().optional(),reason:z.string().optional(),
|
|
96
107
|
},async input=>{
|
|
97
108
|
const before=structuredClone(s.taskBoard)
|
|
98
109
|
try {const result=act(s,input);changed();return {content:[{type:'text',text:JSON.stringify(result)}]}}
|
package/teams.js
CHANGED
|
@@ -174,7 +174,7 @@ const TEAMS = {
|
|
|
174
174
|
const READ_TOOLS = ['Read','Glob','Grep','WebSearch','WebFetch']
|
|
175
175
|
TEAMS.delivery = {
|
|
176
176
|
id:'delivery', name:'Software delivery',
|
|
177
|
-
description:'
|
|
177
|
+
description:'Thorough workflow: scoped work, implementation, independent code review and QA.',
|
|
178
178
|
manager:'manager',
|
|
179
179
|
workflow:{reviewers:['reviewer','qa'],maxAttempts:3,budgetUsd:10},
|
|
180
180
|
roles:{
|
|
@@ -185,9 +185,22 @@ TEAMS.delivery = {
|
|
|
185
185
|
qa:{description:'Verifies acceptance criteria with reproducible evidence.',prompt:QA,model:'sonnet',tools:[...READ_TOOLS,'Bash']},
|
|
186
186
|
},
|
|
187
187
|
}
|
|
188
|
+
// A lighter explicit choice, using the same durable gates and snapshot mechanism.
|
|
189
|
+
TEAMS.quick = {
|
|
190
|
+
id:'quick',name:'Quick task',
|
|
191
|
+
description:'Small, clear changes: one developer and one independent verifier, with focused checks.',
|
|
192
|
+
manager:'manager',workflow:{reviewers:['qa'],maxAttempts:2,budgetUsd:3},
|
|
193
|
+
roles:{
|
|
194
|
+
manager:{...TEAMS.delivery.roles.manager,model:'sonnet',prompt:'Coordinate a small, clearly scoped task. Read only relevant instructions and files. Create one task unless the goal has independent deliverables. Give the developer file boundaries, acceptance criteria and exact checks. Use one QA verification. Avoid broad audits, speculative improvements and repeated repository exploration. Pass concise findings and test evidence between roles.'},
|
|
195
|
+
developer:{...TEAMS.delivery.roles.developer,prompt:DEVELOPER+'\nKeep investigation scoped to the acceptance criteria. Run relevant checks once after the final change; repeat only after a failure or further change.'},
|
|
196
|
+
qa:{...TEAMS.delivery.roles.qa,prompt:QA+'\nKeep verification proportional to this small task. Focus on acceptance criteria and directly affected behavior; stop once sufficient evidence exists.'},
|
|
197
|
+
},
|
|
198
|
+
}
|
|
188
199
|
const TASK_RULES = `
|
|
189
200
|
|
|
190
201
|
Fleet owns the durable task board. Use mcp__fleet__tasks to read it and create tasks before delegating.
|
|
202
|
+
List returns compact metadata; use inspect with delegationId when you need a prior assignment or report.
|
|
203
|
+
Read the board on resume and when state is uncertain, not repeatedly between every action.
|
|
191
204
|
Each task needs an owner, acceptance criteria and optional dependencies. All configured verification
|
|
192
205
|
roles must verify each deliverable. Include a line "Fleet task: <task ID>" in EVERY Agent prompt.
|
|
193
206
|
Invoke only the owner or a configured verification role. Work sequentially in this shared worktree.
|