P0.7 — ζ Decision Trail — Agent Prompts

Copy-paste-ready prompts for agents tackling each task in this group. Canonical spec: task-breakdown.md §P0.7 Master bootstrap prompt: agent-bootstrap.md

Group summary

Task ID Title Depends on Effort Unblocks
P0.7.1 Hash-Chained Record Schema P0.2.2 S P0.7.2
P0.7.2 Thought Record CRUD P0.7.1 M P0.7.3, writeback enforcement
P0.7.3 Chain Verification Tool P0.7.2 S P0.8.x, audit-grade tasks

P0.7.1 — Hash-Chained Record Schema

Spec source: task-breakdown.md §P0.7.1 Extraction reference: docs/reference/extractions/zeta-decision-trail-extraction.md Worktree: feature/p0-7-1-hash-schema Branch command: git worktree add .worktrees/claude/p0-7-1-hash-schema -b feature/p0-7-1-hash-schema origin/main Estimated effort: S (Small — 1-2 hours) Depends on: P0.2.2 (Database for record storage) Unblocks: P0.7.2 (CRUD uses schema)

Files to create

  • src/domains/trail/schema.ts — Record Zod schema + SHA-256 hashing
  • tests/domains/trail/schema.test.ts — Schema validation + hash determinism tests

Acceptance criteria

  • Record schema: { id, type, task_id, agent_id, content, timestamp, prev_hash, hash }
  • type enum: plan | analysis | decision | reflection (4 valid types)
  • hash = SHA-256(canonical_JSON({id, type, task_id, content, timestamp, prev_hash}))
  • Canonical JSON: sorted keys, no whitespace (deterministic)
  • First record: prev_hash = "0000...0000" (64 zeros)
  • Test: two records with identical inputs produce identical hashes

Pre-flight reading

  • CLAUDE.md — worktree rules
  • docs/guides/implementation/task-breakdown.md §P0.7.1 — full spec
  • docs/reference/extractions/zeta-decision-trail-extraction.md — record structure
  • src/domains/trail/schema.ts context (will be created in this task)

Ready-to-paste agent prompt

You are a Phase 0 builder agent for Colibri.

TASK: P0.7.1 — Hash-Chained Record Schema
Define Zod schema for thought records and implement deterministic SHA-256 hashing with previous-hash linking.

FILES TO READ FIRST:
1. CLAUDE.md (execution rules)
2. docs/guides/implementation/task-breakdown.md §P0.7.1
3. docs/reference/extractions/zeta-decision-trail-extraction.md
4. src/domains/trail/ (if exists; may reference later in chain)

WORKTREE SETUP:
git fetch origin
git worktree add .worktrees/claude/p0-7-1-hash-schema -b feature/p0-7-1-hash-schema origin/main
cd .worktrees/claude/p0-7-1-hash-schema

FILES TO CREATE:
- src/domains/trail/schema.ts
  * Zod schema ThoughtRecord:
    - id: string (UUID or unique ID)
    - type: enum ["plan", "analysis", "decision", "reflection"]
    - task_id: string (reference to task)
    - agent_id: string (reference to executing agent)
    - content: string (thought/decision content)
    - timestamp: Date (ISO string or timestamp)
    - prev_hash: string (64-hex SHA-256, first record = "0000...0000")
    - hash: string (computed field, 64-hex SHA-256)
  * Function: computeHash(record: Omit<ThoughtRecord, 'hash'>): string
    - Build canonical JSON object: {id, type, task_id, content, timestamp, prev_hash}
    - Keys MUST be sorted alphabetically at every nesting level
    - NO whitespace, NO line breaks, deterministic UTF-8 encoding
    - Return SHA-256 hex (lowercase)
  * Function: createRecord(input: {...}): ThoughtRecord
    - Auto-assign id (UUID v4)
    - Auto-assign timestamp (now)
    - Set prev_hash (default "0000...0000" or pass from previous record)
    - Compute and set hash
    - Return complete record
  * Use crypto.createHash('sha256') from Node.js crypto module
  * Export types: ThoughtRecord, RecordType

