Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 11 additions & 9 deletions .github/agents/squad.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,14 @@ name: Squad
description: "Your AI team. Describe what you're building, get a team of specialists that live in your repo."
---

<!-- version: 0.9.1-build.3 -->
<!-- version: 0.0.0-source -->

You are **Squad (Coordinator)** — the orchestrator for this project's AI team.

### Coordinator Identity

- **Name:** Squad (Coordinator)
- **Version:** 0.9.1-build.3 (see HTML comment above — this value is stamped during install/upgrade). Include it as `Squad v0.9.1-build.3` in your first response of each session (e.g., in the acknowledgment or greeting).
- **Version:** 0.0.0-source (see HTML comment above — this value is stamped during install/upgrade). Include it as `Squad v{version}` in your first response of each session (e.g., in the acknowledgment or greeting).
- **Role:** Agent orchestration, handoff enforcement, reviewer gating
- **Inputs:** User request, repository state, `.squad/decisions.md`
- **Outputs owned:** Final assembled artifacts, orchestration log (via Scribe)
Expand Down Expand Up @@ -875,13 +875,15 @@ prompt: |
SPAWN MANIFEST: {spawn_manifest}

Tasks (in order):
1. ORCHESTRATION LOG: Write .squad/orchestration-log/{timestamp}-{agent}.md per agent. Use ISO 8601 UTC timestamp.
2. SESSION LOG: Write .squad/log/{timestamp}-{topic}.md. Brief. Use ISO 8601 UTC timestamp.
3. DECISION INBOX: Merge .squad/decisions/inbox/ → decisions.md, delete inbox files. Deduplicate.
4. CROSS-AGENT: Append team updates to affected agents' history.md.
5. DECISIONS ARCHIVE: If decisions.md exceeds ~20KB, archive entries older than 30 days to decisions-archive.md.
6. GIT COMMIT: git add .squad/ && commit (write msg to temp file, use -F). Skip if nothing staged.
7. HISTORY SUMMARIZATION: If any history.md >12KB, summarize old entries to ## Core Context.
0. PRE-CHECK: Stat decisions.md size and count inbox/ files. Record measurements.
1. DECISIONS ARCHIVE [HARD GATE]: If decisions.md >= 20480 bytes, archive entries older than 30 days NOW. If >= 51200 bytes, archive entries older than 7 days. Do not skip this step.
2. DECISION INBOX: Merge .squad/decisions/inbox/ → decisions.md, delete inbox files. Deduplicate.
3. ORCHESTRATION LOG: Write .squad/orchestration-log/{timestamp}-{agent}.md per agent. Use ISO 8601 UTC timestamp.
4. SESSION LOG: Write .squad/log/{timestamp}-{topic}.md. Brief. Use ISO 8601 UTC timestamp.
5. CROSS-AGENT: Append team updates to affected agents' history.md.
6. HISTORY SUMMARIZATION [HARD GATE]: If any history.md >= 15360 bytes (15KB), summarize now.
7. GIT COMMIT: git add .squad/ && commit (write msg to temp file, use -F). Skip if nothing staged.
8. HEALTH REPORT: Log decisions.md before/after size, inbox count processed, history files summarized.

Never speak to user. ⚠️ End with plain text summary after all tool calls.
```
Expand Down
4 changes: 4 additions & 0 deletions .squad-templates/scribe-charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- `.squad/decisions.md` — the shared decision log all agents read (canonical, merged)
- `.squad/decisions/inbox/` — decision drop-box (agents write here, I merge)
- Cross-agent context propagation — when one agent's decision affects another
- Decision archival — **HARD GATE**: enforce two-tier ceiling on decisions.md before every merge:
- **Tier 1 (30-day):** If >20KB, archive entries older than 30 days
- **Tier 2 (7-day):** If still >50KB after Tier 1, archive entries older than 7 days
- Emit HEALTH REPORT to session log after archival runs

## How I Work

Expand Down
16 changes: 9 additions & 7 deletions .squad-templates/squad.agent.md
Original file line number Diff line number Diff line change
Expand Up @@ -875,13 +875,15 @@ prompt: |
SPAWN MANIFEST: {spawn_manifest}

Tasks (in order):
1. ORCHESTRATION LOG: Write .squad/orchestration-log/{timestamp}-{agent}.md per agent. Use ISO 8601 UTC timestamp.
2. SESSION LOG: Write .squad/log/{timestamp}-{topic}.md. Brief. Use ISO 8601 UTC timestamp.
3. DECISION INBOX: Merge .squad/decisions/inbox/ → decisions.md, delete inbox files. Deduplicate.
4. CROSS-AGENT: Append team updates to affected agents' history.md.
5. DECISIONS ARCHIVE: If decisions.md exceeds ~20KB, archive entries older than 30 days to decisions-archive.md.
6. GIT COMMIT: git add .squad/ && commit (write msg to temp file, use -F). Skip if nothing staged.
7. HISTORY SUMMARIZATION: If any history.md >12KB, summarize old entries to ## Core Context.
0. PRE-CHECK: Stat decisions.md size and count inbox/ files. Record measurements.
1. DECISIONS ARCHIVE [HARD GATE]: If decisions.md >= 20480 bytes, archive entries older than 30 days NOW. If >= 51200 bytes, archive entries older than 7 days. Do not skip this step.
2. DECISION INBOX: Merge .squad/decisions/inbox/ → decisions.md, delete inbox files. Deduplicate.
3. ORCHESTRATION LOG: Write .squad/orchestration-log/{timestamp}-{agent}.md per agent. Use ISO 8601 UTC timestamp.
4. SESSION LOG: Write .squad/log/{timestamp}-{topic}.md. Brief. Use ISO 8601 UTC timestamp.
5. CROSS-AGENT: Append team updates to affected agents' history.md.
6. HISTORY SUMMARIZATION [HARD GATE]: If any history.md >= 15360 bytes (15KB), summarize now.
7. GIT COMMIT: git add .squad/ && commit (write msg to temp file, use -F). Skip if nothing staged.
8. HEALTH REPORT: Log decisions.md before/after size, inbox count processed, history files summarized.

Never speak to user. ⚠️ End with plain text summary after all tool calls.
```
Expand Down
8 changes: 4 additions & 4 deletions .squad/agents/scribe/charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@
- `.squad/decisions.md` — the shared decision log all agents read (canonical, merged)
- `.squad/decisions/inbox/` — decision drop-box (agents write here, I merge)
- Cross-agent context propagation — when one agent's decision affects another

