Skip to content
This repository was archived by the owner on Mar 26, 2026. It is now read-only.
6 changes: 3 additions & 3 deletions .spec/CollaborationProtocol/ignition-prompts.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,8 +51,8 @@ You are part of a multi-agent team. Follow these rules:
**Hierarchy**
- You report to: {parent_agent} (or boss if no parent)
- Send status updates to your manager via message when significant progress happens
- Message your manager directly when blocked; message the boss agent channel for boss-level decisions
- Escalate to boss only after manager unresponsive for 30+ minutes
- Message your manager when blocked; set the task to `blocked` status
- Escalate up the chain if your manager is unresponsive

**Your Role**
- Your role is defined by the agent that spawned you — check your ignition message for specifics
Expand All @@ -72,7 +72,7 @@ You → {parent} → {grandparent} → boss
Peers (same manager): {peer1}, {peer2}
Your team (if manager): {child1}, {child2}

Note: The org structure may change as work evolves. Check your messages for hierarchy updates.
Note: Your position in the team is set by whoever spawned you. Check your ignition message for specifics.
```

### Section: Work Loop
Expand Down
11 changes: 6 additions & 5 deletions .spec/CollaborationProtocol/messaging-protocol.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,8 +63,8 @@ the Escalation section below.

### 4. Peer-to-Peer Coordination

Agents may message any peer directly — no manager authorization is required. Peer communication
is the default; a manager can explicitly forbid a specific interaction if needed.
Agents may message any peer directly — no authorization required. Direct peer messaging is always
allowed.

```
DevA sends message to DevB:
Expand All @@ -76,10 +76,11 @@ update so the manager has visibility.

### 5. Escalation

If work is blocked and the manager is unresponsive for >30 minutes:
If work is blocked and the manager is unresponsive after multiple check cycles, escalate up the
chain — message the manager's manager (or the operator if no higher level exists):
```
Agent sends message to boss:
"ESCALATION: TASK-{id} blocked on {blocker}. Manager {ManagerName} unresponsive for 30+ min."
Agent sends message to {ManagersManager}:
"TASK-{id} blocked on {blocker}. {ManagerName} has not responded. Requesting escalation."
```

## Message Discipline
Expand Down
2 changes: 1 addition & 1 deletion .spec/CollaborationProtocol/organizational-model.md
Original file line number Diff line number Diff line change
Expand Up @@ -115,7 +115,7 @@ Every task must have: an assignee, a parent (or be a root task), and a status th

- Agents report status up (via messages and status updates)
- Managers send decisions down (via task assignment and messages)
- Peers coordinate laterally (via direct messages — allowed by default; manager can restrict specific interactions as an exception)
- Peers coordinate laterally (via direct messages — always allowed, no authorization required)

### 5. Context at the edge

Expand Down
8 changes: 5 additions & 3 deletions .spec/CollaborationProtocol/team-formation.md
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ meets **any** of these criteria:
- Has more than one acceptance criterion
- Is a planning, spec, or design task (always non-trivial)
- Would benefit from an independent review pass
- Estimated effort exceeds ~30 minutes of focused work
- Could benefit from a second perspective or independent review
- Requires more than one focused action to complete (e.g. research then implement, or implement then test)

Solo work is appropriate only for tightly scoped leaf tasks: a single bug fix, a one-file
documentation update, or a clearly-specified implementation with no design decisions.
Solo work is appropriate only for atomic leaf tasks: a single, completely specified change with
no decisions to make and no more than one deliverable. When in doubt, form a team — the cost of
an extra agent is far lower than the cost of a solo agent going off in the wrong direction.

## Required Team Roles