- tests/domains/trail/schema.test.ts
  * Test computeHash determinism: hash same input twice → identical output
  * Test canonical JSON: {a: 1, b: 2} and {b: 2, a: 1} → same hash
  * Test type enum validation: valid ["plan", "analysis", "decision", "reflection"], invalid "unknown"
  * Test prev_hash linking: record with prev_hash chains correctly
  * Test first record: prev_hash = "0000...0000" (default)
  * Test content tampering: modify content slightly → hash changes
  * Test full chain: create record1 with default prev_hash, create record2 using record1.hash as prev_hash → hashes differ

ACCEPTANCE CRITERIA (headline):
✓ Zod schema with id, type (4-enum), task_id, agent_id, content, timestamp, prev_hash, hash
✓ Canonical JSON: sorted keys, no whitespace
✓ SHA-256 hash computed from {id, type, task_id, content, timestamp, prev_hash}
✓ First record prev_hash = "0000...0000"
✓ Two identical inputs produce identical hashes (deterministic)

SUCCESS CHECK:
cd .worktrees/claude/p0-7-1-hash-schema && npm test && npm run lint

WRITEBACK (after success):
task_update(task_id="P0.7.1", status="done", progress=100)
thought_record(task_id="P0.7.1", branch="feature/p0-7-1-hash-schema",
  commit_sha=<your-sha>, tests_run=["npm test","npm run lint"],
  summary="Implemented ThoughtRecord Zod schema with 4-type enum (plan|analysis|decision|reflection). SHA-256 hash computed from canonical JSON (sorted keys, no whitespace) of {id,type,task_id,content,timestamp,prev_hash}. First record prev_hash = '0000...0000'. Hash determinism verified: identical inputs → identical hashes.")

FORBIDDENS:
✗ Do not use JSON.stringify alone for canonical JSON (keys must be sorted at every level)
✗ Do not use crypto.subtle (use Node.js crypto module for SHA-256)
✗ Do not allow prev_hash as mutable field after creation (immutable once set)
✗ Do not edit main checkout

NEXT:
P0.7.2 — Thought Record CRUD (uses schema to persist + retrieve records with hash linking)

Verification checklist (for reviewer agent)

  • Zod schema with 4-type enum
  • Record fields: id, type, task_id, agent_id, content, timestamp, prev_hash, hash
  • computeHash uses canonical JSON (sorted keys, no whitespace)
  • SHA-256 from Node.js crypto module
  • First record default prev_hash = “0000…0000”
  • Two identical inputs produce identical hashes
  • Test covers hash determinism, type validation, prev_hash linking
  • npm test and npm run lint pass

Writeback template

task_update:
  task_id: P0.7.1
  status: done
  progress: 100

thought_record:
  task_id: P0.7.1
  branch: feature/p0-7-1-hash-schema
  commit_sha: <sha>
  tests_run: ["npm test", "npm run lint"]
  summary: "Implemented ThoughtRecord Zod schema with id, type (plan|analysis|decision|reflection), task_id, agent_id, content, timestamp, prev_hash, hash. computeHash() builds canonical JSON with sorted keys at every level, no whitespace, deterministic SHA-256. First record prev_hash defaults to '0000...0000' (64 zeros). Test verifies hash determinism: identical inputs  identical outputs. Chain linking ready for P0.7.2."
  blockers: []

Common gotchas

  • Canonical JSON must use sorted keys at every nesting level — Use a recursive key-sorting function or a dedicated canonicalization library (e.g., json-canonicalize npm package). JSON.stringify does NOT sort keys by default. If you mix key order, hashes will differ unpredictably.
  • UTF-8 encoding matters — SHA-256 is sensitive to byte encoding. Ensure consistent UTF-8 (Node.js default). Test with non-ASCII characters if your records might contain them.
  • First record prev_hash is a sentinel — All 64 zeros (0000…0000) signals “no predecessor.” Do not use null, undefined, or empty string. The chain verifier (P0.7.3) will look for this exact pattern.
  • Immutability after creation — Once a record is created with a hash, do not allow mutations to any field (especially content or prev_hash). The schema should reflect this (e.g., readonly fields if using TypeScript interfaces).

P0.7.2 — Thought Record CRUD