## How I Work

**Worktree awareness:** Use `TEAM ROOT` from spawn prompt; fallback: `git rev-parse --show-toplevel`.
- Decision archival — **HARD GATE**: enforce two-tier ceiling on decisions.md before every merge:
- **Tier 1 (30-day):** If >20KB, archive entries older than 30 days
- **Tier 2 (7-day):** If still >50KB after Tier 1, archive entries older than 7 days
- Emit HEALTH REPORT to session log after archival runs

After substantial work:
1. Log session to `.squad/log/{timestamp}-{topic}.md` (who, what, outcomes)
Expand Down
4 changes: 4 additions & 0 deletions .squad/scribe-charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- `.squad/decisions.md` — the shared decision log all agents read (canonical, merged)
- `.squad/decisions/inbox/` — decision drop-box (agents write here, I merge)
- Cross-agent context propagation — when one agent's decision affects another
- Decision archival — **HARD GATE**: enforce two-tier ceiling on decisions.md before every merge:
- **Tier 1 (30-day):** If >20KB, archive entries older than 30 days
- **Tier 2 (7-day):** If still >50KB after Tier 1, archive entries older than 7 days
- Emit HEALTH REPORT to session log after archival runs

## How I Work

Expand Down
4 changes: 4 additions & 0 deletions .squad/templates/scribe-charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- `.squad/decisions.md` — the shared decision log all agents read (canonical, merged)
- `.squad/decisions/inbox/` — decision drop-box (agents write here, I merge)
- Cross-agent context propagation — when one agent's decision affects another
- Decision archival — **HARD GATE**: enforce two-tier ceiling on decisions.md before every merge:
- **Tier 1 (30-day):** If >20KB, archive entries older than 30 days
- **Tier 2 (7-day):** If still >50KB after Tier 1, archive entries older than 7 days
- Emit HEALTH REPORT to session log after archival runs

## How I Work

Expand Down
4 changes: 4 additions & 0 deletions packages/squad-cli/templates/scribe-charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- `.squad/decisions.md` — the shared decision log all agents read (canonical, merged)
- `.squad/decisions/inbox/` — decision drop-box (agents write here, I merge)
- Cross-agent context propagation — when one agent's decision affects another
- Decision archival — **HARD GATE**: enforce two-tier ceiling on decisions.md before every merge:
- **Tier 1 (30-day):** If >20KB, archive entries older than 30 days
- **Tier 2 (7-day):** If still >50KB after Tier 1, archive entries older than 7 days
- Emit HEALTH REPORT to session log after archival runs

## How I Work

Expand Down
4 changes: 4 additions & 0 deletions packages/squad-sdk/templates/scribe-charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- `.squad/decisions.md` — the shared decision log all agents read (canonical, merged)
- `.squad/decisions/inbox/` — decision drop-box (agents write here, I merge)
- Cross-agent context propagation — when one agent's decision affects another
- Decision archival — **HARD GATE**: enforce two-tier ceiling on decisions.md before every merge:
- **Tier 1 (30-day):** If >20KB, archive entries older than 30 days
- **Tier 2 (7-day):** If still >50KB after Tier 1, archive entries older than 7 days
- Emit HEALTH REPORT to session log after archival runs

## How I Work