Expand Down
8 changes: 4 additions & 4 deletions docs/AGENT_PROTOCOL.md
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ X-Agent-Name: {agent}
}
],
"next_steps": "open PR after tests pass",
"questions": ["[?BOSS] should we use approach X or Y?"],
"questions": ["should we use approach X or Y?"],
"blockers": ["waiting for DataMgr to merge PR #7"],
"parent": "ManagerAgent",
"role": "Developer",
Expand All @@ -158,7 +158,7 @@ X-Agent-Name: {agent}
| `items` | array | no | Bullet points shown in dashboard |
| `sections` | array | no | Titled sub-sections with item lists |
| `next_steps` | string | no | What you will do next |
| `questions` | array | no | Auto-tagged `[?BOSS]` in dashboard |
| `questions` | array | no | Questions surfaced in the dashboard for the human operator |
| `blockers` | array | no | Highlighted in dashboard |
| `parent` | string | no | Manager agent name — sticky hierarchy link |
| `role` | string | no | Display label e.g. `"Developer"`, `"SME"` |
Expand Down Expand Up @@ -568,7 +568,7 @@ X-Agent-Boss-Agent: {agent}
4. GET /agent/{agent}/events → open SSE stream (blocking)
↕ (in parallel)
5. Do work
6. POST /agent/{agent} → status update every ~10 minutes
6. POST /agent/{agent} → status update at meaningful milestones
7. On SSE message event → act immediately
8. POST /agent/{agent} → status: done when finished
```
Expand Down Expand Up @@ -691,7 +691,7 @@ Non-tmux agents (Docker, CI, remote, script) interact with the coordinator exact

1. **Register** with `agent_type` set to your runtime (`"http"`, `"docker"`, `"script"`, etc.)
2. **Set `heartbeat_interval_sec`** if you want staleness detection (recommended: 60)
3. **Post status updates** at least every 10 minutes during active work
3. **Post status updates** at meaningful milestones (task complete, blocker hit, PR opened, etc.)
4. **Send heartbeats** at your registered interval
5. **Subscribe to SSE** or poll `/messages` for incoming instructions
6. **Post `"status": "done"`** when finished
Expand Down
26 changes: 17 additions & 9 deletions frontend/src/components/TaskDetailPanel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -86,21 +86,28 @@ const subtaskItems = computed(() => {
})

function buildPrUrl(pr: string): string | null {
if (pr.startsWith('http')) return pr
// Already a full URL
if (/^https?:\/\//.test(pr)) return pr
// URL missing protocol (e.g. github.com/org/repo/pull/42)
if (/^(github\.com|gitlab\.com)\//.test(pr)) return 'https://' + pr

// Extract a bare PR number from formats like #42, PR #42, PR-42, 42
const numMatch = pr.match(/(\d+)$|#(\d+)/)
const num = numMatch ? (numMatch[1] ?? numMatch[2]) : null
if (!num) return null

// Try to build URL from the assigned agent's repo_url
if (props.task?.assigned_to) {
const agent = props.space.agents[props.task.assigned_to]
if (agent?.repo_url) {
const base = agent.repo_url.replace(/\.git$/, '').replace(/\/$/, '')
const num = pr.replace(/^#/, '')
return `${base}/pull/${num}`
}
}
// Fall back to any agent in the space that has a repo_url
for (const agent of Object.values(props.space.agents ?? {})) {
if (agent.repo_url) {
const base = agent.repo_url.replace(/\.git$/, '').replace(/\/$/, '')
const num = pr.replace(/^#/, '')
return `${base}/pull/${num}`
}
}
Expand Down Expand Up @@ -217,7 +224,7 @@ async function setDueDate(value: string) {

<template>
<Sheet :open="open" @update:open="emit('update:open', $event)">
<SheetContent class="w-full sm:w-[480px] md:w-[540px] overflow-y-auto flex flex-col gap-0 p-0">
<SheetContent class="w-full sm:w-[560px] md:w-[680px] flex flex-col gap-0 p-0 overflow-hidden">
<div v-if="task" class="flex flex-col h-full">
<!-- Header -->
<SheetHeader class="px-6 pt-6 pb-4 border-b border-border">
Expand Down Expand Up @@ -389,7 +396,7 @@ async function setDueDate(value: string) {
<!-- Description -->
<div v-if="task.description" class="flex flex-col gap-1.5">
<span class="text-[10px] font-medium text-muted-foreground uppercase tracking-wide">Description</span>
<div class="text-sm text-foreground/80 md-content" v-html="renderMarkdown(task.description)" />
<div class="text-sm text-foreground/80 md-content leading-relaxed" v-html="renderMarkdown(task.description)" />
</div>

<!-- Labels -->
Expand Down Expand Up @@ -417,15 +424,16 @@ async function setDueDate(value: string) {
rel="noopener noreferrer"
class="flex items-center gap-1.5 text-sm text-primary hover:underline"
>
<ExternalLink class="size-3.5" />
<ExternalLink class="size-3.5 shrink-0" />
{{ task.linked_pr }}
</a>
<span
v-else-if="task.linked_pr"
class="flex items-center gap-1.5 text-sm text-muted-foreground"
class="flex items-center gap-1.5 text-sm"
title="No GitHub repo_url configured on agents — cannot resolve full link"
>
<ExternalLink class="size-3.5" />
{{ task.linked_pr }}
<ExternalLink class="size-3.5 shrink-0 text-muted-foreground" />
<code class="text-xs bg-muted px-1.5 py-0.5 rounded">{{ task.linked_pr }}</code>
</span>
</div>
</div>
Expand Down
Loading