Spec source: task-breakdown.md §P0.7.2 Extraction reference: docs/reference/extractions/zeta-decision-trail-extraction.md (CRUD section) Worktree: feature/p0-7-2-trail-crud Branch command: git worktree add .worktrees/claude/p0-7-2-trail-crud -b feature/p0-7-2-trail-crud origin/main Estimated effort: M (Medium — 2-3 hours) Depends on: P0.7.1 (Uses hash schema) Unblocks: P0.7.3 (Chain verification), P0.8.x (Merkle proofs), writeback enforcement

Files to create

  • src/domains/trail/repository.ts — Record CRUD, hash linking, persistence
  • src/tools/trail.ts — MCP tools: thought_record, thought_record_list
  • tests/domains/trail/repository.test.ts — Persistence, linking, MCP tool tests

Acceptance criteria

  • createThoughtRecord(input) computes hash, links to previous record’s hash
  • getThoughtRecord(id) returns record with hash
  • listThoughtRecords({task_id?, limit?}) returns chain in insertion order
  • thought_record MCP tool with Zod input returns record with computed hash
  • thought_record_list MCP tool returns chain for given task_id
  • Stores in SQLite thought_records table (use P0.2.2 schema)

Pre-flight reading

  • CLAUDE.md — execution rules
  • docs/guides/implementation/task-breakdown.md §P0.7.2 — full spec
  • docs/reference/extractions/zeta-decision-trail-extraction.md (CRUD section)
  • src/domains/trail/schema.ts (hash schema from P0.7.1)
  • src/db/schema.sql or similar (database schema from P0.2.2)

Ready-to-paste agent prompt

You are a Phase 0 builder agent for Colibri.

TASK: P0.7.2 — Thought Record CRUD
Implement database persistence, hash linking, and MCP tools for creating and querying thought records.

FILES TO READ FIRST:
1. CLAUDE.md (execution rules)
2. docs/guides/implementation/task-breakdown.md §P0.7.2
3. docs/reference/extractions/zeta-decision-trail-extraction.md (CRUD section)
4. src/domains/trail/schema.ts (schema from P0.7.1)
5. src/db/schema.sql or similar (database schema)

WORKTREE SETUP:
git fetch origin
git worktree add .worktrees/claude/p0-7-2-trail-crud -b feature/p0-7-2-trail-crud origin/main
cd .worktrees/claude/p0-7-2-trail-crud

FILES TO CREATE:
- src/domains/trail/repository.ts
  * Class TrailRepository:
    - Constructor: initializes DB connection (use existing P0.2.2 setup)
    - createThoughtRecord(input: {type, task_id, agent_id, content, prev_hash?}): ThoughtRecord
      - Generate id (UUID v4)
      - Auto timestamp (now)
      - If no prev_hash, use "0000...0000"
      - Compute hash using schema.computeHash()
      - Persist to DB
      - Return complete record
    - getThoughtRecord(id: string): ThoughtRecord | null
      - Query DB, return record or null
    - listThoughtRecords(filters: {task_id?: string, limit?: number}): ThoughtRecord[]
      - Query DB, filter by task_id if provided
      - Order by timestamp ASC (insertion order)
      - Limit if provided (default no limit)
      - Return array of records
  * Use better-sqlite3 or similar (consistent with P0.2.2)
  * Error handling: wrap DB errors, log cleanly
  * Static singleton: export instance

- src/tools/trail.ts (MCP tools)
  * thought_record: input {type, task_id, agent_id, content, prev_hash?}
    - Validate input with Zod (ThoughtRecord schema)
    - Call repository.createThoughtRecord(...)
    - Return {record: {...}} with full record + computed hash
  * thought_record_list: input {task_id: string, limit?: number}
    - Call repository.listThoughtRecords({task_id, limit})
    - Return {records: [...]} in insertion order
    - Include full records (all fields including hash)

- tests/domains/trail/repository.test.ts
  * Test createThoughtRecord: persist to DB, compute hash, return record
  * Test hash linking: create record1 → create record2 with prev_hash = record1.hash → verify chain
  * Test getThoughtRecord: retrieve by id, verify all fields
  * Test listThoughtRecords: query by task_id, verify insertion order, respect limit
  * Test MCP tools: thought_record creates + returns, thought_record_list retrieves
  * Test chain integrity: create 10 records in sequence, verify each links to previous
  * Test filtering: create records for multiple tasks, query by task_id → correct subset

