| Spec version | v0.9 |
| Signal bot | +61460036867 |
| Domain | koda.systems |
| Node.js | v24.14.0 |
| PostgreSQL | 16 (Homebrew) |
| Hardware | M3 MacBook Air 24GB |
| Section | Status | Done | Partial | Missing | Skipped |
|---|---|---|---|---|---|
| Infrastructure | Partial | 14 | 0 | 2 | 0 |
| Database (Section 9) | Done | 9 | 0 | 0 | 0 |
| Signal Integration (Section 3) | Done | 9 | 0 | 0 | 1 |
| Message Pipeline (Section 2-3) | Done | 7 | 0 | 0 | 0 |
| RBAC (Section 5) | Partial | 5 | 1 | 1 | 0 |
| AI Instructions (Section 6) | Gaps | 2 | 1 | 3 | 0 |
| Skills System (Section 7) | Done | 5 | 0 | 0 | 0 |
| Self-Modification Protocol (Section 8) | Done | 5 | 0 | 0 | 0 |
| Security (Section 10) | Done | 8 | 0 | 0 | 0 |
| Email Integration (Section 11) | Partial | 0 | 1 | 0 | 3 |
| Calendar Integration (Section 12) | Done | 0 | 0 | 0 | 1 |
| Credential Management (Section 13) | Done | 6 | 0 | 0 | 0 |
| File Handling (Section 14) | Partial | 3 | 1 | 0 | 0 |
| Playwright MCP (Section 15) | Partial | 4 | 0 | 1 | 0 |
| Web Deployment — Cloudflare (Section 16) | Done | 8 | 0 | 0 | 0 |
| Usage Monitoring (Section 18) | Done | 8 | 0 | 0 | 0 |
| Error Handling (Section 17) | Done | 5 | 0 | 0 | 0 |
| Resilience & Operations (Section 19) | Done | 8 | 0 | 0 | 0 |
| Testing (Section 20) | Gaps | 1 | 1 | 2 | 0 |
| .env Completeness (Section 22.4) | Partial | 8 | 0 | 4 | 0 |
| Done | Node.js via NVM (v24.14.0) |
| Done | PostgreSQL 16 (Homebrew service) |
| Done | PostgREST (launchd, port 3000) |
| Done | Docker Desktop |
| Done | signal-cli REST API Docker (json-rpc mode, port 8080) |
| Done | Bridge server (launchd, port 3033) |
| Done | Playwright MCP (launchd, port 8931) |
| Done | Wrangler CLI installed |
| Done | Wrangler authenticated (`wrangler login`) |
| Done | Cloudflare account ID + API token in .env (set via /config Signal command) |
| Done | Git repo (github.com/cliaz/koda) |
| Done | SSH deploy key on GitHub |
| Done | Central env file (scripts/koda-env.sh) for PATH management |
| Done | PostgreSQL + NVM node in ~/.bashrc PATH |
| Missing | Sleep disabled (`sudo pmset -a sleep 0 disksleep 0`) |
| Missing | Auto-login enabled |
| Done | All 16 tables created (users, groups, messages, sessions, tasks, memories, attachments, instructions, skills, deployments, credentials, browser_sessions, email_actions, audit_log, error_log, usage_alert_config) |
| Done | koda_bridge role + grants |
| Done | koda_agent role + grants |
| Done | koda_owner role (created with SELECT grants) |
| Done | RLS enabled on project-scoped tables |
| Done | koda_agent RLS policies (all 8 tables) |
| Done | koda_bridge RLS policies (all tables — full access) |
| Done | PostgREST JWTs generated |
| Done | pg_hba.conf trust auth for local sockets |
| Done | Signal bot registered (+61460036867) |
| Done | Device linked as secondary |
| Done | WebSocket receiver (json-rpc mode) |
| Done | @mention trigger detection in groups |
| Done | Piecemeal batching in DM |
| Done | Read receipts |
| Done | Markdown stripping from Claude responses |
| Done | Chunk numbering [1/N] format |
| Skipped | Message edit handling (out of scope) |
| Done | Unknown UUID silent ignore (logged, no response) |
| Done | Inbound message logging to DB |
| Done | Outbound message logging |
| Done | Message chunking at 1500 chars |
| Done | "Working..." notification before Claude invocation |
| Done | Concurrency control with FIFO queue (queued requests notified) |
| Done | Global rate limit (RATE_LIMIT_GLOBAL) |
| Done | Owner exempt from per-user rate limit |
| Done | UUID-based user lookup |
| Done | Owner/Admin/User roles |
| Done | Permissions table + capability grants |
| Done | hasPermission / hasRole functions |
| Partial | Slash command names differ from spec (/user add vs /adduser, etc.) |
| Missing | Full capability enforcement for all 14 grantable capabilities |
| Done | /grants <uuid> command (list grants for a user) |
| Partial | /instructions set (works, but no file attachment handling) |
| Done | Content hash to skip recondensation |
| Missing | Condensation via Claude Code subprocess |
| Missing | <!-- ALWAYS INCLUDE --> marker support |
| Missing | fs.watch on instructions directory |
| Done | /instructions clear command |
| Done | skills/ directory + index.json |
| Done | /skills list (also accepts /skill) |
| Done | /skills show <name> |
| Done | /skills delete <name> (owner only) |
| Done | Skills index path in system prompt |
| Done | Pre/post git checkpoints (self-modify.sh) |
| Done | Auto-rollback on failure (verify health, revert file + commit) |
| Done | One-file-per-change rule enforcement (system prompt instructions) |
| Done | /modify command (owner only, 10 min timeout, auto-approved) |
| Done | Self-modification skill file + index entry |
| Done | AES-256-GCM credential encryption |
| Done | .secrets/credential_key (chmod 600) |
| Done | .gitignore excludes .env, .secrets/, node_modules/ |
| Done | pg_hba.conf trust auth |
| Done | File permissions health check on startup |
| Done | --dangerously-skip-permissions always on (NOTE: spec says this should NOT be used for user messages — known deviation) |
| Done | Credential heuristic detection in plain messages |
| Done | Message redaction for /cred and /config commands |
| Skipped | Gmail MCP (deferred by user) |
| Partial | SMTP config in .env (vars present, empty values) |
| Skipped | Action item extraction |
| Skipped | /emailsend autoapprove |
| Skipped | Google Calendar MCP (deferred by user) |
| Done | /cred set (encrypt + store) |
| Done | /cred get (decrypt + return) |
| Done | /cred delete |
| Done | /config set|get|list — .env management via Signal (allowlisted keys, sensitive values encrypted at rest) |
| Done | Message redaction from log on credential commands |
| Done | Credential heuristic detection |
| Done | Inbound attachment save to disk |
| Done | Attachment metadata to DB |
| Done | Directory structure (attachments/, instructions/, skills/, logs/, screenshots/) |
| Partial | Outbound file send (base64_attachments support exists) |
| Done | @playwright/mcp installed globally |
| Done | Chromium binary installed |
| Done | Launchd plist running (port 8931) |
| Done | SSE protocol client in bridge (callPlaywrightMCPTool) |
| Missing | Dedicated browser profile auth to claude.ai |
| Done | Wrangler installed |
| Done | Wrangler authenticated |
| Done | Cloudflare account ID in .env |
| Done | Cloudflare API token in .env (encrypted at rest) |
| Done | Auto-deploy watcher script (deploy-watch.sh + fswatch) |
| Done | Deploy-watch launchd plist (com.koda.deploy-watch) |
| Done | koda.systems custom domain + SSL |
| Done | koda.systems dashboard deployed and live |
| Done | In-memory cache (sessionPct, weeklyPct, capturedAt) |
| Done | Poll interval (15 min default) |
| Done | Cache TTL skip logic |
| Done | Threshold crossing detection (once per crossing) |
| Done | /usage command suite (all 8 sub-commands) |
| Done | usage_alert_config DB persistence |
| Done | Scrape failure alerting |
| Done | scrapeUsage via Claude CLI /usage (user-modified approach) |
| Done | error_log table + logError function |
| Done | uncaughtException handler |
| Done | unhandledRejection handler |
| Done | Claude Code exit handling (logged + error message to user + owner notification) |
| Done | Approval timeout (configurable via APPROVAL_TIMEOUT_MINUTES, default 30 min) |
| Done | Bridge launchd (KeepAlive) |
| Done | PostgREST launchd |
| Done | Playwright MCP launchd |
| Done | Docker restart policy (unless-stopped) |
| Done | logrotate.conf |
| Done | prune-logs.sh |
| Done | Crontab entry for log pruning (daily 3am) |
| Done | Daily log file rotation (bridge-YYYY-MM-DD.log with symlink) |
| Done | tests/run_tests.js (34 tests passing) |
| Partial | Test coverage (encryption, chunking, rate limiting, JWT, PostgREST, Signal, file structure — missing pipeline, RBAC, session, Playwright, usage tests) |
| Missing | Test DB (koda_test) separate from production |
| Missing | Test results to JSON file |
| Done | Signal vars |
| Done | Processing vars (MAX_CONCURRENT_CLAUDE, BATCH_DELAY_MS, MAX_SIGNAL_CHUNK) |
| Done | PostgREST vars |
| Done | Cloudflare vars (all set) |
| Done | Usage monitoring vars |
| Done | SMTP vars (present, empty) |
| Done | APPROVAL_TIMEOUT_MINUTES |
| Done | RATE_LIMIT_GLOBAL |
| Missing | MEMORY_TOKEN_BUDGET |
| Missing | AUTO_APPROVE_DEFAULT |
| Missing | EMAIL_SEND_AUTOAPPROVE |
| Missing | TEST_DB_NAME, TEST_SIGNAL_GROUP_ID, TEST_OWNER_UUID |