8 session blueprints covering all 27 steps across 3 waves: - Session 1: Foundation (rename + commands, Steps 1-5) - Session 2: Skills and templates (Steps 6-7) - Session 3: OpenClaw patterns (memory/heartbeat/proactive/cron, Steps 9-12) - Session 4: Paperclip patterns (context/goals/budget/governance/org-chart, Steps 14-18) - Session 5: Self-learning (feedback/optimization, Steps 20-21) - Session 6: Integration (Docker/transfer/5 more domains, Steps 22-24) - Session 7: Skill updates (memory/autonomy/orchestration/governance/MCP refs, Steps 13,19,25) - Session 8: Finalization (build command integration + v1.0, Steps 8,26,27) Also updates plan assumptions table with verified findings. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
22 KiB
Session 4: Paperclip Orchestration Patterns
Steps 14, 15, 16, 17, 18 | Wave 1 | Depends on: none
Dependencies
Entry condition: none (creates new template directories only, plus 2 new files in heartbeat/)
Scope Fence
Touch:
scripts/templates/heartbeat/context-packet.md(new)scripts/templates/heartbeat/wake-prompt.md(new)scripts/templates/goals/GOALS.md(new)scripts/templates/goals/goal-tracker.sh(new)scripts/templates/goals/README.md(new)scripts/templates/budget/budget-hook.sh(new)scripts/templates/budget/BUDGET.md(new)scripts/templates/budget/budget-report.sh(new)scripts/templates/budget/README.md(new)scripts/templates/governance/GOVERNANCE.md(new)scripts/templates/governance/approval-gate.sh(new)scripts/templates/governance/README.md(new)scripts/templates/org-chart/ORG-CHART.md(new)scripts/templates/org-chart/org-manager.sh(new)scripts/templates/org-chart/README.md(new)
Never touch:
commands/agents/skills/scripts/templates/heartbeat/HEARTBEAT.md(Session 3)scripts/templates/heartbeat/heartbeat-runner.sh(Session 3)scripts/templates/heartbeat/README.md(Session 3)scripts/templates/memory/scripts/templates/proactive/scripts/templates/cron/.claude-plugin/,CLAUDE.md,README.md
Step 14: Create heartbeat context injection templates
Files to create
scripts/templates/heartbeat/context-packet.md — Paperclip's "Memento Man" pattern:
# Context Packet: {{AGENT_NAME}}
Generated: {{TIMESTAMP}}
## Identity
{{AGENT_IDENTITY}}
## Current Goals
{{ACTIVE_GOALS}}
## Memory State
{{MEMORY_SUMMARY}}
## Task Queue
{{PENDING_TASKS}}
## Recent Events (last 24h)
{{RECENT_EVENTS}}
## Wake Reason
{{WAKE_REASON}}
## Budget Status
Spent: {{BUDGET_SPENT}} / {{BUDGET_LIMIT}} ({{BUDGET_PERCENT}}%)
{{BUDGET_WARNING}}
scripts/templates/heartbeat/wake-prompt.md — Prompt template for each heartbeat wakeup:
You are {{AGENT_NAME}}. You are waking up for a scheduled heartbeat.
Read the context packet below carefully. It contains everything you
need to know about your current state and pending work.
{{CONTEXT_PACKET}}
Your task for this beat:
{{WAKE_REASON}}
Rules:
- Do NOT infer tasks from prior conversations
- Only work on what is in the context packet and wake reason
- If nothing needs attention, respond with HEARTBEAT_OK
- Update SESSION-STATE.md before finishing
Verify
ls /Users/ktg/repos/agent-builder/scripts/templates/heartbeat/ | wc -l
Expected: 5 (3 from Session 3 + 2 from this step)
On failure: revert
Checkpoint
git commit -m "feat(templates): add context injection templates (Paperclip heartbeat pattern)"
Step 15: Create goal hierarchy templates
Files to create
scripts/templates/goals/GOALS.md:
# Goals: {{PROJECT_NAME}}
## Company Goals
- [G1] {{COMPANY_GOAL_1}}
- [G2] {{COMPANY_GOAL_2}}
## Project Goals
- [G1.1] {{PROJECT_GOAL_1}} (parent: G1)
- [G1.2] {{PROJECT_GOAL_2}} (parent: G1)
- [G2.1] {{PROJECT_GOAL_3}} (parent: G2)
## Task Goals
- [G1.1.1] {{TASK_GOAL_1}} (parent: G1.1, owner: {{AGENT_NAME}}, status: active)
- [G1.1.2] {{TASK_GOAL_2}} (parent: G1.1, owner: {{AGENT_NAME}}, status: pending)
## Notes
Goal IDs use hierarchical dot notation. Each goal has:
- ID: unique identifier (e.g., G1.1.1)
- Description: what the goal is
- Parent: which goal this supports (simple parent reference, not recursive)
- Owner: which agent is responsible (task goals only)
- Status: active | pending | complete | blocked
scripts/templates/goals/goal-tracker.sh:
#!/bin/bash
# Goal tracker: parse and manage GOALS.md
# Bash 3.2 compatible. Uses python3 for parsing.
#
# Usage:
# ./goal-tracker.sh # Show goal summary
# ./goal-tracker.sh complete G1.1.1 # Mark goal as complete
# ./goal-tracker.sh status # Show status counts
# ./goal-tracker.sh context # Generate context for heartbeat injection
#
# Placeholders:
# {{WORKING_DIR}} - absolute path to project directory
WORKING_DIR="{{WORKING_DIR}}"
GOALS_FILE="$WORKING_DIR/GOALS.md"
ACTION="${1:-summary}"
GOAL_ID="${2:-}"
if [ ! -f "$GOALS_FILE" ]; then
echo "Error: $GOALS_FILE not found"
exit 1
fi
case "$ACTION" in
summary|status)
python3 << PYEOF
import re
goals = []
with open("$GOALS_FILE") as f:
for line in f:
m = re.match(r'-\s*\[(\S+)\]\s+(.+)', line.strip())
if m:
gid = m.group(1)
rest = m.group(2)
status_m = re.search(r'status:\s*(\w+)', rest)
parent_m = re.search(r'parent:\s*(\S+)', rest)
owner_m = re.search(r'owner:\s*(\S+)', rest)
status = status_m.group(1) if status_m else 'active'
parent = parent_m.group(1).rstrip(',)') if parent_m else None
owner = owner_m.group(1).rstrip(',)') if owner_m else None
desc = re.sub(r'\(.*\)', '', rest).strip()
goals.append({'id': gid, 'desc': desc, 'status': status, 'parent': parent, 'owner': owner})
# Status counts
counts = {}
for g in goals:
counts[g['status']] = counts.get(g['status'], 0) + 1
print("Goal Status Summary")
print("=" * 40)
for status, count in sorted(counts.items()):
print(f" {status}: {count}")
print(f" Total: {len(goals)}")
# Check for orphans
all_ids = set(g['id'] for g in goals)
orphans = [g for g in goals if g['parent'] and g['parent'] not in all_ids]
if orphans:
print(f"\nOrphaned goals (parent not found):")
for g in orphans:
print(f" [{g['id']}] parent: {g['parent']}")
# Goals without owners at task level
unowned = [g for g in goals if '.' in g['id'] and g['id'].count('.') >= 2 and not g['owner']]
if unowned:
print(f"\nTask goals without owners:")
for g in unowned:
print(f" [{g['id']}] {g['desc']}")
PYEOF
;;
complete)
if [ -z "$GOAL_ID" ]; then
echo "Usage: $0 complete <goal-id>"
exit 1
fi
python3 -c "
import re
goal_id = '$GOAL_ID'
with open('$GOALS_FILE') as f:
content = f.read()
# Replace status for the specific goal
pattern = r'(\[' + re.escape(goal_id) + r'\][^)]*status:\s*)\w+'
if re.search(pattern, content):
content = re.sub(pattern, r'\1complete', content)
with open('$GOALS_FILE', 'w') as f:
f.write(content)
print(f'Goal {goal_id} marked as complete')
else:
print(f'Goal {goal_id} not found or has no status field')
"
;;
context)
# Generate a goal summary for heartbeat context injection
python3 << PYEOF
import re
goals = []
with open("$GOALS_FILE") as f:
for line in f:
m = re.match(r'-\s*\[(\S+)\]\s+(.+)', line.strip())
if m:
gid = m.group(1)
rest = m.group(2)
status_m = re.search(r'status:\s*(\w+)', rest)
status = status_m.group(1) if status_m else 'active'
desc = re.sub(r'\(.*\)', '', rest).strip()
goals.append({'id': gid, 'desc': desc, 'status': status})
active = [g for g in goals if g['status'] == 'active']
if active:
print("Active goals:")
for g in active:
print(f" [{g['id']}] {g['desc']}")
else:
print("No active goals.")
PYEOF
;;
*)
echo "Usage: $0 [summary|complete <id>|status|context]"
exit 1
;;
esac
scripts/templates/goals/README.md:
# Goal Hierarchy
File-based goal hierarchy inspired by Paperclip's goal system.
## Design decisions
- **Simple parent_id, not recursive**: Each goal references its parent by ID.
No recursive traversal at runtime — matching Paperclip's actual implementation
(not their aspirational docs which describe "full ancestry").
- **Dot notation for hierarchy**: G1 → G1.1 → G1.1.1 makes the hierarchy visible
in the ID itself.
- **File-based, not database**: Human-editable, version-controlled, no dependencies.
## Goal levels
| Level | ID pattern | Example | Description |
|-------|-----------|---------|-------------|
| Company | G1, G2 | G1 | Top-level organizational goals |
| Project | G1.1, G1.2 | G1.1 | Goals that support a company goal |
| Task | G1.1.1 | G1.1.1 | Specific tasks assigned to agents |
## Usage
```bash
# View goal summary
./goal-tracker.sh
# Mark a task as complete
./goal-tracker.sh complete G1.1.1
# Generate context for heartbeat injection
./goal-tracker.sh context
Integration with heartbeat
The context command produces a summary suitable for injection into
the heartbeat context packet (see scripts/templates/heartbeat/context-packet.md).
The heartbeat runner can call ./goal-tracker.sh context and inject
the output as {{ACTIVE_GOALS}}.
### Verify
```bash
bash -n /Users/ktg/repos/agent-builder/scripts/templates/goals/goal-tracker.sh && echo "VALID"
Expected: VALID
On failure: retry — fix bash syntax, then revert
Checkpoint
git commit -m "feat(templates): add goal hierarchy templates (Paperclip pattern)"
Step 16: Create budget tracking templates
Files to create
scripts/templates/budget/BUDGET.md:
# Budget Policy: {{PROJECT_NAME}}
## Company Budget
- window: {{BUDGET_WINDOW}}
- limit: {{BUDGET_LIMIT_CENTS}} cents
- warn_percent: 80
- hard_stop: true
## Agent Budgets
- {{AGENT_NAME}}: {{AGENT_BUDGET_CENTS}} cents/{{BUDGET_WINDOW}}
## Notification
- on_warn: log
- on_hard_stop: pause
## Notes
Budget enforcement is POST-HOC (checked after each run, not before).
This matches Paperclip's proven approach: check SUM(cost) after run,
pause if exceeded. No pre-run reservation needed.
Cost estimation uses token counts × published pricing. For accurate
cost data, organizations can use the Admin API:
`/v1/organizations/cost_report` (requires Admin API key: sk-ant-admin...).
For headless runs, use `claude -p --max-budget-usd N` as a per-run cap.
scripts/templates/budget/budget-hook.sh:
#!/bin/bash
# PostToolUse hook: Log cost events and enforce budget.
# Bash 3.2 compatible. Uses python3 for JSON parsing.
#
# Follows Paperclip's post-hoc enforcement pattern:
# 1. Log cost event after each tool call
# 2. Check cumulative cost against budget policy
# 3. Warn at soft threshold, pause at hard threshold
#
# Placeholders:
# {{WORKING_DIR}} - absolute path to project directory
WORKING_DIR="{{WORKING_DIR}}"
BUDGET_DIR="$WORKING_DIR/budget"
COST_LOG="$BUDGET_DIR/cost-events.jsonl"
BUDGET_FILE="$WORKING_DIR/BUDGET.md"
PAUSED_FLAG="$BUDGET_DIR/PAUSED"
mkdir -p "$BUDGET_DIR"
# Read hook input
INPUT=$(cat)
TOOL_NAME=$(echo "$INPUT" | python3 -c "import sys,json; print(json.load(sys.stdin).get('tool_name',''))" 2>/dev/null)
# Log cost event
python3 << PYEOF
import json, sys, time, os
try:
data = json.loads('''$INPUT''')
except:
sys.exit(0)
tool_name = data.get('tool_name', '')
# Estimate cost from token counts if available in tool result
# This is a rough estimate; actual costs come from the Admin API
event = {
'timestamp': time.strftime('%Y-%m-%dT%H:%M:%SZ', time.gmtime()),
'tool_name': tool_name,
'agent': os.environ.get('AGENT_NAME', 'unknown'),
'estimated_tokens': 0
}
cost_log = "$COST_LOG"
with open(cost_log, 'a') as f:
f.write(json.dumps(event) + '\n')
PYEOF
# Check budget if BUDGET.md exists
if [ -f "$BUDGET_FILE" ] && [ -f "$COST_LOG" ]; then
BUDGET_CHECK=$(python3 << 'PYEOF'
import re, json, os
budget_file = os.environ.get('BUDGET_FILE', '')
cost_log = os.environ.get('COST_LOG', '')
paused_flag = os.environ.get('PAUSED_FLAG', '')
if not budget_file or not cost_log:
print("ok")
exit(0)
# Parse budget
try:
content = open(budget_file).read()
limit_m = re.search(r'limit:\s*(\d+)\s*cents', content)
warn_m = re.search(r'warn_percent:\s*(\d+)', content)
hard_m = re.search(r'hard_stop:\s*(\w+)', content)
if not limit_m:
print("ok")
exit(0)
limit = int(limit_m.group(1))
warn_pct = int(warn_m.group(1)) if warn_m else 80
hard_stop = hard_m.group(1).lower() == 'true' if hard_m else True
except:
print("ok")
exit(0)
# Sum cost events (count events as rough proxy — actual cost tracking
# requires Admin API or token counting from responses)
try:
event_count = sum(1 for _ in open(cost_log))
except:
event_count = 0
# Rough estimate: each event ~ 1 cent (placeholder — customize per model)
estimated_cents = event_count
pct = (estimated_cents / limit * 100) if limit > 0 else 0
if pct >= 100 and hard_stop:
open(paused_flag, 'w').write(f'Budget exceeded: {estimated_cents}/{limit} cents')
print("hard_stop")
elif pct >= warn_pct:
print("warn")
else:
print("ok")
PYEOF
)
BUDGET_FILE="$BUDGET_FILE" COST_LOG="$COST_LOG" PAUSED_FLAG="$PAUSED_FLAG" \
BUDGET_RESULT=$(BUDGET_FILE="$BUDGET_FILE" COST_LOG="$COST_LOG" PAUSED_FLAG="$PAUSED_FLAG" python3 -c "
import re, json, os
budget_file = '$BUDGET_FILE'
cost_log = '$COST_LOG'
paused_flag = '$PAUSED_FLAG'
try:
content = open(budget_file).read()
limit_m = re.search(r'limit:\s*(\d+)\s*cents', content)
if not limit_m: print('ok'); exit(0)
limit = int(limit_m.group(1))
warn_m = re.search(r'warn_percent:\s*(\d+)', content)
warn_pct = int(warn_m.group(1)) if warn_m else 80
hard_m = re.search(r'hard_stop:\s*(\w+)', content)
hard_stop = hard_m.group(1).lower() == 'true' if hard_m else True
event_count = sum(1 for _ in open(cost_log))
estimated_cents = event_count
pct = (estimated_cents / limit * 100) if limit > 0 else 0
if pct >= 100 and hard_stop:
open(paused_flag, 'w').write(f'Budget exceeded: {estimated_cents}/{limit} cents')
print('hard_stop')
elif pct >= warn_pct:
print('warn')
else:
print('ok')
except Exception as e:
print('ok')
" 2>/dev/null)
if [ "$BUDGET_RESULT" = "hard_stop" ]; then
echo "BUDGET EXCEEDED — agent paused. Check $PAUSED_FLAG" >&2
elif [ "$BUDGET_RESULT" = "warn" ]; then
echo "BUDGET WARNING — approaching limit" >&2
fi
fi
# Check if agent is paused
if [ -f "$PAUSED_FLAG" ]; then
echo '{"decision": "block", "reason": "Agent paused: budget exceeded. Remove '"$PAUSED_FLAG"' to resume."}'
exit 2
fi
exit 0
scripts/templates/budget/budget-report.sh:
#!/bin/bash
# Budget report: summarize cost events and compare against policy.
# Bash 3.2 compatible. Uses python3 for aggregation.
#
# Usage: ./budget-report.sh
#
# Placeholders:
# {{WORKING_DIR}} - absolute path to project directory
WORKING_DIR="{{WORKING_DIR}}"
COST_LOG="$WORKING_DIR/budget/cost-events.jsonl"
BUDGET_FILE="$WORKING_DIR/BUDGET.md"
PAUSED_FLAG="$WORKING_DIR/budget/PAUSED"
if [ ! -f "$COST_LOG" ]; then
echo "No cost events recorded yet."
exit 0
fi
python3 << PYEOF
import json, re, os
from collections import defaultdict
cost_log = "$COST_LOG"
budget_file = "$BUDGET_FILE"
paused_flag = "$PAUSED_FLAG"
# Read events
events = []
with open(cost_log) as f:
for line in f:
line = line.strip()
if line:
try:
events.append(json.loads(line))
except:
pass
# Aggregate
by_agent = defaultdict(int)
by_day = defaultdict(int)
by_tool = defaultdict(int)
for e in events:
agent = e.get('agent', 'unknown')
day = e.get('timestamp', '')[:10]
tool = e.get('tool_name', 'unknown')
by_agent[agent] += 1
by_day[day] += 1
by_tool[tool] += 1
print("BUDGET REPORT")
print("=" * 50)
print(f"Total events: {len(events)}")
print()
# Per-agent breakdown
print("By Agent:")
for agent, count in sorted(by_agent.items(), key=lambda x: -x[1]):
print(f" {agent}: {count} events")
print()
# Per-day breakdown (last 7 days)
print("By Day (last 7):")
for day, count in sorted(by_day.items())[-7:]:
print(f" {day}: {count} events")
print()
# Budget comparison
if os.path.exists(budget_file):
content = open(budget_file).read()
limit_m = re.search(r'limit:\s*(\d+)\s*cents', content)
if limit_m:
limit = int(limit_m.group(1))
est_cents = len(events) # rough proxy
pct = (est_cents / limit * 100) if limit > 0 else 0
print(f"Budget: ~{est_cents}/{limit} cents ({pct:.0f}%)")
# Paused status
if os.path.exists(paused_flag):
print(f"\n!! AGENT PAUSED: {open(paused_flag).read().strip()}")
print(f" Remove {paused_flag} to resume")
PYEOF
scripts/templates/budget/README.md:
# Budget Tracking
Post-hoc budget enforcement inspired by Paperclip's budget system.
## How it works
1. `budget-hook.sh` runs as a PostToolUse hook after every tool call
2. Each call is logged to `budget/cost-events.jsonl`
3. After logging, cumulative cost is compared against `BUDGET.md` policy
4. If soft threshold (default 80%) exceeded: warning to stderr
5. If hard threshold (100%) exceeded and hard_stop=true: creates `budget/PAUSED`
flag file, subsequent tool calls are blocked (exit 2)
## Why post-hoc, not pre-run?
Paperclip uses the same approach. Pre-run budget reservation requires a
persistent service or lock file coordination. Post-hoc checking is simpler
and robust enough in practice — the worst case is one extra run before pause.
## Cost estimation
The current implementation counts events as a rough proxy for cost. For
accurate cost tracking, you have two options:
1. **Admin API** (org accounts only): Query `/v1/organizations/cost_report`
with an Admin API key (`sk-ant-admin...`). This gives actual USD costs.
2. **Token estimation**: Parse token counts from Claude's responses and
multiply by published per-token prices. More accurate than event counting
but still an estimate.
For headless runs, `claude -p --max-budget-usd N` provides a per-run
budget cap directly in the CLI.
## Integration
Add to `.claude/settings.json`:
```json
{
"hooks": {
"PostToolUse": [{
"matcher": "*",
"hooks": [{"type": "command", "command": "bash budget/budget-hook.sh"}]
}]
}
}
### Verify
```bash
bash -n /Users/ktg/repos/agent-builder/scripts/templates/budget/budget-hook.sh && bash -n /Users/ktg/repos/agent-builder/scripts/templates/budget/budget-report.sh && echo "VALID"
Expected: VALID
On failure: retry — fix bash syntax, then revert
Checkpoint
git commit -m "feat(templates): add budget tracking templates (Paperclip pattern)"
Step 17: Create governance and approval gate templates
Files to create
scripts/templates/governance/GOVERNANCE.md — See plan Step 17 for full content. Key sections:
- Autonomy Levels (0-4 scale from full manual to full autonomy)
- Approval Gates with
{{GATE_NAME}}and{{GATE_CONDITION}}placeholders - Escalation Rules (budget exceeded, error threshold, unknown tool, scope violation)
- Audit Requirements (tool calls, budget events, approvals, retention)
scripts/templates/governance/approval-gate.sh — PreToolUse hook implementing approval gates. Bash 3.2 compatible. Key behavior:
- Reads GOVERNANCE.md for current autonomy level
- Based on level, auto-approves or requires approval
- For gated operations: writes request to
governance/pending-approvals.jsonl - Checks
governance/approval-responses.jsonlfor matching response - No response within timeout → block (exit 2)
scripts/templates/governance/README.md — Explains the governance model, autonomy levels, Paperclip's "autonomy is a privilege" philosophy.
Verify
bash -n /Users/ktg/repos/agent-builder/scripts/templates/governance/approval-gate.sh && echo "VALID"
Expected: VALID
On failure: retry — fix bash syntax, then revert
Checkpoint
git commit -m "feat(templates): add governance and approval gate templates (Paperclip pattern)"
Step 18: Create org-chart template
Files to create
scripts/templates/org-chart/ORG-CHART.md — Markdown table with columns: Agent, Role, Reports To, Status, Budget. Uses reportsTo pattern from Paperclip. Includes delegation rules and human override section.
scripts/templates/org-chart/org-manager.sh — Bash 3.2 script that:
- Parses ORG-CHART.md table with python3
- Validates: agents exist in
.claude/agents/, no circular chains - Can add/remove agents from the chart
- Generates text-based org tree visualization
scripts/templates/org-chart/README.md — Explains the simple reportsTo pattern, delegation flows, cross-team routing.
Verify
bash -n /Users/ktg/repos/agent-builder/scripts/templates/org-chart/org-manager.sh && echo "VALID"
Expected: VALID
On failure: retry — fix bash syntax, then revert
Checkpoint
git commit -m "feat(templates): add org-chart template (Paperclip pattern)"
Exit Condition
ls /Users/ktg/repos/agent-builder/scripts/templates/heartbeat/ | wc -l→ 5ls /Users/ktg/repos/agent-builder/scripts/templates/goals/ | wc -l→ 3ls /Users/ktg/repos/agent-builder/scripts/templates/budget/ | wc -l→ 4ls /Users/ktg/repos/agent-builder/scripts/templates/governance/ | wc -l→ 3ls /Users/ktg/repos/agent-builder/scripts/templates/org-chart/ | wc -l→ 3- All shell scripts pass
bash -n:find /Users/ktg/repos/agent-builder/scripts/templates/goals /Users/ktg/repos/agent-builder/scripts/templates/budget /Users/ktg/repos/agent-builder/scripts/templates/governance /Users/ktg/repos/agent-builder/scripts/templates/org-chart -name "*.sh" -exec bash -n {} \;→ no errors - context-packet.md contains
{{WAKE_REASON}}placeholder - budget-hook.sh contains reference to PAUSED flag file
Quality Criteria
- Context packet follows Paperclip's "Memento Man" pattern with all sections
- Wake prompt includes rules about not inferring from prior conversations
- Goal hierarchy uses simple parent_id (not recursive) matching Paperclip's actual code
- Budget enforcement is post-hoc matching Paperclip's pattern
- Budget README honestly documents Admin API limitation (org-only, admin key)
- Governance has 5 autonomy levels (0-4) with clear descriptions
- Org chart uses simple reportsTo pattern with human override authority
- All bash scripts are 3.2 compatible