ACCEPTANCE CRITERIA (headline):
✓ createThoughtRecord(input) computes hash, links to previous
✓ getThoughtRecord(id) returns record with hash
✓ listThoughtRecords({task_id?, limit?}) returns chain in insertion order
✓ thought_record MCP tool with Zod input, returns computed hash
✓ thought_record_list MCP tool returns chain for task_id
✓ Persists to SQLite using P0.2.2 schema

SUCCESS CHECK:
cd .worktrees/claude/p0-7-2-trail-crud && npm test && npm run lint

WRITEBACK (after success):
task_update(task_id="P0.7.2", status="done", progress=100)
thought_record(task_id="P0.7.2", branch="feature/p0-7-2-trail-crud",
  commit_sha=<your-sha>, tests_run=["npm test","npm run lint"],
  summary="Implemented TrailRepository with createThoughtRecord (auto-hash, prev_hash linking), getThoughtRecord (retrieve by id), listThoughtRecords (query by task_id + limit). 2 MCP tools: thought_record (create with Zod validation), thought_record_list (query chain). SQLite persistence using P0.2.2 schema. Chain linking verified in tests: 10-record sequence → each links to previous hash.")

FORBIDDENS:
✗ Do not allow hash recomputation after creation (use schema.computeHash once)
✗ Do not skip prev_hash linking (always set it, default to "0000...0000")
✗ Do not use non-insertion-order retrieval (listThoughtRecords must be ASC by timestamp)
✗ Do not edit main checkout

NEXT:
P0.7.3 — Chain Verification Tool (verifies hash links across entire chain)

Verification checklist (for reviewer agent)

  • createThoughtRecord persists to DB with computed hash
  • getThoughtRecord returns complete record including hash
  • listThoughtRecords filters by task_id, respects limit, insertion order (ASC)
  • thought_record MCP tool validates input, returns record with hash
  • thought_record_list MCP tool returns chain for task_id
  • prev_hash linking: create record1 → record2 uses record1.hash as prev_hash
  • Test covers chain integrity (10 records verify each links to previous)
  • npm test and npm run lint pass

Writeback template

task_update:
  task_id: P0.7.2
  status: done
  progress: 100

thought_record:
  task_id: P0.7.2
  branch: feature/p0-7-2-trail-crud
  commit_sha: <sha>
  tests_run: ["npm test", "npm run lint"]
  summary: "Implemented TrailRepository with createThoughtRecord (auto-compute hash, link to previous via prev_hash), getThoughtRecord (retrieve by id), listThoughtRecords (query by task_id, optional limit, insertion order). MCP tools: thought_record (create with Zod validation) and thought_record_list (retrieve chain). SQLite persistence using P0.2.2 schema. Chain integrity verified: create 10 records  each links to predecessor hash."
  blockers: []

Common gotchas

  • Recomputing hashes from prev_hash chains amplifies bugs — Write the tamper-test FIRST (modify one record’s content, verify chain breaks at correct position), then implement verifyChain. This catches logic errors early.
  • prev_hash must be set on creation, not later — Do not allow mutable updates to prev_hash. If you store it as nullable and fill it in later, you’ll miss hash mismatches when the chain is incomplete.
  • Insertion order matters for audit trails — Store and retrieve by timestamp (ASC). Do not use auto-increment IDs as the ordering signal (timestamps may overlap).
  • First record sentinel — The first record in any task must have prev_hash = “0000…0000”. If a task starts with a later record (no prior), that record’s prev_hash should be the sentinel, not null.

P0.7.3 — Chain Verification Tool

Spec source: task-breakdown.md §P0.7.3 Extraction reference: docs/reference/extractions/zeta-decision-trail-extraction.md (verification section) Worktree: feature/p0-7-3-chain-verifier Branch command: git worktree add .worktrees/claude/p0-7-3-chain-verifier -b feature/p0-7-3-chain-verifier origin/main Estimated effort: S (Small — 1-2 hours) Depends on: P0.7.2 (Uses CRUD + schema) Unblocks: P0.8.x, audit-grade tasks