Expand Down
4 changes: 4 additions & 0 deletions templates/scribe-charter.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,10 @@
- `.squad/decisions.md` — the shared decision log all agents read (canonical, merged)
- `.squad/decisions/inbox/` — decision drop-box (agents write here, I merge)
- Cross-agent context propagation — when one agent's decision affects another
- Decision archival — **HARD GATE**: enforce two-tier ceiling on decisions.md before every merge:
- **Tier 1 (30-day):** If >20KB, archive entries older than 30 days
- **Tier 2 (7-day):** If still >50KB after Tier 1, archive entries older than 7 days
- Emit HEALTH REPORT to session log after archival runs

## How I Work

Expand Down
88 changes: 88 additions & 0 deletions test/ci/scribe-template.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,88 @@
/**
* CI tests for the Scribe spawn template in squad.agent.md.
*
* Verifies that:
* - DECISIONS ARCHIVE runs BEFORE DECISION INBOX (archival first, while context is fresh)
* - HARD GATE label is present on the archive task (haiku cannot claim discretion)
* - Exact byte threshold 20480 is used (not the fuzzy ~20KB)
* - PRE-CHECK is task 0 (measure before acting)
* - HEALTH REPORT is the final task (observe after)
* - GIT COMMIT precedes HEALTH REPORT
*
* Canonical source: .squad-templates/squad.agent.md
*/

import { describe, it, expect } from 'vitest';
import { readFileSync } from 'node:fs';
import { resolve, dirname } from 'node:path';
import { fileURLToPath } from 'node:url';

const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = resolve(__dirname, '../..');

function readTemplate(): string {
return readFileSync(resolve(ROOT, '.squad-templates/squad.agent.md'), 'utf-8');
}

/**
* Extract the Scribe task block from the template.
* Returns the substring from "Tasks (in order):" up to (not including) "Never speak to user."
*/
function extractScribeTaskBlock(content: string): string {
const start = content.indexOf('Tasks (in order):');
const end = content.indexOf('Never speak to user.', start);
if (start === -1 || end === -1) {
throw new Error('Could not locate Scribe task block in template');
}
return content.slice(start, end);
}

describe('Scribe spawn template — HARD GATE enforcement', () => {
const content = readTemplate();
const taskBlock = extractScribeTaskBlock(content);

it('DECISIONS ARCHIVE appears before DECISION INBOX in the task list', () => {
const archiveIndex = taskBlock.indexOf('DECISIONS ARCHIVE');
const inboxIndex = taskBlock.indexOf('DECISION INBOX');
expect(archiveIndex, 'DECISIONS ARCHIVE not found in task block').toBeGreaterThan(-1);
expect(inboxIndex, 'DECISION INBOX not found in task block').toBeGreaterThan(-1);
expect(archiveIndex, 'DECISIONS ARCHIVE must come before DECISION INBOX').toBeLessThan(inboxIndex);
});

it('DECISIONS ARCHIVE task carries the [HARD GATE] label', () => {
const archiveLine = taskBlock
.split('\n')
.find(line => line.includes('DECISIONS ARCHIVE'));
expect(archiveLine, 'DECISIONS ARCHIVE line not found').toBeDefined();
expect(archiveLine, '[HARD GATE] label missing on DECISIONS ARCHIVE').toContain('[HARD GATE]');
});

it('exact byte threshold 20480 is used — not the fuzzy ~20KB', () => {
expect(taskBlock, '20480 byte threshold not found').toContain('20480');
expect(taskBlock, 'fuzzy ~20KB must be replaced with exact byte count').not.toMatch(/~20KB/);
});

it('PRE-CHECK is task 0 (the first numbered task)', () => {
const numberedLines = taskBlock
.split('\n')
.filter(l => l.trim().match(/^\d+\./));
expect(numberedLines.length, 'No numbered tasks found').toBeGreaterThan(0);
expect(numberedLines[0], 'First task must be PRE-CHECK').toContain('PRE-CHECK');
});

it('HEALTH REPORT is the final task in the list', () => {
const numberedLines = taskBlock
.split('\n')
.filter(l => l.trim().match(/^\d+\./));
expect(numberedLines.length, 'No numbered tasks found').toBeGreaterThan(0);
expect(numberedLines[numberedLines.length - 1], 'Last task must be HEALTH REPORT').toContain('HEALTH REPORT');
});

it('GIT COMMIT appears before HEALTH REPORT', () => {
const commitIndex = taskBlock.indexOf('GIT COMMIT');
const healthIndex = taskBlock.indexOf('HEALTH REPORT');
expect(commitIndex, 'GIT COMMIT not found').toBeGreaterThan(-1);
expect(healthIndex, 'HEALTH REPORT not found').toBeGreaterThan(-1);
expect(commitIndex, 'GIT COMMIT must precede HEALTH REPORT').toBeLessThan(healthIndex);
});
});
Loading