chore: merge squad update assets
Merge Squad update workflows/templates and Scribe issue-plan decision log.
Juan Manuel Servera committed
Jun 5, 2026 at 22:55 UTC
ac7575d052bd00365d021ea0f307a047ae457561
10 files changed
+624
.github/workflows/squad-ci.yml
new
+28
@@ -0,0 +1,28 @@
1
+name: Squad CI
2
+# python project — configure build/test commands below
3
+
4
+on:
5
+ pull_request:
6
+ branches: [dev, preview, main, insider]
7
+ types: [opened, synchronize, reopened]
8
+ push:
9
+ branches: [dev, insider]
10
+
11
+permissions:
12
+ contents: read
13
+
14
+jobs:
15
+ test:
16
+ runs-on: ubuntu-latest
17
+ steps:
18
+ - uses: actions/checkout@v4
19
+
20
+ - name: Build and test
21
+ run: |
22
+ # TODO: Add your python build/test commands here
23
+ # Go: go test ./...
24
+ # Python: pip install -r requirements.txt && pytest
25
+ # .NET: dotnet test
26
+ # Java (Maven): mvn test
27
+ # Java (Gradle): ./gradlew test
28
+ echo "No build commands configured — update squad-ci.yml"
.github/workflows/squad-docs.yml
new
+27
@@ -0,0 +1,27 @@
1
+name: Squad Docs — Build & Deploy
2
+# python project — configure documentation build commands below
3
+
4
+on:
5
+ workflow_dispatch:
6
+ push:
7
+ branches: [preview]
8
+ paths:
9
+ - 'docs/**'
10
+ - '.github/workflows/squad-docs.yml'
11
+
12
+permissions:
13
+ contents: read
14
+ pages: write
15
+ id-token: write
16
+
17
+jobs:
18
+ build:
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+
23
+ - name: Build docs
24
+ run: |
25
+ # TODO: Add your documentation build commands here
26
+ # This workflow is optional — remove or customize it for your project
27
+ echo "No docs build commands configured — update or remove squad-docs.yml"
.github/workflows/squad-insider-release.yml
new
+34
@@ -0,0 +1,34 @@
1
+name: Squad Insider Release
2
+# python project — configure build, test, and insider release commands below
3
+
4
+on:
5
+ push:
6
+ branches: [insider]
7
+
8
+permissions:
9
+ contents: write
10
+
11
+jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - name: Build and test
20
+ run: |
21
+ # TODO: Add your python build/test commands here
22
+ # Go: go test ./...
23
+ # Python: pip install -r requirements.txt && pytest
24
+ # .NET: dotnet test
25
+ # Java (Maven): mvn test
26
+ # Java (Gradle): ./gradlew test
27
+ echo "No build commands configured — update squad-insider-release.yml"
28
+
29
+ - name: Create insider release
30
+ env:
31
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32
+ run: |
33
+ # TODO: Add your insider/pre-release commands here
34
+ echo "No release commands configured — update squad-insider-release.yml"
.github/workflows/squad-label-enforce.yml
new
+181
@@ -0,0 +1,181 @@
1
+name: Squad Label Enforce
2
+
3
+on:
4
+ issues:
5
+ types: [labeled]
6
+
7
+permissions:
8
+ issues: write
9
+ contents: read
10
+
11
+jobs:
12
+ enforce:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Enforce mutual exclusivity
18
+ uses: actions/github-script@v7
19
+ with:
20
+ script: |
21
+ const issue = context.payload.issue;
22
+ const appliedLabel = context.payload.label.name;
23
+
24
+ // Namespaces with mutual exclusivity rules
25
+ const EXCLUSIVE_PREFIXES = ['go:', 'release:', 'type:', 'priority:'];
26
+
27
+ // Skip if not a managed namespace label
28
+ if (!EXCLUSIVE_PREFIXES.some(p => appliedLabel.startsWith(p))) {
29
+ core.info(`Label ${appliedLabel} is not in a managed namespace — skipping`);
30
+ return;
31
+ }
32
+
33
+ const allLabels = issue.labels.map(l => l.name);
34
+
35
+ // Handle go: namespace (mutual exclusivity)
36
+ if (appliedLabel.startsWith('go:')) {
37
+ const otherGoLabels = allLabels.filter(l =>
38
+ l.startsWith('go:') && l !== appliedLabel
39
+ );
40
+
41
+ if (otherGoLabels.length > 0) {
42
+ // Remove conflicting go: labels
43
+ for (const label of otherGoLabels) {
44
+ await github.rest.issues.removeLabel({
45
+ owner: context.repo.owner,
46
+ repo: context.repo.repo,
47
+ issue_number: issue.number,
48
+ name: label
49
+ });
50
+ core.info(`Removed conflicting label: ${label}`);
51
+ }
52
+
53
+ // Post update comment
54
+ await github.rest.issues.createComment({
55
+ owner: context.repo.owner,
56
+ repo: context.repo.repo,
57
+ issue_number: issue.number,
58
+ body: `🏷️ Triage verdict updated → \`${appliedLabel}\``
59
+ });
60
+ }
61
+
62
+ // Auto-apply release:backlog if go:yes and no release target
63
+ if (appliedLabel === 'go:yes') {
64
+ const hasReleaseLabel = allLabels.some(l => l.startsWith('release:'));
65
+ if (!hasReleaseLabel) {
66
+ await github.rest.issues.addLabels({
67
+ owner: context.repo.owner,
68
+ repo: context.repo.repo,
69
+ issue_number: issue.number,
70
+ labels: ['release:backlog']
71
+ });
72
+
73
+ await github.rest.issues.createComment({
74
+ owner: context.repo.owner,
75
+ repo: context.repo.repo,
76
+ issue_number: issue.number,
77
+ body: `📋 Marked as \`release:backlog\` — assign a release target when ready.`
78
+ });
79
+
80
+ core.info('Applied release:backlog for go:yes issue');
81
+ }
82
+ }
83
+
84
+ // Remove release: labels if go:no
85
+ if (appliedLabel === 'go:no') {
86
+ const releaseLabels = allLabels.filter(l => l.startsWith('release:'));
87
+ if (releaseLabels.length > 0) {
88
+ for (const label of releaseLabels) {
89
+ await github.rest.issues.removeLabel({
90
+ owner: context.repo.owner,
91
+ repo: context.repo.repo,
92
+ issue_number: issue.number,
93
+ name: label
94
+ });
95
+ core.info(`Removed release label from go:no issue: ${label}`);
96
+ }
97
+ }
98
+ }
99
+ }
100
+
101
+ // Handle release: namespace (mutual exclusivity)
102
+ if (appliedLabel.startsWith('release:')) {
103
+ const otherReleaseLabels = allLabels.filter(l =>
104
+ l.startsWith('release:') && l !== appliedLabel
105
+ );
106
+
107
+ if (otherReleaseLabels.length > 0) {
108
+ // Remove conflicting release: labels
109
+ for (const label of otherReleaseLabels) {
110
+ await github.rest.issues.removeLabel({
111
+ owner: context.repo.owner,
112
+ repo: context.repo.repo,
113
+ issue_number: issue.number,
114
+ name: label
115
+ });
116
+ core.info(`Removed conflicting label: ${label}`);
117
+ }
118
+
119
+ // Post update comment
120
+ await github.rest.issues.createComment({
121
+ owner: context.repo.owner,
122
+ repo: context.repo.repo,
123
+ issue_number: issue.number,
124
+ body: `🏷️ Release target updated → \`${appliedLabel}\``
125
+ });
126
+ }
127
+ }
128
+
129
+ // Handle type: namespace (mutual exclusivity)
130
+ if (appliedLabel.startsWith('type:')) {
131
+ const otherTypeLabels = allLabels.filter(l =>
132
+ l.startsWith('type:') && l !== appliedLabel
133
+ );
134
+
135
+ if (otherTypeLabels.length > 0) {
136
+ for (const label of otherTypeLabels) {
137
+ await github.rest.issues.removeLabel({
138
+ owner: context.repo.owner,
139
+ repo: context.repo.repo,
140
+ issue_number: issue.number,
141
+ name: label
142
+ });
143
+ core.info(`Removed conflicting label: ${label}`);
144
+ }
145
+
146
+ await github.rest.issues.createComment({
147
+ owner: context.repo.owner,
148
+ repo: context.repo.repo,
149
+ issue_number: issue.number,
150
+ body: `🏷️ Issue type updated → \`${appliedLabel}\``
151
+ });
152
+ }
153
+ }
154
+
155
+ // Handle priority: namespace (mutual exclusivity)
156
+ if (appliedLabel.startsWith('priority:')) {
157
+ const otherPriorityLabels = allLabels.filter(l =>
158
+ l.startsWith('priority:') && l !== appliedLabel
159
+ );
160
+
161
+ if (otherPriorityLabels.length > 0) {
162
+ for (const label of otherPriorityLabels) {
163
+ await github.rest.issues.removeLabel({
164
+ owner: context.repo.owner,
165
+ repo: context.repo.repo,
166
+ issue_number: issue.number,
167
+ name: label
168
+ });
169
+ core.info(`Removed conflicting label: ${label}`);
170
+ }
171
+
172
+ await github.rest.issues.createComment({
173
+ owner: context.repo.owner,
174
+ repo: context.repo.repo,
175
+ issue_number: issue.number,
176
+ body: `🏷️ Priority updated → \`${appliedLabel}\``
177
+ });
178
+ }
179
+ }
180
+
181
+ core.info(`Label enforcement complete for ${appliedLabel}`);
.github/workflows/squad-preview.yml
new
+30
@@ -0,0 +1,30 @@
1
+name: Squad Preview Validation
2
+# python project — configure build, test, and validation commands below
3
+
4
+on:
5
+ push:
6
+ branches: [preview]
7
+
8
+permissions:
9
+ contents: read
10
+
11
+jobs:
12
+ validate:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+
17
+ - name: Build and test
18
+ run: |
19
+ # TODO: Add your python build/test commands here
20
+ # Go: go test ./...
21
+ # Python: pip install -r requirements.txt && pytest
22
+ # .NET: dotnet test
23
+ # Java (Maven): mvn test
24
+ # Java (Gradle): ./gradlew test
25
+ echo "No build commands configured — update squad-preview.yml"
26
+
27
+ - name: Validate
28
+ run: |
29
+ # TODO: Add pre-release validation commands here
30
+ echo "No validation commands configured — update squad-preview.yml"
.github/workflows/squad-promote.yml
new
+120
@@ -0,0 +1,120 @@
1
+name: Squad Promote
2
+
3
+on:
4
+ workflow_dispatch:
5
+ inputs:
6
+ dry_run:
7
+ description: 'Dry run — show what would happen without pushing'
8
+ required: false
9
+ default: 'false'
10
+ type: choice
11
+ options: ['false', 'true']
12
+
13
+permissions:
14
+ contents: write
15
+
16
+jobs:
17
+ dev-to-preview:
18
+ name: Promote dev → preview
19
+ runs-on: ubuntu-latest
20
+ steps:
21
+ - uses: actions/checkout@v4
22
+ with:
23
+ fetch-depth: 0
24
+ token: ${{ secrets.GITHUB_TOKEN }}
25
+
26
+ - name: Configure git
27
+ run: |
28
+ git config user.name "github-actions[bot]"
29
+ git config user.email "github-actions[bot]@users.noreply.github.com"
30
+
31
+ - name: Fetch all branches
32
+ run: git fetch --all
33
+
34
+ - name: Show current state (dry run info)
35
+ run: |
36
+ echo "=== dev HEAD ===" && git log origin/dev -1 --oneline
37
+ echo "=== preview HEAD ===" && git log origin/preview -1 --oneline
38
+ echo "=== Files that would be stripped ==="
39
+ git diff origin/preview..origin/dev --name-only | grep -E "^(\.(ai-team|squad|ai-team-templates)|team-docs/|docs/proposals/)" || echo "(none)"
40
+
41
+ - name: Merge dev → preview (strip forbidden paths)
42
+ if: ${{ inputs.dry_run == 'false' }}
43
+ run: |
44
+ git checkout preview
45
+ git merge origin/dev --no-commit --no-ff -X theirs || true
46
+
47
+ # Strip forbidden paths from merge commit
48
+ git rm -rf --cached --ignore-unmatch \
49
+ .ai-team/ \
50
+ .squad/ \
51
+ .ai-team-templates/ \
52
+ team-docs/ \
53
+ "docs/proposals/" || true
54
+
55
+ # Commit if there are staged changes
56
+ if ! git diff --cached --quiet; then
57
+ git commit -m "chore: promote dev → preview (v$(node -e "console.log(require('./package.json').version)"))"
58
+ git push origin preview
59
+ echo "✅ Pushed preview branch"
60
+ else
61
+ echo "ℹ️ Nothing to commit — preview is already up to date"
62
+ fi
63
+
64
+ - name: Dry run complete
65
+ if: ${{ inputs.dry_run == 'true' }}
66
+ run: echo "🔍 Dry run complete — no changes pushed."
67
+
68
+ preview-to-main:
69
+ name: Promote preview → main (release)
70
+ needs: dev-to-preview
71
+ runs-on: ubuntu-latest
72
+ steps:
73
+ - uses: actions/checkout@v4
74
+ with:
75
+ fetch-depth: 0
76
+ token: ${{ secrets.GITHUB_TOKEN }}
77
+
78
+ - name: Configure git
79
+ run: |
80
+ git config user.name "github-actions[bot]"
81
+ git config user.email "github-actions[bot]@users.noreply.github.com"
82
+
83
+ - name: Fetch all branches
84
+ run: git fetch --all
85
+
86
+ - name: Show current state
87
+ run: |
88
+ echo "=== preview HEAD ===" && git log origin/preview -1 --oneline
89
+ echo "=== main HEAD ===" && git log origin/main -1 --oneline
90
+ echo "=== Version ===" && node -e "console.log('v' + require('./package.json').version)"
91
+
92
+ - name: Validate preview is release-ready
93
+ run: |
94
+ git checkout preview
95
+ VERSION=$(node -e "console.log(require('./package.json').version)")
96
+ if ! grep -q "## \[$VERSION\]" CHANGELOG.md 2>/dev/null; then
97
+ echo "::error::Version $VERSION not found in CHANGELOG.md — update before releasing"
98
+ exit 1
99
+ fi
100
+ echo "✅ Version $VERSION has CHANGELOG entry"
101
+
102
+ # Verify no forbidden files on preview
103
+ FORBIDDEN=$(git ls-files | grep -E "^(\.(ai-team|squad|ai-team-templates)/|team-docs/|docs/proposals/)" || true)
104
+ if [ -n "$FORBIDDEN" ]; then
105
+ echo "::error::Forbidden files found on preview: $FORBIDDEN"
106
+ exit 1
107
+ fi
108
+ echo "✅ No forbidden files on preview"
109
+
110
+ - name: Merge preview → main
111
+ if: ${{ inputs.dry_run == 'false' }}
112
+ run: |
113
+ git checkout main
114
+ git merge origin/preview --no-ff -m "chore: promote preview → main (v$(node -e "console.log(require('./package.json').version)"))"
115
+ git push origin main
116
+ echo "✅ Pushed main — squad-release.yml will tag and publish the release"
117
+
118
+ - name: Dry run complete
119
+ if: ${{ inputs.dry_run == 'true' }}
120
+ run: echo "🔍 Dry run complete — no changes pushed."
.github/workflows/squad-release.yml
new
+34
@@ -0,0 +1,34 @@
1
+name: Squad Release
2
+# python project — configure build, test, and release commands below
3
+
4
+on:
5
+ push:
6
+ branches: [main]
7
+
8
+permissions:
9
+ contents: write
10
+
11
+jobs:
12
+ release:
13
+ runs-on: ubuntu-latest
14
+ steps:
15
+ - uses: actions/checkout@v4
16
+ with:
17
+ fetch-depth: 0
18
+
19
+ - name: Build and test
20
+ run: |
21
+ # TODO: Add your python build/test commands here
22
+ # Go: go test ./...
23
+ # Python: pip install -r requirements.txt && pytest
24
+ # .NET: dotnet test
25
+ # Java (Maven): mvn test
26
+ # Java (Gradle): ./gradlew test
27
+ echo "No build commands configured — update squad-release.yml"
28
+
29
+ - name: Create release
30
+ env:
31
+ GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
32
+ run: |
33
+ # TODO: Add your release commands here (e.g., git tag, gh release create)
34
+ echo "No release commands configured — update squad-release.yml"
.squad/decisions.md
+41
@@ -736,3 +736,44 @@ Do not open a separate crawler/RSS matrix issue from this run. The existing PRD/
736
**Outcome:** decisions.md grew from 45948 → 91562 bytes. Inbox purged. No duplicates found in merge. Added 5 decision dividers. Content addresses crawl matrix topology, analysis map/reduce experiment design, QA gates/tests, run diagnostics, and fallback strategy.
737
738
**No archiving trigger:** decisions.md is still within typical document lifecycle size; existing PRD scope is fresh and actionable.
739
+
740
+---
741
+
742
+## Leela: Analysis rerun safety issue plan
743
+
744
+Created: 2026-06-05T20:46:00.582+00:00
745
+
746
+### Parent epic
747
+
748
+- #248 — [Protect published weekly analysis from unsafe reruns](https://github.com/jmservera/SquadScope/issues/248)
749
+
750
+### Immediate objective
751
+
752
+Stop failed, degraded, low-quality, or no-AI analysis reruns from overwriting a good published weekly article. This protection should land before map/reduce implementation changes can affect publication.
753
+
754
+### Child issues hierarchy
755
+
756
+**P0 Safety Layer (11 issues):**
757
+- #249 — Add candidate staging and publish eligibility manifest for analysis outputs | Bender | type:feature, priority:p0
758
+- #250 — Preserve existing good weekly analysis on failed/degraded reruns | Bender | type:feature, priority:p0
759
+- #251 — Block no-AI fallback from replacing AI-authored weekly summaries by default | Farnsworth | type:feature, priority:p0, rai
760
+- #252 — Add explicit safe rerun modes and restore workflow controls | Leela | type:feature, priority:p0
761
+- #253 — Add immutable backups and publish-branch concurrency safeguards | Bender | type:feature, priority:p0
762
+- #254 — Make weekly promotion atomic across analyzed/content/deploy/notify | Bender | type:feature, priority:p0
763
+- #255 — Strengthen analysis publish gate beyond structural validation | Farnsworth | type:feature, priority:p0, rai
764
+- #257 — Add overwrite-protection and rerun idempotency regression tests | Fry | type:feature, priority:p0
765
+
766
+**P1 Quality/Run Readiness (2 issues):**
767
+- #256 — Add preflight compaction and fallback policy for next analysis run | Farnsworth | type:feature, priority:p1
768
+- #259 — Document safe rerun, force-replace, and restore operations | Leela | type:docs, priority:p1
769
+
770
+**P2 Future Analysis Architecture (1 issue):**
771
+- #258 — Add map/reduce dry-run with claim-ledger contracts and QA comparison gates | Farnsworth with Fry QA support | type:feature, priority:p2, rai
772
+
773
+### Summary
774
+
775
+Safety-first protection layer for analysis reruns across staging/publish workflow. Prevents silent overwrite of good weekly articles on transient failures, low-quality output, or no-AI fallback misuse. Prioritizes atomic promotion, eligibility gates, and immutable backups before rolling out map/reduce.
776
+
777
+### Notes
778
+
779
+GitHub issue hierarchy represented via parent #248 with linked child issues and inline comments. All issues labeled `squad` with per-owner tracking.
.squad/templates/fact-checker-charter.md
new
+83
@@ -0,0 +1,83 @@
1
+# Fact Checker
2
+
3
+> Trust, but verify. Every claim gets a source check.
4
+
5
+## Identity
6
+
7
+- **Name:** Fact Checker
8
+- **Role:** Devil's Advocate & Verification Agent
9
+- **Style:** Rigorous but constructive. Flags issues clearly without being abrasive.
10
+- **Casting:** Gets a universe name like any other agent (not exempt like Scribe/Ralph).
11
+
12
+## What I Do
13
+
14
+Validate claims, detect hallucinations, and run counter-hypotheses on team output before it ships.
15
+
16
+## Verification Methodology
17
+
18
+For every claim or assertion I review:
19
+
20
+1. **Source Check:** What evidence supports this? Can I verify it?
21
+2. **Counter-Hypothesis:** What would disprove this? Is there an alternative explanation?
22
+3. **Existence Check:** Do the URLs, package names, API endpoints, file paths, and version numbers actually exist?
23
+4. **Consistency Check:** Does this contradict anything in `.squad/decisions.md` or prior team output?
24
+
25
+## Confidence Ratings
26
+
27
+Every verified item gets one of:
28
+
29
+| Rating | Meaning |
30
+|--------|---------|
31
+| ✅ Verified | Confirmed via source, test, or direct observation |
32
+| ⚠️ Unverified | Plausible but could not confirm — needs human review |
33
+| ❌ Contradicted | Found evidence that contradicts the claim |
34
+| 🔍 Needs Investigation | Requires deeper analysis beyond current scope |
35
+
36
+## When I'm Triggered
37
+
38
+- **Auto-trigger (via routing):** Tasks tagged with `review`, `verify`, `fact-check`, `audit`
39
+- **Pre-publish gate:** Before any artifact is delivered to the user, if configured
40
+- **Manual:** User says "fact-check this", "verify these claims", "double-check"
41
+- **Post-research:** After any agent produces research output or external references
42
+
43
+## How I Work
44
+
45
+1. **Read the artifact** — understand what's being claimed
46
+2. **Extract claims** — list every factual assertion (package versions, API behavior, file existence, etc.)
47
+3. **Verify each claim** — use available tools (grep, glob, web search, gh CLI) to check
48
+4. **Run counter-hypotheses** — for key assumptions, ask "what if this is wrong?"
49
+5. **Produce a verification report:**
50
+
51
+```markdown
52
+## Verification Report — {artifact name}
53
+
54
+### Claims Verified
55
+- ✅ {claim} — confirmed via {source}
56
+- ⚠️ {claim} — could not verify, {reason}
57
+- ❌ {claim} — contradicted by {evidence}
58
+
59
+### Counter-Hypotheses
60
+- {assumption} → Alternative: {counter}
61
+
62
+### Recommendation
63
+{proceed / revise / block with reasons}
64
+```
65
+
66
+6. **Write decision** if I found issues: `.squad/decisions/inbox/fact-checker-{slug}.md`
67
+
68
+## Boundaries
69
+
70
+**I handle:** Verification, fact-checking, counter-hypotheses, hallucination detection.
71
+
72
+**I don't handle:** Implementation, design, testing, or docs. I review, not create.
73
+
74
+**I am not a blocker by default.** My verification report is advisory unless the coordinator or a reviewer escalates it to a gate.
75
+
76
+## Project Context
77
+
78
+**Project:** {project_name}
79
+{project_description}
80
+
81
+## Learnings
82
+
83
+Initial setup complete. Ready for verification work.
.squad/templates/loop.md
new
+46
@@ -0,0 +1,46 @@
1
+---
2
+configured: false
3
+interval: 10
4
+timeout: 30
5
+description: "My squad work loop"
6
+---
7
+
8
+# Squad Work Loop
9
+
10
+> ⚠️ Set `configured: true` in the frontmatter above to activate this loop.
11
+> Run with: `squad loop`
12
+
13
+## What to do each cycle
14
+
15
+Describe what your squad should do every time the loop wakes up. Be specific —
16
+the more context you give, the better your squad performs.
17
+
18
+Examples:
19
+- Check for new messages in a Teams channel and summarize action items
20
+- Review recent pull requests and flag anything needing attention
21
+- Run a health check on staging and report anomalies
22
+- Scan the inbox for anything that needs a response today
23
+
24
+<!-- Replace this section with your actual loop instructions. -->
25
+
26
+## Monitoring (optional)
27
+
28
+If you want your squad to watch external channels, enable monitor capabilities:
29
+
30
+```bash
31
+squad loop --monitor-email --monitor-teams
32
+```
33
+
34
+## Personality (optional)
35
+
36
+If your squad has a specific voice or style, describe it here so each cycle
37
+stays consistent.
38
+
39
+Example: "Be concise. Use bullet points. Flag blockers clearly."
40
+
41
+## Tips
42
+
43
+- **Be specific.** Vague prompts produce vague results.
44
+- **Set boundaries.** Tell the squad what NOT to do (e.g., "Don't send messages to anyone but me").
45
+- **Start small.** Begin with one task per cycle, then expand.
46
+- **Use frontmatter.** `interval` controls how often the loop runs. `timeout` caps each cycle.