Files to create

  • src/domains/trail/verifier.ts — Chain verification logic
  • src/tools/audit.ts — MCP tool: audit_verify_chain
  • tests/domains/trail/verifier.test.ts — Tamper tests, performance tests

Acceptance criteria

  • verifyChain(records[]) iterates chain, recomputes each hash, checks links
  • Returns { valid: bool, first_broken_at?: id, broken_count: number }
  • audit_verify_chain MCP tool calls verifyChain on full DB chain
  • Test: tamper with one record’s content → verify valid: false at correct position
  • Test: intact 100-record chain → valid: true in < 500ms

Pre-flight reading

  • CLAUDE.md — execution rules
  • docs/guides/implementation/task-breakdown.md §P0.7.3 — full spec
  • docs/reference/extractions/zeta-decision-trail-extraction.md (verification section)
  • src/domains/trail/schema.ts (hash schema)
  • src/domains/trail/repository.ts (CRUD from P0.7.2)

Ready-to-paste agent prompt

You are a Phase 0 builder agent for Colibri.

TASK: P0.7.3 — Chain Verification Tool
Verify thought record chains by recomputing hashes and checking prev_hash links. Detect tampering.

FILES TO READ FIRST:
1. CLAUDE.md (execution rules)
2. docs/guides/implementation/task-breakdown.md §P0.7.3
3. docs/reference/extractions/zeta-decision-trail-extraction.md (verification section)
4. src/domains/trail/schema.ts (hash schema, computeHash function)
5. src/domains/trail/repository.ts (CRUD + DB access)

WORKTREE SETUP:
git fetch origin
git worktree add .worktrees/claude/p0-7-3-chain-verifier -b feature/p0-7-3-chain-verifier origin/main
cd .worktrees/claude/p0-7-3-chain-verifier

FILES TO CREATE:
- src/domains/trail/verifier.ts
  * Function verifyChain(records: ThoughtRecord[]): VerificationResult
    - Input: array of records in chronological order
    - For each record i:
      - Recompute expected hash using schema.computeHash({id, type, task_id, content, timestamp, prev_hash})
      - Compare to record[i].hash
      - If mismatch: mark as broken
      - Check prev_hash link: record[i].prev_hash must equal record[i-1].hash (or "0000...0000" if i==0)
      - If link broken: mark as broken
    - Return VerificationResult {valid: bool, first_broken_at?: id, broken_count: number}
  * Type VerificationResult: {valid: boolean, first_broken_at?: string, broken_count: number}
  * Handle edge cases: empty array (valid=true), single record with sentinel prev_hash (valid=true)
  * Performance: optimize for 100+ records, should complete in < 500ms
  * Logging: use debug logger for each check (no console.log)

- src/tools/audit.ts (MCP tool)
  * audit_verify_chain: no input parameters
    - Query DB for ALL thought records (ordered by timestamp ASC)
    - Call verifyChain(records)
    - Return {valid: bool, first_broken_at?: id, broken_count: number, total_records: number, latency_ms: number}
    - Include latency measurement (start time at query, end time after verification)

