Phase 0 namespace note. All environment variables in this file use the
COLIBRI_*namespace (S17 §3). The legacyAMS_*namespace is not read by the Phase 0 runtime. The Phase 0 env floor isCOLIBRI_DB_PATH,COLIBRI_LOG_LEVEL,COLIBRI_STARTUP_TIMEOUT_MS; integration variables likeCOLIBRI_MCP_TIMEOUTandCOLIBRI_WEBHOOK_URLare added here as they’re earned.Not in Phase 0.
agent.spawnednotifications,agent_spawn/agent_statustools, andsrc/domains/agents/are all deferred to Phase 1.5 per ADR-005. P0.9.2’s “Unblocks P0.5.2” line below refers to a δ Model Router that is spec-only in Phase 0 per ADR-005 — P0.9.2 ships the wrapper; the router that consumes it is deferred.
P0.9 — ν Integrations — Agent Prompts
Copy-paste-ready prompts for agents tackling each task in this group. Canonical spec: task-breakdown.md §P0.9 Master bootstrap prompt: agent-bootstrap.md
Group summary
| Task ID | Title | Depends on | Effort | Unblocks |
|---|---|---|---|---|
| P0.9.1 | MCP Bridge | P0.2.1 | M | federated MCP routing (Slack, Gmail, Linear MCPs) |
| P0.9.2 | Claude API Wrappers | P0.1.4 | M | Phase 1.5 δ Model Router (deferred per ADR-005) |
| P0.9.3 | Notification Channels | P0.2.1 | S | external observability + Slack/webhook notifications |
P0.9.1 — MCP Bridge
Spec source: task-breakdown.md §P0.9.1
Extraction reference: docs/reference/extractions/nu-integrations-extraction.md (bridge section)
Worktree: feature/p0-9-1-mcp-bridge
Branch command: git worktree add .worktrees/claude/p0-9-1-mcp-bridge -b feature/p0-9-1-mcp-bridge origin/main
Estimated effort: M (Medium — 2-3 hours)
Depends on: P0.2.1 (Core server infrastructure)
Unblocks: federated MCP routing (Slack, Gmail, Linear MCPs)
Files to create
src/domains/integrations/mcp-bridge.ts— Outbound MCP client wrappertests/domains/integrations/mcp-bridge.test.ts— Connection, retry, timeout tests
Acceptance criteria
McpBridgewraps outbound MCP client calls to external serversconnectToServer(url)creates client, returns connected bridgecallTool(bridge, name, args)calls remote tool, returns result- Timeout: 30s default, configurable via
COLIBRI_MCP_TIMEOUT - Retry: 3 attempts with exponential backoff on transient errors
- Test: mock MCP server → verify roundtrip tool call
Pre-flight reading
CLAUDE.md— execution rulesdocs/guides/implementation/task-breakdown.md§P0.9.1 — full specdocs/reference/extractions/nu-integrations-extraction.md(bridge section)- MCP Python SDK or Node.js MCP client documentation (pick available version)
Ready-to-paste agent prompt
You are a Phase 0 builder agent for Colibri.
TASK: P0.9.1 — MCP Bridge
Wrap outbound MCP client calls with timeout, retry, and error handling.
FILES TO READ FIRST:
1. CLAUDE.md (execution rules)
2. docs/guides/implementation/task-breakdown.md §P0.9.1
3. docs/reference/extractions/nu-integrations-extraction.md (bridge section)
4. MCP SDK documentation (Node.js @modelcontextprotocol/sdk or similar)
WORKTREE SETUP:
git fetch origin
git worktree add .worktrees/claude/p0-9-1-mcp-bridge -b feature/p0-9-1-mcp-bridge origin/main
cd .worktrees/claude/p0-9-1-mcp-bridge
DEPENDENCIES:
npm install @modelcontextprotocol/sdk
FILES TO CREATE:
- src/domains/integrations/mcp-bridge.ts
* Class McpBridge:
- Constructor(url: string, timeout?: number): url is remote MCP server endpoint
- Properties:
- client: MCP client instance (StdioClient, HttpClient, WebSocketClient as appropriate)
- url: remote server URL
- timeout: milliseconds (default 30000 from COLIBRI_MCP_TIMEOUT env var)
- retryAttempts: 3
- retryBackoff: exponential (100ms, 200ms, 400ms)
* Static async connectToServer(url: string, options?: {timeout?: number}): Promise<McpBridge>
- Create client based on URL scheme (http://, ws://, stdio://, etc.)
- Connect to remote server
- Verify connection (call _list_resources or similar)
- Return connected McpBridge instance
- Throw error if connection fails
* Async callTool(name: string, args: Record<string, any>): Promise<ToolResult>
- Validate name (non-empty string)
- Validate args (object or null)
- Wrap call with timeout (reject if exceeds this.timeout)
- Retry logic:
- Attempt 1: call tool
- If transient error (timeout, 429, 5xx): wait backoff[1] ms, attempt 2
- If still transient: wait backoff[2] ms, attempt 3
- If still failed: throw error after all attempts exhausted
- Log: start, end, latency, status
- Return {result, latency_ms}
* Private reconnect(): Promise<void>
- If connection drops, attempt reconnect up to 2 times
- Backoff between reconnect attempts
* Type ToolResult = {result?: any, error?: string, latency_ms: number}
- tests/domains/integrations/mcp-bridge.test.ts
* Test connectToServer: valid URL → connected bridge, invalid URL → error
* Test callTool success: call _list_resources on connected server → returns resource list
* Test callTool with args: call example tool with {param1: value1} → receives result
* Test timeout: set timeout=100ms, call slow endpoint (simulate 5s delay) → rejects with timeout error
* Test retry on transient error: mock 429 response on attempt 1, success on attempt 2 → succeeds after retry
* Test retry exhaustion: mock failure on all 3 attempts → throws error with retry_count=3
* Test backoff timing: measure retry delays, verify exponential backoff (100ms, 200ms, 400ms)
* Test latency_ms: measure elapsed time, verify it includes all retries + network latency
* Test per-call timeout override: create bridge with timeout=30s, call with timeout=5s override → uses 5s
ACCEPTANCE CRITERIA (headline):
✓ McpBridge wraps outbound MCP client calls
✓ connectToServer(url) creates + connects, returns bridge
✓ callTool(name, args) calls remote tool, returns result
✓ Timeout: 30s default, configurable via COLIBRI_MCP_TIMEOUT
✓ Retry: 3 attempts, exponential backoff on transient errors
✓ Mock MCP server roundtrip test
SUCCESS CHECK:
cd .worktrees/claude/p0-9-1-mcp-bridge && npm test && npm run lint
WRITEBACK (after success):
task_update(task_id="P0.9.1", status="done", progress=100)
thought_record(task_id="P0.9.1", branch="feature/p0-9-1-mcp-bridge",
commit_sha=<your-sha>, tests_run=["npm test","npm run lint"],
summary="Implemented McpBridge wrapper for outbound MCP client calls. connectToServer(url) creates client, verifies connection. callTool(name, args) executes remote tool with 30s default timeout (configurable via COLIBRI_MCP_TIMEOUT). Retry: 3 attempts with exponential backoff (100ms, 200ms, 400ms) on transient errors (timeout, 429, 5xx). Returns {result, latency_ms}. Tests: successful roundtrip, timeout rejection, retry on 429, retry exhaustion, backoff timing verification.")
FORBIDDENS:
✗ Do not hardcode timeouts (read COLIBRI_MCP_TIMEOUT env var at startup)
✗ Do not silently swallow transient errors (log each retry, expose retry_count)
✗ Do not allow unlimited retries (max 3 attempts)
✗ Do not edit main checkout
NEXT:
P0.9.2 — Claude API Wrappers (wraps Anthropic API calls with rate limiting, logging)
Verification checklist (for reviewer agent)
- McpBridge class with connectToServer and callTool methods
- connectToServer verifies connection (not just creates client)
- callTool wraps with timeout (default 30s from COLIBRI_MCP_TIMEOUT)
- Retry logic: 3 attempts, exponential backoff (100/200/400ms)
- Returns {result, latency_ms}
- Transient error detection (timeout, 429, 5xx)
- Logging for each attempt and final status
- Tests: success roundtrip, timeout, retry, backoff, latency measurement
- npm test and npm run lint pass
Writeback template
task_update:
task_id: P0.9.1
status: done
progress: 100
thought_record:
task_id: P0.9.1
branch: feature/p0-9-1-mcp-bridge
commit_sha: <sha>
tests_run: ["npm test", "npm run lint"]
summary: "Implemented McpBridge class wrapping outbound MCP client calls. connectToServer(url) creates client from URL scheme, verifies connection, returns bridge. callTool(name, args) executes remote tool with 30s default timeout (COLIBRI_MCP_TIMEOUT env var, per-call override supported). Retry: 3 attempts with exponential backoff (100ms → 200ms → 400ms) on transient errors (timeout, 429, 5xx). Returns {result?, error?, latency_ms}. Logging: start, retry attempt, final status. Tests: successful roundtrip, timeout rejection, 429 retry success, retry exhaustion (3 failures), exponential backoff timing, latency measurement."
blockers: []
Common gotchas
- Outbound MCP timeouts must be configurable per-call — Some MCPs are slow (e.g., Slack search). Do not enforce a global 30s limit if a caller needs 2 minutes. Provide per-call override in callTool options.
- Transient error detection is critical — 429 (rate limit), 5xx (server error), and timeout are transient. 4xx (except 429), 403 (forbidden), 401 (auth) are NOT transient; don’t retry. Test this carefully.
- Exponential backoff prevents thundering herd — If 10 instances retry simultaneously, exponential backoff helps spread the load. Don’t use fixed delays; vary by attempt number.
- Log every retry — If a caller is debugging a slow integration, they need to see the retry timeline. Log each attempt with timestamp and result. Don’t hide retries inside McpBridge.
P0.9.2 — Claude API Wrappers
Spec source: task-breakdown.md §P0.9.2
Extraction reference: docs/reference/extractions/nu-integrations-extraction.md (Claude API section)
Worktree: feature/p0-9-2-claude-api
Branch command: git worktree add .worktrees/claude/p0-9-2-claude-api -b feature/p0-9-2-claude-api origin/main
Estimated effort: M (Medium — 2-3 hours)
Depends on: P0.1.4 (Configuration + env var setup)
Unblocks: Phase 1.5 δ Model Router (spec-only in Phase 0 per ADR-005) — P0.9.2 ships the client wrapper now so the router can pick it up when agent runtime comes online
Files to create
src/domains/integrations/claude.ts— Anthropic API wrappertests/domains/integrations/claude.test.ts— API calls, rate limiting, logging tests
Acceptance criteria
createCompletion(prompt, options)calls Anthropic API with configured modelcreateCompletionWithTools(prompt, tools, options)tool-use completion- API key from
ANTHROPIC_API_KEYenv var — reconciled R75 Wave H: declared.optional()in the Zod schema (src/config.ts:79); validated at call-time bycreateCompletion/createCompletionWithTools, which throwAnthropicConfigErrorif absent. This is Design Invariant 5 — the server boots cleanly when the key is unset for deployments that don’t use the Claude API integration. The original AC wording “validated at startup” is preserved here historically; the shipped contract is “validated before use”. - Rate limit handling: 429 → exponential backoff, max 3 retries
- All API calls logged with: model, prompt_tokens, completion_tokens, latency_ms
- Test (mock): verify retry logic and logging
Pre-flight reading
CLAUDE.md— execution rulesdocs/guides/implementation/task-breakdown.md§P0.9.2 — full specdocs/reference/extractions/nu-integrations-extraction.md(Claude API section)- Anthropic SDK: @anthropic-ai/sdk npm package
.env.example(API key env var names)
Ready-to-paste agent prompt
You are a Phase 0 builder agent for Colibri.
TASK: P0.9.2 — Claude API Wrappers
Wrap Anthropic API calls with rate limiting, logging, and error handling.
FILES TO READ FIRST:
1. CLAUDE.md (execution rules)
2. docs/guides/implementation/task-breakdown.md §P0.9.2
3. docs/reference/extractions/nu-integrations-extraction.md (Claude API section)
4. .env.example (API key env var names, check ANTHROPIC_API_KEY)
5. Anthropic SDK documentation (@anthropic-ai/sdk)
WORKTREE SETUP:
git fetch origin
git worktree add .worktrees/claude/p0-9-2-claude-api -b feature/p0-9-2-claude-api origin/main
cd .worktrees/claude/p0-9-2-claude-api
DEPENDENCIES:
npm install @anthropic-ai/sdk
FILES TO CREATE:
- src/domains/integrations/claude.ts
* Class ClaudeClient:
- Constructor: read ANTHROPIC_API_KEY from env, validate at startup (throw if missing)
- Properties:
- apiKey: string (from ANTHROPIC_API_KEY)
- model: string (configured, e.g., "claude-3-5-sonnet-20241022")
- anthropicClient: Anthropic instance
- rateLimitCooldown: number (default 1000ms, increases with 429 responses)
* Async createCompletion(prompt: string, options?: {model?: string, max_tokens?: number, temperature?: number}): Promise<CompletionResult>
- Prepare message: [{role: "user", content: prompt}]
- Call client.messages.create({model, messages, ...options})
- Validate response, extract text content
- Log: model, prompt_tokens, completion_tokens, latency_ms, stop_reason
- Return {text: string, tokens: {prompt, completion}, latency_ms}
* Async createCompletionWithTools(prompt: string, tools: Tool[], options?: {...}): Promise<ToolCompletionResult>
- Call client.messages.create({model, messages, tools, tool_choice: "auto"})
- Handle tool_use content blocks: extract tool_name, tool_input
- Return {text?: string, tool_calls: [{name, input}], tokens, latency_ms}
* Rate limit handling (both methods):
- Wrap with retry: max 3 attempts
- On 429 response: exponential backoff (1s, 2s, 4s)
- Increase rateLimitCooldown for next call (adaptive)
- Return after success or all attempts exhausted
* Logging (all calls):
- Start: {method, model, prompt_length, timestamp}
- End: {method, model, prompt_tokens, completion_tokens, latency_ms, stop_reason, status}
- Use logger (not console.log)
* Type CompletionResult = {text: string, tokens: {prompt, completion}, latency_ms}
* Type ToolCompletionResult = {text?: string, tool_calls: Array<{name, input}>, tokens, latency_ms}
* Type Tool = {name, description, input_schema}
- tests/domains/integrations/claude.test.ts
* Test createCompletion: mock API response, verify text extraction + logging
* Test createCompletionWithTools: mock tool_use response, extract tool_name + input
* Test API key validation: missing ANTHROPIC_API_KEY → throw at startup
* Test rate limit 429: mock 429 on attempt 1, success on attempt 2 → succeeds after retry
* Test rate limit exhaustion: mock 429 on all 3 attempts → throw error after retries
* Test exponential backoff: measure retry delays, verify 1s → 2s → 4s backoff
* Test logging: call API, verify logs include model, tokens, latency_ms, stop_reason
* Test token counting: mock response with usage {input_tokens: 100, output_tokens: 50}, verify logged correctly
* Test error logging: API error, verify error + status logged, no sensitive data exposed
ACCEPTANCE CRITERIA (headline):
✓ createCompletion(prompt, options) calls Anthropic API
✓ createCompletionWithTools(prompt, tools, options) tool-use completion
✓ API key from ANTHROPIC_API_KEY env var, validated at startup
✓ Rate limit 429 → exponential backoff, max 3 retries
✓ All calls logged: model, prompt_tokens, completion_tokens, latency_ms
✓ Tests verify retry + logging behavior
SUCCESS CHECK:
cd .worktrees/claude/p0-9-2-claude-api && npm test && npm run lint
WRITEBACK (after success):
task_update(task_id="P0.9.2", status="done", progress=100)
thought_record(task_id="P0.9.2", branch="feature/p0-9-2-claude-api",
commit_sha=<your-sha>, tests_run=["npm test","npm run lint"],
summary="Implemented ClaudeClient wrapper for Anthropic API. createCompletion(prompt, options) extracts text response. createCompletionWithTools(prompt, tools, options) handles tool_use content blocks. API key validated at startup (ANTHROPIC_API_KEY env var). Rate limiting: 429 responses trigger exponential backoff (1s, 2s, 4s), max 3 retries. All calls logged with model, prompt_tokens, completion_tokens, latency_ms, stop_reason. Tests: successful completions, tool-use extraction, 429 retry/exhaustion, exponential backoff timing, token logging, error cases without credential exposure.")
FORBIDDENS:
✗ Do not log API keys or sensitive tokens (validate but never echo)
✗ Do not allow null/undefined API key at runtime (validate at startup)
✗ Do not expose rate limit backoff times to callers (hide implementation detail)
✗ Do not edit main checkout
NEXT:
P0.9.3 — Notification Channels (dispatch events to log, MCP, webhook)
Verification checklist (for reviewer agent)
- ClaudeClient constructor validates ANTHROPIC_API_KEY at startup
- createCompletion returns {text, tokens, latency_ms}
- createCompletionWithTools handles tool_use blocks, returns tool_calls array
- Rate limit 429 handling: exponential backoff (1/2/4s), max 3 retries
- All API calls logged with: model, prompt_tokens, completion_tokens, latency_ms
- No API key or sensitive data in logs or error messages
- Tests: successful calls, tool-use, 429 retry, rate limit exhaustion, logging
- npm test and npm run lint pass
Writeback template
task_update:
task_id: P0.9.2
status: done
progress: 100
thought_record:
task_id: P0.9.2
branch: feature/p0-9-2-claude-api
commit_sha: <sha>
tests_run: ["npm test", "npm run lint"]
summary: "Implemented ClaudeClient wrapper for Anthropic API calls. createCompletion(prompt, options) sends message, extracts text response, returns {text, tokens: {prompt, completion}, latency_ms}. createCompletionWithTools(prompt, tools, options) handles tool_use content blocks, returns {text?, tool_calls: [{name, input}], tokens, latency_ms}. API key from ANTHROPIC_API_KEY env var, validated at startup (throws if missing). Rate limiting: 429 responses trigger exponential backoff (1s → 2s → 4s), max 3 retries. All calls logged with: model, prompt_tokens, completion_tokens, latency_ms, stop_reason. No sensitive data in logs. Tests: completions, tool-use, 429 retry, exhaustion, backoff timing, logging, error cases."
blockers: []
Common gotchas
- Anthropic API key handling — never log it, never echo it in errors — If an API call fails, the error response must not include the API key (should be filtered by SDK, but verify). When logging start/end, log {method, model, latency}, NOT {method, model, apiKey}. Add explicit filters in error logging.
- Token counting from usage field — The API response includes
usage: {input_tokens, output_tokens}. Log these fields exactly as provided. Don’t try to estimate tokens; let the API report them. - Rate limit backoff is exponential per instance — If you have 5 agents all calling Claude, each will back off independently. This is fine; it naturally spreads the load. But if a global rate limiter is needed, that’s a future concern.
- Validate API key at startup, not on first request — If API key is missing, the server should fail to start, not on the first user request. This prevents surprise failures in production.
P0.9.3 — Notification Channels
Spec source: task-breakdown.md §P0.9.3
Extraction reference: docs/reference/extractions/nu-integrations-extraction.md (notifications section)
Worktree: feature/p0-9-3-notifications
Branch command: git worktree add .worktrees/claude/p0-9-3-notifications -b feature/p0-9-3-notifications origin/main
Estimated effort: S (Small — 1-2 hours)
Depends on: P0.2.1 (Core server infrastructure)
Unblocks: external observability + Slack/webhook notifications
Files to create
src/domains/integrations/notifications.ts— Event dispatch, channel routingtests/domains/integrations/notifications.test.ts— Channel tests, fire-and-forget verification
Acceptance criteria
notify(event, payload)dispatches event to configured channels- Channels:
log(always on),mcp(MCP notification),webhook(optional) COLIBRI_WEBHOOK_URLenv var enables webhook channel- Events:
task.completed,merkle.finalized,error.critical(noagent.spawned— agent runtime is deferred to Phase 1.5 per ADR-005) - Fire-and-forget: notification failures do not block main execution
- Test: verify each channel receives correct payload for each event type
Pre-flight reading
CLAUDE.md— execution rulesdocs/guides/implementation/task-breakdown.md§P0.9.3 — full specdocs/reference/extractions/nu-integrations-extraction.md(notifications section).env.example(COLIBRI_WEBHOOK_URL env var)
Ready-to-paste agent prompt
You are a Phase 0 builder agent for Colibri.
TASK: P0.9.3 — Notification Channels
Dispatch events to logging, MCP, and webhook channels (fire-and-forget).
FILES TO READ FIRST:
1. CLAUDE.md (execution rules)
2. docs/guides/implementation/task-breakdown.md §P0.9.3
3. docs/reference/extractions/nu-integrations-extraction.md (notifications section)
4. .env.example (COLIBRI_WEBHOOK_URL env var)
WORKTREE SETUP:
git fetch origin
git worktree add .worktrees/claude/p0-9-3-notifications -b feature/p0-9-3-notifications origin/main
cd .worktrees/claude/p0-9-3-notifications
FILES TO CREATE:
- src/domains/integrations/notifications.ts
* Type NotificationEvent = "task.completed" | "merkle.finalized" | "error.critical"
// NOTE: "agent.spawned" is NOT a Phase 0 event — agent runtime is deferred to Phase 1.5 per ADR-005.
* Type NotificationPayload = Record<string, any> (flexible, event-specific)
* Type Channel = "log" | "mcp" | "webhook"
* Function notify(event: NotificationEvent, payload: NotificationPayload): void (fire-and-forget)
- Do NOT await or handle errors (fire-and-forget)
- Dispatch to all enabled channels asynchronously (Promise-based, no await)
- Log dispatch start (debug level)
- Let errors be swallowed (but log them at the handler level)
* Private async dispatchToLog(event, payload)
- Log event at INFO level: {event, timestamp, payload_keys: Object.keys(payload)}
* Private async dispatchToMcp(event, payload)
- Call notification MCP tool (via MCP client or internal tool handler)
- Tool signature: notification_emit(event: string, payload: object) → {success: bool}
* Private async dispatchToWebhook(event, payload)
- Read COLIBRI_WEBHOOK_URL env var
- If not set: skip (webhook disabled)
- POST to webhook URL: {event, payload, timestamp}
- Timeout: 5s
- On failure: log error at WARN level, do NOT rethrow
* Static singleton: export instance
* Configuration at startup:
- Validate COLIBRI_WEBHOOK_URL if set (valid URL format)
- Log enabled channels on startup
- tests/domains/integrations/notifications.test.ts
* Test notify with task.completed event: verify log channel receives event
* Test notify with merkle.finalized event: verify log + MCP channels receive event
* Test notify with error.critical event: verify all channels notified
* Test that `agent.spawned` is NOT accepted (TypeScript should reject it, runtime should reject it too) — agent runtime is Phase 1.5
* Test webhook disabled: notify without COLIBRI_WEBHOOK_URL set → webhook handler skipped
* Test webhook enabled: set COLIBRI_WEBHOOK_URL to mock endpoint, notify → POST received
* Test webhook timeout: mock slow endpoint (10s), notify with 5s timeout → logs warning, doesn't throw
* Test webhook error: mock 500 response, notify → logs warning, doesn't throw
* Test fire-and-forget: notify returns immediately (no await), handlers execute async
* Test MCP notification tool: mock tool invocation, verify event + payload passed
* Test payload flexibility: notify with task.completed + custom fields → all fields in logs
ACCEPTANCE CRITERIA (headline):
✓ notify(event, payload) dispatches to enabled channels
✓ Channels: log (always), mcp, webhook (if COLIBRI_WEBHOOK_URL)
✓ Events: task.completed, merkle.finalized, error.critical (no agent.spawned — Phase 1.5)
✓ Fire-and-forget: errors swallowed (logged only)
✓ Each channel receives correct payload for each event
SUCCESS CHECK:
cd .worktrees/claude/p0-9-3-notifications && npm test && npm run lint
WRITEBACK (after success):
task_update(task_id="P0.9.3", status="done", progress=100)
thought_record(task_id="P0.9.3", branch="feature/p0-9-3-notifications",
commit_sha=<your-sha>, tests_run=["npm test","npm run lint"],
summary="Implemented notify(event, payload) dispatcher for task.completed, merkle.finalized, error.critical events (agent.spawned deferred to Phase 1.5 per ADR-005). Channels: log (always on), mcp (MCP notification tool), webhook (if COLIBRI_WEBHOOK_URL set). Fire-and-forget: no await, errors logged (not thrown). Log channel: INFO level with event + timestamp. MCP channel: calls notification_emit tool. Webhook: POST {event, payload, timestamp}, 5s timeout, failures logged at WARN. Tests: all event types, channels enabled/disabled, webhook timeout/error handling, fire-and-forget verification.")
FORBIDDENS:
✗ Do not block main execution on notification failures (fire-and-forget)
✗ Do not allow unhandled promise rejections (catch all async errors)
✗ Do not validate webhook URL format at dispatch time (validate at startup)
✗ Do not edit main checkout
NEXT:
Phase 0 complete: P0.1–P0.9 ready for integration testing
Verification checklist (for reviewer agent)
- notify function is fire-and-forget (no await in caller)
- Supported events: task.completed, merkle.finalized, error.critical (NO agent.spawned — Phase 1.5)
- Log channel: always enabled, logs at INFO level
- MCP channel: calls notification_emit tool with {event, payload}
- Webhook channel: enabled if COLIBRI_WEBHOOK_URL set, POSTs {event, payload, timestamp}
- Webhook timeout: 5s max, logs WARN on timeout or error
- All errors caught and logged, never rethrown
- Tests: all events, all channels, webhook enabled/disabled, error handling
- npm test and npm run lint pass
Writeback template
task_update:
task_id: P0.9.3
status: done
progress: 100
thought_record:
task_id: P0.9.3
branch: feature/p0-9-3-notifications
commit_sha: <sha>
tests_run: ["npm test", "npm run lint"]
summary: "Implemented notify(event: NotificationEvent, payload: NotificationPayload): void dispatcher (fire-and-forget). Supported events: task.completed, merkle.finalized, error.critical (agent.spawned deferred to Phase 1.5 per ADR-005). Channels: (1) log—always on, logs event + payload at INFO; (2) mcp—calls notification_emit MCP tool; (3) webhook—enabled if COLIBRI_WEBHOOK_URL set, POSTs {event, payload, timestamp} with 5s timeout. All errors caught, logged at WARN, never rethrown. Main execution never blocked. Tests: all event types, channel dispatch verification, webhook enabled/disabled, timeout/error handling (no exception), fire-and-forget immediate return."
blockers: []
Common gotchas
- Fire-and-forget means swallow errors — but log them — Do not throw errors from notification handlers. Catch and log them at WARN level. This prevents notification failures from crashing the main task. But if you don’t log, debugging becomes impossible.
- Webhook configuration validation at startup, not dispatch time — Check COLIBRI_WEBHOOK_URL format (valid URL) when the server starts. Don’t wait until the first notify() call. This catches configuration errors early.
- Timeout must be shorter than main operation — If a webhook hangs, don’t let it block the task. Use a 5s timeout; if webhook doesn’t respond, log and continue. The webhook can be optional.
- Flexible payload structure — Don’t enforce a strict schema for payload. Each event type can have different fields. Tests should verify that custom fields are preserved through the notification pipeline.
Phase 0 Summary
P0.1–P0.9 implementation roadmap complete. These 32 tasks build the foundation:
- Execution (P0.1–P0.6): 18 tasks — infrastructure, core, pipeline, lifecycle, router, skills
- Legitimacy (P0.7–P0.8): 6 tasks — decision trail, proof store (hash chains, Merkle trees)
- Integrations (P0.9): 3 tasks — MCP bridge, Claude API, notifications
All three agent-prompt files cover headline acceptance criteria, forbiddens, gotchas, and writeback templates. Ready for dog-fooding.