- tests/domains/trail/verifier.test.ts
  * Test verifyChain with valid chain: create 5 records, verify → valid=true
  * Test first record sentinel: prev_hash = "0000...0000" → valid
  * Test prev_hash linking: create 5-record chain, verify each link → valid=true
  * Test tamper with content: create 5-record chain, modify record[2].content, recompute hash (NO, leave as is), call verify
    - Expected: valid=false, first_broken_at=record[2].id, broken_count=1
    - Verify subsequent records are NOT marked broken (they don't know about tampering yet)
  * Test tamper with hash: create chain, set record[2].hash to "aaa...aaa" (wrong), call verify
    - Expected: valid=false, first_broken_at=record[2].id
    - Record[3] prev_hash will reference wrong hash → also broken, broken_count=2
  * Test tamper with prev_hash: set record[2].prev_hash to wrong value, call verify
    - Expected: valid=false, first_broken_at=record[2].id (link check fails)
  * Test empty chain: verifyChain([]) → valid=true, broken_count=0
  * Test performance: create 100-record chain, measure time → should complete in < 500ms
  * Test MCP tool: call audit_verify_chain on full DB → includes latency_ms

ACCEPTANCE CRITERIA (headline):
✓ verifyChain(records[]) recomputes hashes, checks prev_hash links
✓ Returns {valid, first_broken_at?, broken_count}
✓ Detects content tampering (hash mismatch)
✓ Detects link tampering (prev_hash mismatch)
✓ audit_verify_chain MCP tool on full DB chain
✓ 100-record chain verifies in < 500ms

SUCCESS CHECK:
cd .worktrees/claude/p0-7-3-chain-verifier && npm test && npm run lint

WRITEBACK (after success):
task_update(task_id="P0.7.3", status="done", progress=100)
thought_record(task_id="P0.7.3", branch="feature/p0-7-3-chain-verifier",
  commit_sha=<your-sha>, tests_run=["npm test","npm run lint"],
  summary="Implemented verifyChain(records[]): iterates chain, recomputes hash for each record, validates prev_hash links. Returns {valid, first_broken_at?, broken_count}. Detects content tampering (hash recompute fails), link tampering (prev_hash reference wrong). MCP tool audit_verify_chain calls verifyChain on full DB, includes latency_ms. 100-record chain: < 500ms. Tamper tests verify correct broken_at detection.")

FORBIDDENS:
✗ Do not skip hash recomputation (always verify hash, never trust record.hash)
✗ Do not trust prev_hash links without validation (always compare to predecessor's hash)
✗ Do not allow tampering to propagate silently (mark first_broken_at when detected)
✗ Do not edit main checkout

NEXT:
P0.8.1 — Merkle Tree Construction (builds proof tree from verified hashes)

Verification checklist (for reviewer agent)

  • verifyChain recomputes hash for each record
  • verifyChain checks prev_hash link to predecessor
  • Returns {valid, first_broken_at?, broken_count}
  • audit_verify_chain MCP tool queries DB, calls verifyChain
  • Tamper test: modify content, verify detects at correct position
  • Link tamper test: modify prev_hash, verify detects link break
  • 100-record chain performance < 500ms
  • Empty chain and single record (sentinel) handle correctly
  • npm test and npm run lint pass

Writeback template

task_update:
  task_id: P0.7.3
  status: done
  progress: 100

thought_record:
  task_id: P0.7.3
  branch: feature/p0-7-3-chain-verifier
  commit_sha: <sha>
  tests_run: ["npm test", "npm run lint"]
  summary: "Implemented verifyChain(records[]): for each record, recompute hash from canonical JSON and compare to stored hash; validate prev_hash link to predecessor (or sentinel '0000...0000' for first record). Returns {valid: boolean, first_broken_at?: id, broken_count: number}. Detects content tampering (hash mismatch) and link tampering (prev_hash mismatch). MCP tool audit_verify_chain queries full DB chain and includes latency_ms. Performance: 100-record chain < 500ms. Tamper tests verify correct first_broken_at detection."
  blockers: []

Common gotchas

  • Recomputing hashes FIRST (tamper test, then implementation) — Write the tamper test before verifyChain. This forces you to think through the logic: if you modify content and don’t recompute the hash, that record’s stored hash is now wrong. The verifier should catch it. If you implement naively, you’ll miss this.
  • prev_hash chain is sensitive to order — If records are not in chronological order, prev_hash links will be wrong. Always verify input is sorted by timestamp before checking links.
  • First record sentinel check — For i==0, prev_hash MUST be “0000…0000” (all 64 zeros). Do NOT allow null, undefined, or empty string. This signals “no predecessor.”
  • Broken count accumulation — If you tamper with record[2] hash, record[3]’s prev_hash will NOT match (it points to record[2].hash, but record[2] is broken). Should broken_count be 1 or 2? It should be 1 (only record[2] itself is tampered). Record[3]’s link is correct per the DB; the issue is upstream. Clarify this in tests.

Next group

P0.8 — η Proof Store

Back to task-prompts index


Back to top

Colibri — documentation-first MCP runtime. Apache 2.0 + Commons Clause.

This site uses Just the Docs, a documentation theme for Jekyll.