{"id":"79d4cd87-8ebf-4a87-82d2-d2eae881a42c","entityType":"agent","slug":"clawhub-batthis-amber-phone-agent","name":"Amber — Phone-Capable Voice Agent","canonicalUrl":"https://www.xpersona.co/agent/clawhub-batthis-amber-phone-agent","canonicalPath":"/agent/clawhub-batthis-amber-phone-agent","generatedAt":"2026-10-10T00:36:24.917Z","source":"CLAWHUB","claimStatus":"UNCLAIMED","verificationTier":"NONE","summary":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:23:34.821Z","emptyReason":null},"description":"Give your agent a phone number. Amber answers calls, places confirmed outbound calls, completes phone tasks, logs transcripts, and exposes MCP tools.","descriptionLabel":"Source description","evidenceSummary":"Capability contract not published. No trust telemetry is available yet. 5.1K downloads reported by the source. Last updated 10/9/2026.","installCommand":"clawhub skill install s177cd8521x179ryrctnxwgpth83hrgh:amber-phone-agent","sourceUrl":"https://clawhub.ai/batthis/amber-phone-agent","homepage":"https://clawhub.ai/batthis/skills/amber-phone-agent","primaryLinks":[{"label":"View on ClawHub","url":"https://clawhub.ai/batthis/amber-phone-agent","kind":"source"},{"label":"Homepage","url":"https://clawhub.ai/batthis/skills/amber-phone-agent","kind":"homepage"}],"safetyScore":84,"overallRank":62,"popularityScore":74,"trustScore":null,"claimedByName":null,"isOwner":false,"seoDescription":"Amber — Phone-Capable Voice Agent technical dossier on Xpersona with agent coverage, OPENCLEW support, and live trust metadata."},"coverage":{"evidence":{"source":"public-profile","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:23:34.821Z","emptyReason":null},"protocols":[{"protocol":"OPENCLEW","label":"OpenClaw","status":"self-declared","notes":"Declared in the public agent profile."}],"capabilities":[],"verifiedCount":0,"selfDeclaredCount":1,"capabilityMatrix":{"rows":[{"key":"OPENCLEW","type":"protocol","support":"unknown","confidenceSource":"profile","notes":"Listed on profile"}],"flattenedTokens":"protocol:OPENCLEW|unknown|profile"}},"adoption":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:23:34.821Z","emptyReason":null},"stars":null,"forks":null,"downloads":5105,"packageName":null,"latestVersion":"5.5.50","tractionLabel":"5.1K downloads"},"release":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:23:34.821Z","emptyReason":null},"lastUpdatedAt":"2026-10-09T04:23:34.821Z","lastCrawledAt":"2026-10-09T04:23:34.821Z","lastIndexedAt":null,"nextCrawlAt":"2026-10-10T04:23:34.821Z","lastVerifiedAt":null,"highlights":[{"version":"5.5.50","createdAt":"2026-08-24T01:45:41.314Z","changelog":"Sharpen ClawHub positioning around giving agents a phone number and completing real phone tasks.","fileCount":70,"zipByteSize":223850},{"version":"5.5.49","createdAt":"2026-07-30T23:34:06.014Z","changelog":"Fix CRM caller recognition after Node ABI changes; add privacy-safe CRM opt-in during setup; tune Realtime VAD sensitivity and expose VAD controls.","fileCount":72,"zipByteSize":227014},{"version":"5.5.48","createdAt":"2026-07-30T11:55:06.919Z","changelog":"Bundle explicit ClawHub skill-card evidence and keep the 5.5.47 CRM opt-in hardening: CRM stays hidden from runtime and MCP tools unless AMBER_CRM_ENABLED=true.","fileCount":72,"zipByteSize":226234},{"version":"5.5.47","createdAt":"2026-07-30T11:42:54.402Z","changelog":"Tighten CRM opt-in behavior: hide CRM from the voice runtime and MCP tool list unless AMBER_CRM_ENABLED=true, while keeping the setup wizard opt-in prompts and CRM dependency validation from 5.5.46.","fileCount":72,"zipByteSize":226194},{"version":"5.5.46","createdAt":"2026-07-30T11:31:48.294Z","changelog":"Improve CRM install and setup flow: add opt-in CRM caller-memory prompts, install metadata for CRM dependencies, validation for native SQLite loading when CRM is enabled, and rebuild guidance for Node upgrades.","fileCount":72,"zipByteSize":225840},{"version":"5.5.45","createdAt":"2026-07-25T14:02:54.036Z","changelog":"Add ClawHub skill card, keep dashboard test-call controls and scanner-hardened release metadata, and bump runtime package version.","fileCount":72,"zipByteSize":224700},{"version":"5.5.44","createdAt":"2026-07-25T13:54:48.036Z","changelog":"Promote the clean Amber release after ClawHub review hardening: dashboard model controls, opt-in CRM persistence/enrichment, scanner-safe docs, pinned dependencies, and safer setup credential handling.","fileCount":72,"zipByteSize":224463},{"version":"5.5.43","createdAt":"2026-07-25T13:46:21.689Z","changelog":"Clean up ClawHub review findings: enforce CRM opt-in gate, remove external CRM adapter design drift, stop plaintext .env backups, write .env with 0600 permissions, remove hidden prompt comment, and pin direct dependency versions.","fileCount":72,"zipByteSize":224511}]},"execution":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No published capability contract is available yet."},"installCommand":"clawhub skill install s177cd8521x179ryrctnxwgpth83hrgh:amber-phone-agent","setupComplexity":"low","setupSteps":["Install using `clawhub skill install s177cd8521x179ryrctnxwgpth83hrgh:amber-phone-agent` in an isolated environment before connecting it to live workloads.","No published capability contract is available yet, so validate auth and request/response behavior manually.","Review the upstream CLAWHUB listing at https://clawhub.ai/batthis/amber-phone-agent before using production credentials."],"contract":{"contractStatus":"missing","authModes":[],"requires":[],"forbidden":[],"supportsMcp":false,"supportsA2a":false,"supportsStreaming":false,"inputSchemaRef":null,"outputSchemaRef":null,"dataRegion":null,"contractUpdatedAt":null,"sourceUpdatedAt":null,"freshnessSeconds":null},"invocationGuide":{"preferredApi":{"snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/trust"},"curlExamples":["curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/snapshot\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/contract\"","curl -s \"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/trust\""],"jsonRequestTemplate":{"query":"summarize this repo","constraints":{"maxLatencyMs":2000,"protocolPreference":["OPENCLEW"]}},"jsonResponseTemplate":{"ok":true,"result":{"summary":"...","confidence":0.9},"meta":{"source":"CLAWHUB","generatedAt":"2026-10-10T00:36:24.911Z"}},"retryPolicy":{"maxAttempts":3,"backoffMs":[500,1500,3500],"retryableConditions":["HTTP_429","HTTP_503","NETWORK_TIMEOUT"]}},"endpoints":{"dossierUrl":"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/dossier","snapshotUrl":"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/snapshot","contractUrl":"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/contract","trustUrl":"https://www.xpersona.co/api/v1/agents/clawhub-batthis-amber-phone-agent/trust"}},"reliability":{"evidence":{"source":"runtime-metrics","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No trust, reliability, or runtime telemetry is available."},"trust":{"status":"unavailable","handshakeStatus":"UNKNOWN","verificationFreshnessHours":null,"reputationScore":null,"p95LatencyMs":null,"successRate30d":null,"fallbackRate":null,"attempts30d":null,"trustUpdatedAt":null,"trustConfidence":"unknown","sourceUpdatedAt":null,"freshnessSeconds":null},"decisionGuardrails":{"doNotUseIf":["Contract metadata is missing or unavailable for deterministic execution."],"safeUseWhen":[],"riskFlags":["missing_or_unavailable_contract","trust_data_unavailable","schema_references_missing"],"operationalConfidence":"low"},"executionMetrics":{"observedLatencyMsP50":null,"observedLatencyMsP95":null,"estimatedCostUsd":null,"uptime30d":null,"rateLimitRpm":null,"rateLimitBurst":null,"lastVerifiedAt":null,"verificationSource":null},"runtimeMetrics":{"successRate":null,"avgLatencyMs":null,"avgCostUsd":null,"hallucinationRate":null,"retryRate":null,"disputeRate":null,"p50Latency":null,"p95Latency":null,"lastUpdated":null}},"benchmarks":{"evidence":{"source":"no-benchmark-data","verified":false,"confidence":"low","updatedAt":null,"emptyReason":"No benchmark suites or observed failure patterns are available."},"suites":[],"failurePatterns":[]},"artifacts":{"evidence":{"source":"CLAWHUB","verified":false,"confidence":"medium","updatedAt":"2026-10-09T04:23:34.821Z","emptyReason":null},"readme":"Skill: Amber — Phone-Capable Voice Agent\n\nOwner: batthis\n\nSummary: Give your agent a phone number. Amber answers calls, places confirmed outbound calls, completes phone tasks, logs transcripts, and exposes MCP tools.\n\nTags: ai-phone:5.5.48, answering-service:5.5.48, assistant:5.5.48, calendar:5.5.48, call-screening:5.5.48, inbound_calls:5.5.48, latest:5.5.50, openclaw:5.5.48, outbound_calls:5.5.48, phone:5.5.48, phone-screening:5.5.48, realtime:5.5.48, receptionist:5.5.48, telephone:5.5.48, twilio:5.5.48, voice:5.5.48\n\nVersion history:\n\nv5.5.50 | 2026-08-24T01:45:41.314Z | user\n\nSharpen ClawHub positioning around giving agents a phone number and completing real phone tasks.\n\nv5.5.49 | 2026-07-30T23:34:06.014Z | user\n\nFix CRM caller recognition after Node ABI changes; add privacy-safe CRM opt-in during setup; tune Realtime VAD sensitivity and expose VAD controls.\n\nv5.5.48 | 2026-07-30T11:55:06.919Z | user\n\nBundle explicit ClawHub skill-card evidence and keep the 5.5.47 CRM opt-in hardening: CRM stays hidden from runtime and MCP tools unless AMBER_CRM_ENABLED=true.\n\nv5.5.47 | 2026-07-30T11:42:54.402Z | user\n\nTighten CRM opt-in behavior: hide CRM from the voice runtime and MCP tool list unless AMBER_CRM_ENABLED=true, while keeping the setup wizard opt-in prompts and CRM dependency validation from 5.5.46.\n\nv5.5.46 | 2026-07-30T11:31:48.294Z | user\n\nImprove CRM install and setup flow: add opt-in CRM caller-memory prompts, install metadata for CRM dependencies, validation for native SQLite loading when CRM is enabled, and rebuild guidance for Node upgrades.\n\nv5.5.45 | 2026-07-25T14:02:54.036Z | user\n\nAdd ClawHub skill card, keep dashboard test-call controls and scanner-hardened release metadata, and bump runtime package version.\n\nv5.5.44 | 2026-07-25T13:54:48.036Z | user\n\nPromote the clean Amber release after ClawHub review hardening: dashboard model controls, opt-in CRM persistence/enrichment, scanner-safe docs, pinned dependencies, and safer setup credential handling.\n\nv5.5.43 | 2026-07-25T13:46:21.689Z | user\n\nClean up ClawHub review findings: enforce CRM opt-in gate, remove external CRM adapter design drift, stop plaintext .env backups, write .env with 0600 permissions, remove hidden prompt comment, and pin direct dependency versions.\n\nv5.5.42 | 2026-07-25T13:36:58.763Z | user\n\nMake CRM persistence opt-in, make transcript CRM enrichment separately opt-in, add front-loaded privacy notices across runtime/Cowork docs, avoid dashboard token persistence, and chmod the local CRM database.\n\nv5.5.41 | 2026-07-25T13:28:02.405Z | user\n\nHarden ClawHub release metadata and docs, add handler-level calendar create confirmation, keep dashboard bridge proxy body-only/loopback-only, replace raw-IP Hermes example, and clarify local CRM/contact/log privacy scope.\n\nv5.5.40 | 2026-07-25T13:20:04.920Z | user\n\nAdd call log dashboard one-touch test calls, cost visibility, regular/mini Realtime model selection, setup wizard model defaults, scanner-safe placeholders, and pinned runtime install lockfile.\n\nv5.5.39 | 2026-06-18T12:11:39.709Z | user\n\nCompatibility-first OpenAI webhook strict mode, privacy/CRM documentation hardening, safer published excludes, and clearer setup/demo validation wording.\n\nv5.5.38 | 2026-06-14T19:45:30.778Z | user\n\nSecurity audit cleanup: remove scanner-confusing examples/phrasing, keep confirmation gates and privacy guardrails, preserve all phone/CRM/calendar/MCP capabilities, and retain clean npm audit state.\n\nv5.5.37 | 2026-06-14T19:38:08.005Z | user\n\nSecurity audit hardening: add dashboard privacy/access-control warnings, remove unsafe network-bind example, disclose setup wizard secret storage and validation scope, and refresh runtime dependencies to clear npm audit findings.\n\nv5.5.36 | 2026-06-14T19:33:21.645Z | user\n\nSecurity audit hardening: align CRM retention/consent guidance, minimize sensitive context extraction, require confirmed calendar-create examples, and exclude generated call-log artifacts from published packages.\n\nv3.691.0 | 2026-06-14T19:32:24.994Z | user\n\nSecurity audit hardening: align CRM retention/consent guidance, minimize sensitive context extraction, require confirmed calendar-create examples, and exclude generated call-log artifacts from published packages.\n\nv5.5.35 | 2026-06-13T12:13:27.062Z | user\n\nHarden security metadata, dashboard CORS, helper execution, calendar logging, CRM consent wording, contacts export defaults, and MIT-0 package licensing.\n\nv5.5.34 | 2026-05-16T15:08:09.047Z | user\n\nHighlight MCP-capable client and agent harness support beyond Claude Desktop/Cowork.\n\nv5.5.33 | 2026-05-16T14:26:08.347Z | user\n\nClarify outbound-disabled messaging: outbound calling is enabled by default and only disabled when AMBER_ENABLE_OUTBOUND_CALLS=false is set.\n\nv5.5.32 | 2026-05-16T14:22:05.067Z | user\n\nDefault outbound calling back to enabled for full Amber UX while preserving AMBER_ENABLE_OUTBOUND_CALLS=false kill-switch and confirmation gates.\n\nv5.5.31 | 2026-05-16T14:16:26.701Z | user\n\nMake outbound calling opt-in via AMBER_ENABLE_OUTBOUND_CALLS=false by default, with runtime and MCP enforcement plus setup wizard/docs updates.\n\nv5.5.30 | 2026-05-16T14:08:18.692Z | user\n\nTighten ClawScan-facing capability wording and rely on setup wizard for credential prompts while preserving runtime behavior.\n\nv5.5.29 | 2026-05-16T14:01:02.151Z | user\n\nFurther reframe ClawScan-facing docs for local memory, optional watcher, and gateway wording without changing capabilities.\n\nv5.5.28 | 2026-05-16T13:55:24.323Z | user\n\nReframe ClawScan-facing docs around code-enforced confirmation, local CRM review, and least-privilege configuration without changing runtime capabilities.\n\nv5.5.27 | 2026-05-16T13:43:59.761Z | user\n\nAvoid false critical static-analysis helper-execution pattern while keeping shell-disabled allowlisted local helpers.\n\nv5.5.26 | 2026-05-16T12:17:23.941Z | user\n\nAvoid OpenAI credential literal pattern in static analysis.\n\nv5.5.25 | 2026-05-16T12:16:04.865Z | user\n\nRemove remaining env and apiKey static-analysis patterns from the bridge runtime.\n\nv5.5.24 | 2026-05-16T12:13:59.877Z | user\n\nMove runtime personalization/provider env reads into config helpers to reduce static-analysis findings.\n\nv5.5.23 | 2026-05-16T12:12:15.721Z | user\n\nCentralize runtime environment mode to reduce static-analysis findings.\n\nv5.5.22 | 2026-05-16T12:10:45.178Z | user\n\nCentralize webhook strict config to reduce static-analysis findings.\n\nv5.5.21 | 2026-05-16T12:09:26.562Z | user\n\nCentralize bridge credential config to reduce static-analysis findings.\n\nv5.5.20 | 2026-05-16T12:08:19.913Z | user\n\nCentralize gateway credential config to reduce static-analysis findings.\n\nv5.5.19 | 2026-05-16T12:07:12.294Z | user\n\nAvoid gateway token literal pattern in runtime static analysis.\n\nv5.5.18 | 2026-05-16T12:04:27.163Z | user\n\nAvoid credential/voice literal patterns that triggered static-analysis false positives.\n\nv5.5.17 | 2026-05-16T12:02:44.372Z | user\n\nMove provider credential reads into a dedicated config helper to reduce static-analysis noise.\n\nv5.5.16 | 2026-05-16T12:01:10.289Z | user\n\nFurther reduce static-analysis noise by replacing execFileSync helper calls with shell-disabled spawnSync and removing token/provider literal patterns.\n\nv5.5.15 | 2026-05-16T11:55:06.429Z | user\n\nReduce critical static-analysis findings by removing setup/dashboard child-process execution and isolating config.\n\nv5.5.14 | 2026-05-16T11:43:04.735Z | user\n\nAvoid static token-pattern noise in gateway fallback.\n\nv5.5.13 | 2026-05-16T11:41:56.014Z | user\n\nAvoid static token-pattern noise in gateway client setup.\n\nv5.5.12 | 2026-05-16T11:40:40.811Z | user\n\nFurther reduce token-literal static analysis noise.\n\nv5.5.11 | 2026-05-16T11:39:21.786Z | user\n\nReduce static-analysis false positives in setup and documentation.\n\nv5.5.10 | 2026-05-16T10:21:15.863Z | user\n\nClarify prompt-based usage and safety documentation.\n\nv5.5.9 | 2026-05-16T10:17:36.589Z | user\n\nClarify Amber setup wizard and prompt-based usage.\n\nv5.5.8 | 2026-04-18T13:03:37.503Z | user\n\nReposition Amber around real phone capabilities for agents.\n\nv5.5.7 | 2026-03-24T02:58:44.151Z | user\n\nBump all tags to 5.5.7; add receptionist/telephone/answering-service tags for search\n\nv5.5.6 | 2026-03-24T02:56:06.124Z | user\n\nSEO: richer phone keyword density in description and title for better search discoverability (telephone, virtual receptionist, AI phone assistant, phone call screening)\n\nv5.5.5 | 2026-03-07T00:08:55.405Z | user\n\nv5.5.5: kick stuck VT scan with fresh file hash; minor description tweak\n\nv5.5.4 | 2026-03-06T17:23:57.929Z | user\n\nv5.5.4: bump all tags to latest version for search discoverability\n\nv5.5.3 | 2026-03-06T17:16:10.797Z | user\n\nv5.5.3: update description + bump phone/voice/ai-phone tags to latest for search discoverability\n\nv5.5.2 | 2026-03-06T16:17:49.837Z | user\n\nv5.5.2: re-publish to resolve stuck security scan (name change to Phone Voice Assistant - Amber)\n\nArchive index:\n\nArchive v5.5.50: 70 files, 223850 bytes\n\nFiles: AGENT.md (18161b), AMBER_SKILLS_SPEC.md (20685b), amber-skills/calendar/handler.js (8722b), amber-skills/calendar/SKILL.md (3989b), amber-skills/crm/DESIGN.md (19828b), amber-skills/crm/handler.js (17094b), amber-skills/crm/package-lock.json (16675b), amber-skills/crm/package.json (299b), amber-skills/crm/SKILL.md (6080b), amber-skills/send-message/handler.js (3323b), amber-skills/send-message/SKILL.md (2792b), amber-skills/SKILL_MANIFEST.json (255b), ASTERISK-IMPLEMENTATION-PLAN.md (14234b), dashboard/contacts.example.json (132b), dashboard/index.html (38732b), dashboard/process_logs.js (30483b), dashboard/README.md (7775b), dashboard/scripts/serve.js (8417b), dashboard/scripts/watch.js (4032b), dashboard/update_data.sh (609b), demo/demo-wizard.js (6641b), demo/README.md (4327b), DO-NOT-CHANGE.md (2036b), FEEDBACK.md (1431b), LICENSE (911b), NOTICE (158b), packaging/cowork/commands/call.md (1118b), packaging/cowork/commands/calls.md (852b), packaging/cowork/commands/screen.md (1055b), packaging/cowork/commands/voicemail.md (515b), packaging/cowork/README.md (3504b), packaging/cowork/skills/calendar/SKILL.md (1407b), packaging/cowork/skills/call-screening/SKILL.md (1844b), packaging/cowork/skills/contacts/SKILL.md (755b), packaging/cowork/skills/crm/SKILL.md (1747b), packaging/cowork/skills/phone-calls/SKILL.md (1652b), packaging/hermes/mcp_servers.yaml (407b), packaging/hermes/README.md (1264b), packaging/hermes/SKILL.md (4932b), README.md (13978b), references/architecture.md (1509b), references/positioning-backup-2026-04-18.md (1333b), references/release-checklist.md (1152b), runtime/package-lock.json (112565b), runtime/package.json (1051b), runtime/README.md (9110b), runtime/scripts/dist-watcher.cjs (3547b), runtime/scripts/sync-contacts.js (6764b), runtime/setup-wizard.js (21861b), runtime/src/config.ts (4606b), runtime/src/index.ts (95733b), runtime/src/local-helper-runner.ts (1481b), runtime/src/mcp-server.ts (30343b), runtime/src/providers/index.ts (2302b), runtime/src/providers/telnyx.ts (6969b), runtime/src/providers/twilio.ts (4746b), runtime/src/providers/types.ts (4510b), runtime/src/skills/api.ts (5563b), runtime/src/skills/index.ts (349b), runtime/src/skills/loader.ts (6412b), runtime/src/skills/router.ts (8930b), runtime/src/skills/types.ts (1527b), runtime/tsconfig.json (431b), scripts/setup_quickstart.sh (826b), scripts/validate_voice_env.sh (2790b), skill-card.md (2919b), SKILL.md (17781b), skills/amber-phone-agent/SKILL.md (4932b), UPGRADING.md (2706b), _meta.json (137b)\n\nFile v5.5.50:amber-skills/calendar/SKILL.md\n\n---\nname: calendar\nversion: 1.2.0\ndescription: \"Query and manage the operator's calendar — check availability and create new entries\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": true, \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [\"ical-query\"], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"calendar_query\", \"description\": \"Check the operator's calendar availability or create a new entry. PRIVACY RULE: When reporting availability to callers, NEVER disclose event titles, names, locations, or any details about what the operator is doing. Only share whether they are free or busy at a given time (e.g. 'free from 2pm to 4pm', 'busy until 3pm'). Treat all calendar event details as private and confidential. Calendar creation requires explicit confirmation from the caller before the action proceeds.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup\", \"create\"], \"description\": \"Whether to look up availability or create a new event\"}, \"range\": {\"type\": \"string\", \"description\": \"For lookup: today, tomorrow, week, or a specific date like 2026-02-23\", \"pattern\": \"^(today|tomorrow|week|\\\\d{4}-\\\\d{2}-\\\\d{2})$\"}, \"title\": {\"type\": \"string\", \"description\": \"For create: the event title\", \"maxLength\": 200}, \"start\": {\"type\": \"string\", \"description\": \"For create: start date-time like 2026-02-23T15:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"end\": {\"type\": \"string\", \"description\": \"For create: end date-time like 2026-02-23T16:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"calendar\": {\"type\": \"string\", \"description\": \"Optional: specific calendar name\", \"maxLength\": 100}, \"notes\": {\"type\": \"string\", \"description\": \"For create: event notes\", \"maxLength\": 500}, \"location\": {\"type\": \"string\", \"description\": \"For create: event location\", \"maxLength\": 200}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Required for create actions after the caller explicitly confirms the booking details.\"}}, \"required\": [\"action\"]}}}}\n---\n\n# Calendar Skill\n\nQuery the operator's calendar for availability and create new entries via `ical-query`.\n\n## Capabilities\n\n- **read**: Check free/busy availability for today, tomorrow, this week, or a specific date\n- **act**: Create new calendar entries (explicit confirmation required)\n\n## Privacy Rule\n\n**Event details are never disclosed to callers.** This is enforced at two levels:\n\n1. **Handler level** — the handler strips all event titles, names, locations, and notes from ical-query output before returning results. Only busy time slots (start/end times) are returned.\n2. **Model level** — the function description instructs Amber to only communicate availability (\"free from 2pm to 4pm\") and never reveal what the events are.\n\nAmber should say things like:\n- ✅ \"The operator is free between 2 and 4 this afternoon\"\n- ✅ \"They're busy until 3pm, then free for the rest of the day\"\n- ❌ \"They have a meeting with John at 2pm\" ← never\n- ❌ \"They're at the dentist from 10 to 11\" ← never\n\n## Security — Three Layers\n\nInput validation is enforced at three independent levels:\n\n1. **Schema level** — `range` is constrained by `pattern: ^(today|tomorrow|week|\\d{4}-\\d{2}-\\d{2})$`; `start`/`end` by `pattern: ^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$`; freetext fields have `maxLength` caps. The LLM cannot produce out-of-spec values without violating the schema.\n2. **Handler level** — explicit validation before any exec call; rejects values that don't match expected formats even if schema is bypassed.\n3. **Exec level** — `context.exec()` takes a `string[]` and uses `execFileSync` (no shell spawned); arguments are passed as discrete tokens, not a shell-interpolated string.\n\n## Notes\n\n- Uses `/usr/local/bin/ical-query` — no network access, no gateway round-trip\n- Fast: direct local binary call (~100ms)\n- Calendar name optional — defaults to operator's primary calendar\n\nFile v5.5.50:amber-skills/crm/SKILL.md\n\n---\nname: crm\nversion: 1.0.0\ndescription: \"Local contact memory and interaction log for operator-reviewed phone follow-up\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": false, \"timeout_ms\": 3000, \"permissions\": {\"local_binaries\": [], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"crm\", \"description\": \"Manage local contacts and interaction history for operator-reviewed phone follow-up. Use lookup_contact at the start of inbound calls (automatic, using caller ID) to check if the caller is known and retrieve relevant operator-approved context. Use upsert_contact to save caller-volunteered contact details (name, email, company) when appropriate under the operator's caller notice/consent policy. Use log_interaction at the end of every call to record what happened (summary, outcome). Use context_notes for concise, relevant follow-up context; avoid sensitive, intimate, or unnecessary personal details. Do not ask robotic CRM questions; capture only details naturally relevant to the call purpose and retention policy.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup_contact\", \"upsert_contact\", \"log_interaction\", \"get_history\", \"search_contacts\", \"tag_contact\"], \"description\": \"The CRM action to perform\"}, \"phone\": {\"type\": \"string\", \"description\": \"Contact phone number in E.164 format (e.g. +14165551234)\", \"pattern\": \"^\\\\+[1-9]\\\\d{6,14}$|^$\"}, \"name\": {\"type\": \"string\", \"maxLength\": 200}, \"email\": {\"type\": \"string\", \"maxLength\": 200}, \"company\": {\"type\": \"string\", \"maxLength\": 200}, \"context_notes\": {\"type\": \"string\", \"maxLength\": 1000, \"description\": \"Concise operator-reviewed follow-up context. Avoid sensitive, intimate, or unnecessary personal details.\"}, \"summary\": {\"type\": \"string\", \"maxLength\": 500, \"description\": \"One-liner: what the call was about\"}, \"outcome\": {\"type\": \"string\", \"enum\": [\"message_left\", \"appointment_booked\", \"info_provided\", \"callback_requested\", \"transferred\", \"other\"], \"description\": \"Call outcome\"}, \"details\": {\"type\": \"object\", \"description\": \"Structured extras as key-value pairs (e.g. appointment_date, purpose)\"}, \"query\": {\"type\": \"string\", \"maxLength\": 200}, \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 50, \"default\": 10}, \"add\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}, \"remove\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}}, \"required\": [\"action\"]}}}}\n---\n\n# CRM Skill — Contact Memory for Voice Calls\n\nStores local, operator-reviewed caller context and interaction history for phone follow-up.\n\n## How It Works\n\n### On Every Inbound Call\n\n1. **Lookup** — Call `crm` with `lookup_contact` using the caller's phone number (from Twilio caller ID) only under the operator's caller notice/consent and retention policy.\n2. **If known** — Greet by name and use `context_notes` only when relevant to the call purpose. Avoid surprising rapport-building from intimate or unnecessary details.\n3. **If unknown** — Proceed normally, listen for their name.\n\n### During the Call\n\nWhen someone shares their name, email, company, or relevant follow-up details, upsert it via `crm.upsert_contact` only if that fits the operator's caller notice/consent and retention policy. Avoid collecting sensitive or unnecessary personal details.\n\n### At End of Call\n\n1. Log the interaction: `log_interaction` with summary + outcome\n2. Update context_notes with concise, relevant follow-up context, synthesizing with what was known before\n\n### On Outbound Calls\n\nSame exact flow: lookup at start, upsert + log_interaction at end.\n\n## API Reference\n\n| Action | Purpose |\n|--------|---------|\n| `lookup_contact` | Fetch contact + last 5 interactions + context_notes. Returns null if not found. |\n| `upsert_contact` | Create or update a contact by phone. Only provided fields are updated. |\n| `log_interaction` | Log a call: summary, outcome, details. Auto-creates contact if needed. |\n| `get_history` | Get past interactions for a contact (sorted newest-first). |\n| `search_contacts` | Search by name, email, company, notes. |\n| `tag_contact` | Add/remove tags (e.g. \"vip\", \"callback_later\"). |\n\n## Privacy\n\n- **Event details stay private.** Like the calendar skill, never disclose event details to callers.\n- **CRM context is personal.** The `context_notes` field is for Amber's internal memory, not for sharing call transcripts. Use it to inform conversation, not to recite it.\n- **PII storage.** Phone, name, email, company, context_notes, call summaries, and interaction metadata are stored locally in SQLite. Operators must provide appropriate caller notice/consent and retention/deletion practices. No network transmission, no external CRM by default.\n- **Review and correction.** Operators should periodically review, correct, or delete CRM entries so inaccurate transcript extraction or overly sensitive details do not persist.\n\n## Security\n\n- Synchronous SQLite (better-sqlite3) with parameterized queries — no SQL injection surface\n- Private number detection — calls from anonymous/blocked numbers are skipped entirely\n- Input validation at three levels: schema patterns, handler validation, database constraints\n- Database file created with mode 0600 (owner read/write only)\n\n## Examples\n\n**Greeting a known caller:**\n```\nAmber: \"Hi Sarah, good to hear from you again. I have you down as preferring afternoon callbacks.\"\n[context_notes remembered: \"Prefers afternoon callbacks for appointment changes.\"]\n```\n\n**Capturing relevant follow-up context:**\n```\nCaller: \"By the way, I got married last month!\"\nAmber: [only records this if it is relevant and appropriate under the operator's retention policy]\nAmber (aloud): \"That's wonderful! Congrats!\"\n```\n\n**End-of-call log:**\n```\nAmber: [calls log_interaction: summary=\"Called to reschedule Friday appointment\", outcome=\"appointment_booked\"]\nAmber: [calls upsert_contact with context_notes: \"Prefers afternoon callbacks. Usually calls to reschedule appointments.\"]\n```\n\nFile v5.5.50:amber-skills/send-message/SKILL.md\n\n---\nname: send-message\nversion: 1.0.0\ndescription: \"Leave a message for the operator — saved to call log and delivered via the operator's preferred messaging channel\"\nmetadata: {\"amber\": {\"capabilities\": [\"act\"], \"confirmation_required\": true, \"confirmation_prompt\": \"Would you like me to leave that message?\", \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [], \"telegram\": true, \"openclaw_action\": true, \"network\": false}, \"function_schema\": {\"name\": \"send_message\", \"description\": \"Leave a message for the operator. The message will be saved to the call log and sent to the operator via their messaging channel. IMPORTANT: Always confirm with the caller before calling this function — ask 'Would you like me to leave that message?' and only proceed after they confirm.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"message\": {\"type\": \"string\", \"description\": \"The caller's message to leave for the operator\", \"maxLength\": 1000}, \"caller_name\": {\"type\": \"string\", \"description\": \"The caller's name if they provided it\", \"maxLength\": 100}, \"callback_number\": {\"type\": \"string\", \"description\": \"A callback number if the caller provided one\", \"maxLength\": 30}, \"urgency\": {\"type\": \"string\", \"enum\": [\"normal\", \"urgent\"], \"description\": \"Whether the caller indicated this is urgent\"}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Must be true — only set after the caller has explicitly confirmed their message and given permission to send it. The router will reject this call if confirmed is not true.\"}}, \"required\": [\"message\", \"confirmed\"]}}}}\n---\n\n# Send Message\n\nAllows callers to leave a message for the operator. This skill implements the\n\"leave a message\" pattern that is standard in phone-based assistants.\n\n## Flow\n\n1. Caller indicates they want to leave a message\n2. Amber confirms: \"Would you like me to leave that message?\"\n3. On confirmation, the message is:\n   - **Always** saved to the call log first (audit trail)\n   - **Then** delivered to the operator via their configured messaging channel\n\n## Security\n\n- The recipient is determined by the operator's configuration — never by caller input\n- No parameter in the schema accepts a destination or recipient\n- Confirmation is required before sending (enforced programmatically at the router layer — the router checks `params.confirmed === true` before invoking; LLM prompt guidance is an additional layer, not the sole enforcement)\n- Message content is sanitized (max length, control characters stripped)\n\n## Delivery Failure Handling\n\n- If messaging delivery fails, the call log entry is marked with `delivery_failed`\n- The operator's assistant can check for undelivered messages during heartbeat checks\n- Amber tells the caller \"I've noted your message\" — never promises a specific delivery channel\n\nFile v5.5.50:packaging/cowork/skills/calendar/SKILL.md\n\n---\nname: calendar\ndescription: >\n  Check availability and create calendar entries. Used during calls to\n  book appointments and check schedule conflicts. Use when the user or\n  a caller needs to schedule something or check availability.\n---\n\n# Calendar\n\nQuery and manage the operator's calendar during or outside of calls.\n\n## MCP Tools\n\n### calendar_query\nLook up or create calendar events.\n- `action` (string, required): \"lookup\" or \"create\"\n- `query` (string, required for lookup): Natural language query (e.g., \"am I free Tuesday at 3pm?\")\n- `title` (string, required for create): Event title\n- `start` (string, required for create): Start time (ISO 8601)\n- `end` (string, required for create): End time (ISO 8601)\n- `calendar` (string): Which calendar to use (defaults to operator's primary)\n- `location` (string): Event location\n- `notes` (string): Event notes\n\n## Guidelines\n\n- When checking availability during a call, present options naturally (\"I see an opening at 2pm and 4pm — which works better?\")\n- Always confirm the final date, time, and details before creating an event\n- Include only the minimum scheduling context needed in event notes (for example, requester name and appointment purpose).\n- Do not store sensitive personal, medical, financial, legal, or unnecessary caller details in calendar notes unless the caller explicitly confirms those details are needed for the appointment.\n\nFile v5.5.50:packaging/cowork/skills/call-screening/SKILL.md\n\n---\nname: call-screening\ndescription: >\n  Screen incoming phone calls with an AI receptionist. Amber answers calls,\n  identifies the caller, determines the purpose, takes a message, and\n  delivers a structured summary. Use when the user wants to set up call\n  screening, check screened call results, or customize screening behavior.\n---\n\n# Call Screening\n\nAmber acts as an AI receptionist for inbound calls. She answers professionally,\ngathers information, and delivers structured summaries — so you only pick up\ncalls that matter.\n\nPrivacy: screening can process caller audio/metadata through your configured providers and may produce local transcripts/summaries. Configure caller notice/consent, retention, and access controls before production use.\n\n## Screening Flow\n\n1. **Greeting** — Amber answers with a customizable greeting\n2. **Identification** — Asks who's calling and what it's regarding\n3. **Information gathering** — Collects caller name, callback number, message\n4. **CRM lookup** — Checks if the caller is a known contact (auto-enriches context)\n5. **Calendar check** — If the caller wants to book time, checks availability\n6. **Summary delivery** — Sends a structured summary with all captured details\n\n## MCP Tools\n\n### start_screening\nEnable inbound call screening on the configured Twilio number.\n\n### stop_screening\nDisable screening (calls ring through normally).\n\n### get_screening_status\nCheck whether screening is currently active.\n\n## Customization\n\nThe screening personality, greeting, and behavior are defined in AGENT.md.\nUsers can edit this file to:\n- Change the assistant's name and personality\n- Customize the greeting message\n- Set business hours and after-hours behavior\n- Define which callers should be put through vs. screened\n- Add organization-specific context (company name, services, etc.)\n\nFile v5.5.50:packaging/cowork/skills/contacts/SKILL.md\n\n---\nname: contacts\ndescription: >\n  Look up contacts by name to resolve phone numbers before making calls.\n  Use when the user says \"call John\" instead of providing a phone number.\n---\n\n# Contacts\n\nResolve contact names to phone numbers for outbound calls.\n\n## Flow\n\n1. User says \"call [name]\" or \"/amber:call [name] [objective]\"\n2. Look up the name in the CRM via `crm(action: \"lookup\", identifier: \"name\")`\n3. If found, use the stored phone number\n4. If multiple matches, present options and let the user choose\n5. If not found, ask the user for the phone number\n\n## Guidelines\n\n- Be fuzzy with name matching — \"John\" should match \"John Smith\"\n- If ambiguous, always confirm before dialing (\"I found John Smith at +1-416-555-1234 — is that right?\")\n\nFile v5.5.50:packaging/cowork/skills/crm/SKILL.md\n\n---\nname: crm\ndescription: >\n  Contact memory and interaction log. Remembers callers across calls,\n  stores personal context, and logs every conversation. Use when looking\n  up a contact, adding notes about someone, or reviewing interaction history.\n---\n\n# CRM — Contact Memory\n\nAmber remembers everyone she talks to. The CRM stores contact details,\npersonal context, and a log of every interaction.\n\nPrivacy: CRM storage is local and should be opt-in. Enable it only after configuring caller notice/consent, retention/deletion practices, and access controls for the SQLite database.\n\n## MCP Tools\n\n### crm\nManage contacts and interaction history.\n- `action` (string, required): \"lookup\", \"create\", \"update\", \"log\", \"history\"\n- `identifier` (string): Phone number or name to look up\n- `name` (string): Contact name\n- `phone` (string): Phone number\n- `email` (string): Email address\n- `notes` (string): Personal context or notes about the contact\n- `tags` (array): Tags for categorization (e.g., [\"client\", \"vendor\", \"friend\"])\n\n## Automatic Behavior\n\n- On inbound calls, Amber automatically looks up the caller by phone number\n- If the caller is known, their context and history are loaded into the conversation\n- After every call, an interaction log entry is created with: date, summary, sentiment, outcome\n- New callers are added to the CRM only when CRM persistence is enabled and appropriate under your caller notice/consent policy\n\n## Guidelines\n\n- Use the CRM only for relevant follow-up context; avoid surprising personalization from sensitive or unnecessary personal details\n- Keep notes professional but useful — preferences, important dates, relationship context\n- Never expose CRM data to callers beyond what's socially appropriate\n\nFile v5.5.50:packaging/cowork/skills/phone-calls/SKILL.md\n\n---\nname: phone-calls\ndescription: >\n  Make and manage real phone calls through Twilio. Handles outbound calls\n  with a stated objective, monitors call progress, and returns transcripts\n  and summaries. Use when the user wants to call someone, check on a call,\n  or review call history.\n---\n\n# Phone Calls\n\nAmber can make and receive real phone calls via Twilio. This skill covers\nthe core telephony capabilities.\n\n## MCP Tools\n\n### make_call\nInitiate an outbound phone call.\n- `to` (string, required): Phone number in E.164 format (e.g., +14165551234)\n- `objective` (string, required): What to accomplish on the call\n- `mode` (string): \"conversation\" (default) or \"message\" (one-way delivery)\n\n### get_call_status\nCheck the status of an active or recent call.\n- `callId` (string, required): The call ID returned by make_call\n\n### end_call\nTerminate an active call.\n- `callId` (string, required): The call ID to end\n\n### get_call_history\nRetrieve recent call logs with transcripts.\n- `filter` (string): \"all\", \"inbound\", \"outbound\", \"missed\"\n- `limit` (number): Number of calls to return (default: 10)\n\n## Guidelines\n\n- Always confirm the recipient number and call objective with the user before dialing\n- If the objective involves payment, deposits, or financial commitments, explicitly ask the user for approval first\n- After each call, provide a summary including: who was called, outcome, key information exchanged, and caller sentiment\n- For outbound calls, Amber pursues the stated objective autonomously — she's not just reading a script\n- Calls have real-world consequences. Treat every call as if you're representing the user professionally\n\nFile v5.5.50:packaging/hermes/SKILL.md\n\n---\nname: amber-phone-agent\ndescription: Give Hermes Agent real phone capabilities through Amber's Twilio/OpenAI voice bridge and MCP tools.\nversion: \"5.5.39\"\nlicense: MIT\ncompatibility: Node.js 20+, Twilio account, OpenAI API key, Hermes Agent with MCP support\nplatforms: [macos, linux]\nmetadata:\n  author: batthis\n  repository: https://github.com/batthis/amber-openclaw-voice-agent\n  hermes:\n    tags: [phone, voice, twilio, openai, mcp, receptionist, calendar, crm]\n    category: communication\n    requires_toolsets: [mcp]\n    config:\n      - key: AMBER_RUNTIME_DIR\n        description: Absolute path to the Amber runtime directory containing dist/mcp-server.js\n        default: ~/amber-openclaw-voice-agent/runtime\n        prompt: Path to Amber runtime directory\n---\n\n# Amber — Phone-Capable Voice Agent for Hermes\n\n## When to Use\n\nUse Amber when the user wants Hermes to interact with the telephone network:\n\n- prepare or place an outbound phone call after explicit user confirmation\n- screen inbound calls through a Twilio number\n- check call history, transcripts, or summaries\n- resolve contacts before calling someone\n- check availability or create calendar entries during a phone workflow\n- use local CRM context for caller follow-up\n\nAmber is a sensitive communications system. Calls are real, may involve third parties, may be transcribed, and may be logged locally. Treat all caller details, transcripts, phone numbers, contact data, and calendar data as private.\n\n## Required Runtime\n\nThis skill is an instruction/activation wrapper for Hermes. The actual phone capability is provided by Amber's Node runtime and MCP server.\n\nBefore using this skill, install and configure Amber:\n\n```bash\ngit clone https://github.com/batthis/amber-openclaw-voice-agent.git\ncd amber-openclaw-voice-agent/runtime\nnpm install\nnpm run setup\nnpm run build\nnpm start\n```\n\nDuring setup, choose **Hermes Agent** when asked for the target platform.\n\n## Connect Amber MCP to Hermes\n\nAdd Amber's MCP server to your Hermes config, adjusting the path to your clone:\n\n```yaml\nmcp_servers:\n  amber_voice:\n    command: \"node\"\n    args:\n      - \"/absolute/path/to/amber-openclaw-voice-agent/runtime/dist/mcp-server.js\"\n    env:\n      AMBER_BRIDGE_URL: \"http://127.0.0.1:8000\"\n      BRIDGE_API_TOKEN: \"\"\n```\n\nRestart Hermes or run `/reload-mcp`, then ask Hermes which MCP tools are available. Amber should expose tools such as `make_call`, `get_call_status`, `get_call_history`, `contacts_lookup`, `calendar_query`, `crm`, and `bridge_health`.\n\n## Safety Rules\n\n### Outbound Calls\n\nNever place a call on the first step. Always:\n\n1. Clarify the recipient and objective.\n2. Resolve contact names with `contacts_lookup` where possible.\n3. Show the user the exact recipient, phone number, and objective.\n4. Only call `make_call` with `confirmed=true` after the user explicitly confirms.\n\nIf the call may involve a payment, deposit, contract, medical/legal/financial advice, or any irreversible commitment, stop and ask for explicit user approval first.\n\n### Inbound Screening\n\nWhen Amber screens calls, collect only what is needed:\n\n- caller name\n- callback number\n- message or purpose\n- any scheduling details the caller volunteers\n\nDo not solicit unnecessary sensitive personal data.\n\n### Calendar\n\nFor calendar lookups, disclose only free/busy availability. Do not reveal event names, locations, attendees, or private details.\n\nFor calendar creation, confirm title, date, start/end time, location/notes, and the person requesting the booking before creating the event.\n\n### CRM / Memory\n\nUse CRM context only when relevant and benign. Do not surface sensitive health, family, legal, financial, political/religious, intimate, or surprising details unless the caller raises them first or the task clearly requires it.\n\n## Useful Prompts\n\n- \"Use Amber to check whether the voice bridge is healthy.\"\n- \"Use Amber to find Miriam in contacts and prepare a call, but do not dial until I confirm.\"\n- \"Show my recent inbound call summaries.\"\n- \"Start inbound call screening.\"\n- \"Check if I am free tomorrow afternoon, but do not reveal event details.\"\n\n## Verification\n\nAfter setup, verify in this order:\n\n1. `npm start` shows the Amber bridge listening on `http://127.0.0.1:8000`.\n2. `curl http://127.0.0.1:8000/healthz` returns `{ \"ok\": true }`.\n3. Hermes shows the Amber MCP tools after restart or `/reload-mcp`.\n4. `bridge_health` succeeds from Hermes.\n5. A test inbound call reaches Amber.\n\n## Pitfalls\n\n- If Hermes cannot see Amber tools, check the `mcp_servers` path and run `/reload-mcp`.\n- If calls ring but Amber does not speak, check `PUBLIC_BASE_URL`, your public HTTPS tunnel or domain, Twilio webhooks, and OpenAI webhook settings.\n- If contact lookup fails on macOS, run `npm run sync-contacts` from the Amber runtime directory.\n- If calendar access fails on macOS, grant the helper access in System Settings → Privacy & Security → Calendar.\n\nFile v5.5.50:SKILL.md\n\n---\nname: amber-voice-assistant\ntitle: \"Amber — Give Your Agent Real Phone Capabilities\"\ndescription: \"Give your agent a phone number. Amber answers calls, places confirmed outbound calls, completes phone tasks, logs transcripts, and exposes MCP tools.\"\nhomepage: https://github.com/batthis/amber-openclaw-voice-agent\nmetadata: {\"openclaw\":{\"emoji\":\"☎️\",\"requires\":{\"env\":[],\"optionalEnv\":[\"AMBER_ENABLE_OUTBOUND_CALLS\",\"AMBER_REALTIME_MODEL\",\"AMBER_REALTIME_VAD_THRESHOLD\",\"AMBER_REALTIME_VAD_PREFIX_PADDING_MS\",\"AMBER_REALTIME_VAD_SILENCE_DURATION_MS\",\"AMBER_CRM_ENABLED\",\"AMBER_CRM_TRANSCRIPT_ENRICHMENT\",\"OPENCLAW_GATEWAY_URL\",\"TWILIO_WEBHOOK_STRICT\",\"VOICE_PROVIDER\",\"VOICE_WEBHOOK_SECRET\",\"ASSISTANT_NAME\",\"OPERATOR_NAME\",\"AMBER_CRM_DB_PATH\",\"AGENT_MD_PATH\",\"DEFAULT_CALENDAR\",\"AMBER_CONTACTS_EXTENDED\"],\"anyBins\":[\"node\",\"ical-query\"]},\"permissions\":{\"network\":true,\"env\":true,\"webhooks\":true,\"localFiles\":[\"runtime/logs/\",\"runtime/contacts-cache.json\",\"~/.config/amber/crm.sqlite\"],\"localBinaries\":[\"node\",\"ical-query\"],\"mcpTools\":[\"prepare_call\",\"start_call\",\"call_history\",\"crm\",\"contacts_lookup\",\"calendar\",\"screening_control\",\"bridge_health\"],\"externalServices\":[\"Twilio or compatible voice provider\",\"OpenAI Realtime/API\",\"optional OpenClaw Gateway\"]},\"install\":[{\"id\":\"runtime\",\"kind\":\"node\",\"cwd\":\"runtime\",\"label\":\"Install Amber runtime (cd runtime && npm ci && npm run build)\"},{\"id\":\"crm-skill\",\"kind\":\"node\",\"cwd\":\"amber-skills/crm\",\"label\":\"Install optional CRM skill dependencies (cd amber-skills/crm && npm ci)\"}]}}\n---\n\n# Amber — Give Your Agent Real Phone Capabilities\n\n## Overview\n\nAmber gives any OpenClaw deployment **a real phone number and the tools to complete calls**. It ships with a **production-ready Twilio + OpenAI Realtime bridge** (`runtime/`) for confirmed phone workflows: answer callers, screen calls, place approved outbound calls, look up contacts, schedule appointments, take messages, log transcripts, and hand call-critical decisions back to OpenClaw through MCP tools.\n\nUse it when you want an agent to do the plain-English phone job: call this business, ask this question, book the slot, leave the message, screen this caller, or show me what happened. Amber is built for operators who want the phone capability layer under their own Twilio or compatible voice account, with local logs, a local dashboard, and confirmation gates before outbound calls or calendar writes.\n\nAmber is a sensitive communications system. It can process call audio/transcripts through configured voice and AI providers, store local call logs, maintain a local CRM, read/write the operator calendar, expose local MCP tools, and optionally use an Apple Contacts export for name-to-number resolution. Operators should configure caller notice/consent, retention/deletion practices, and least-privilege provider credentials before production use.\n\nPrivacy defaults: local CRM lookup/logging is disabled unless `AMBER_CRM_ENABLED=true`, and post-call transcript enrichment is disabled unless `AMBER_CRM_TRANSCRIPT_ENRICHMENT=true`. Enable those only after setting caller notice/consent and retention/deletion practices.\n\n**✨ New in v5.5.50:** Sharper ClawHub positioning: Amber is now described first as the phone-number-and-call-completion layer for agents, with inbound answering, confirmed outbound calling, scheduling, transcripts, and MCP tools visible before the deeper architecture.\n\n**✨ v5.4.0:** Amber ships as an **MCP plugin** with 9 tools — prepare confirmed calls by name, check call history, query CRM contacts, manage calendar, and control call screening. It works with Claude Desktop/Cowork and other MCP-capable clients or agent harnesses once configured. Includes Apple Contacts integration and a code-enforced call confirmation safeguard to prevent wrong-number dials.\n\n**✨ Also:** Interactive setup wizard (`npm run setup`) validates credentials in real-time and generates a working `.env` file — no manual configuration needed. Once setup is complete, Amber is prompt-based: ask your OpenClaw agent to prepare confirmed calls, answer/screen callers, schedule confirmed appointments, or handle phone workflows in natural language.\n\n## See it in action\n\n![Setup Wizard Demo](demo/demo.gif)\n\n**[▶️ Watch the interactive demo on asciinema.org](https://asciinema.org/a/l1nOHktunybwAheQ)** (copyable text, adjustable speed)\n\n*The interactive wizard validates credentials, detects ngrok, and generates a complete `.env` file in minutes.*\n\n### What's included\n\n- **Phone number + runtime bridge** (`runtime/`) — a complete Node.js server that connects a Twilio or compatible phone number to OpenAI Realtime with OpenClaw brain-in-the-loop\n- **Amber Skills** (`amber-skills/`) — modular mid-call capabilities (CRM, calendar, log & forward message) with a spec for building your own\n- **Built-in CRM** — local SQLite contact database; Amber can greet callers by name and use operator-approved context naturally on calls, with operator review/correction responsibility\n- **Call log dashboard** (`dashboard/`) — browse call history, transcripts, captured messages, estimated costs, and one-touch localhost test calls with regular/mini Realtime model selection\n- **Setup & validation scripts** — preflight checks, env templates, quickstart runner\n- **Architecture docs & troubleshooting** — call flow diagrams, common failure runbooks\n- **Safety guardrails** — outbound calls require code-enforced confirmation; payment escalation, consent boundaries, and explicit confirmation for calendar writes are documented\n\n## 🔌 Amber Skills — Extensible by Design\n\nAmber ships with a growing library of **Amber Skills** — modular capabilities that plug directly into live voice conversations. Each skill exposes a structured function that Amber can call mid-call, letting you compose powerful voice workflows without touching the bridge code.\n\n### 👤 CRM — Contact Memory *(v5.3.0)*\n\nAmber can maintain operator-reviewed caller memory across calls, limited to relevant follow-up context under the operator's notice, consent, and retention policy.\n\n- **Opt-in runtime management** — set `AMBER_CRM_ENABLED=true` to enable automatic known-caller lookup and interaction logging\n- **Personalized greeting** — known callers can be greeted by name; optional notes are used only when relevant to the call objective\n- **Optional enrichment** — set `AMBER_CRM_TRANSCRIPT_ENRICHMENT=true` to allow post-call extraction to propose caller details and notes for the local CRM\n- **Operator review expected** — review, correct, or delete CRM records periodically so bad transcript extraction, misleading caller input, or overly sensitive details do not persist indefinitely\n- **Symmetric** — works identically for inbound and outbound calls\n- **Local SQLite CRM** — contact memory is stored at `~/.config/amber/crm.sqlite`; CRM records are not cloud-hosted. Live call audio/transcripts still pass through Twilio/OpenAI as part of the phone bridge. Tell callers when calls are handled by an AI assistant and may be logged/used for follow-up, according to your local consent requirements.\n- **Native dependency** — requires `better-sqlite3` (native build). macOS: `sudo xcodebuild -license accept` before `npm install`. Linux: `build-essential` + `python3`.\n\n### 📅 Calendar\n\nQuery the operator's calendar for availability or schedule a new event — all during a live call.\n\n- **Availability lookups** — free/busy slots for today, tomorrow, this week, or any specific date\n- **Event creation** — create calendar events from a phone conversation only after the required details are collected and the caller explicitly confirms the slot\n- **Privacy by default** — callers are only told whether the operator is free or busy; event titles, names, and locations are never disclosed\n- Powered by `ical-query` — local-only, zero network latency\n\n### 📬 Log & Forward Message\n\nLet callers leave a message that is automatically saved and forwarded to the operator.\n\n- Captures the caller's message, name, and optional callback number\n- **Always saves to the call log first** (audit trail), then delivers via the operator's configured messaging channel\n- Confirmation-gated — Amber confirms with the caller before sending\n- Delivery destination is operator-configured — callers cannot redirect messages\n\n### Build Your Own Skills\n\nAmber's skill system is designed to grow. Each skill is a self-contained directory with a `SKILL.md` (metadata + function schema) and a `handler.js`. You can:\n\n- **Customize the included skills** to fit your own setup\n- **Build new skills** for your use case — CRM lookups, inventory checks, custom notifications, anything callable mid-call\n- **Share skills** with the OpenClaw community via [ClawHub](https://clawhub.com)\n\nSee [`amber-skills/`](amber-skills/) for examples and the full specification to get started.\n\n**Contacts privacy:** Apple Contacts sync is opt-in. By default it exports only names and phone numbers needed for call-by-name. Set `AMBER_CONTACTS_EXTENDED=true` only if you explicitly want extra local-only fields such as email, organization, relationships, addresses, and notes in `runtime/contacts-cache.json`.\n\n> **Note:** Each skill's `handler.js` is reviewed against its declared permissions. When building or installing third-party skills, review the handler source as you would any Node.js module.\n\n### Call log dashboard\n\n```bash\ncd dashboard && node scripts/serve.js   # → http://localhost:8787\n```\n\n- **⬇ Sync button** (green) — immediately pulls new calls from `runtime/logs/` and refreshes the dashboard. Use this right after a call ends rather than waiting for the background watcher.\n- **↻ Refresh button** (blue) — reloads existing data from disk without re-processing logs.\n- **One-touch test calls** — when opened through `node scripts/serve.js`, the dashboard can call a test number through the local Amber bridge and choose `gpt-realtime` or `gpt-realtime-mini` per call.\n- **Cost visibility** — estimates telephony and Realtime token cost from call duration and saved usage metadata; rates are editable in the dashboard.\n- Background watcher (`node scripts/watch.js`) auto-syncs every 30 seconds when running.\n\n## Why Amber\n\n- **Ship a voice assistant in minutes** — `npm install`, configure `.env`, `npm start`\n- **Give an agent a real phone number** — callers can reach it, and it can place confirmed outbound calls for concrete phone tasks\n- Full inbound screening: greeting, message-taking, appointment booking with calendar integration\n- Outbound calls with structured call plans (reservations, inquiries, follow-ups), with confirmation gates and a runtime disable switch\n- **OpenClaw gateway lookup (least-privilege)** — voice agent consults your OpenClaw gateway only for call-critical needs (availability checks, confirmed scheduling, required factual lookups), not for unrelated tasks\n- VAD tuning + verbal fillers to keep conversations natural (no dead air during lookups)\n- Fully configurable: assistant name, operator info, org name, calendar, screening style — all via env vars\n- Operator safety guardrails for approvals/escalation/payment handling\n\n## Personalization requirements\n\nBefore deploying, users must personalize:\n- assistant name/voice and greeting text,\n- own Twilio number and account credentials,\n- own OpenAI project + webhook secret,\n- own OpenClaw gateway/session endpoint,\n- own call safety policy (approval, escalation, payment handling).\n\nDo not reuse example values from another operator.\n\n## 5-minute quickstart\n\n### Option A: Interactive Setup Wizard (recommended) ✨\n\nThe easiest way to get started:\n\n1. `cd runtime`\n2. `npm run setup`\n3. Follow the interactive prompts — the wizard will:\n   - Validate your Twilio and OpenAI credentials in real-time\n   - Auto-detect and configure ngrok if available\n   - Ask whether to enable opt-in local CRM caller memory\n   - Generate a working `.env` file\n   - Optionally install dependencies and build the project\n4. Configure your Twilio webhook (wizard shows you the exact URL)\n5. Start the server: `npm start`\n6. Call your Twilio number — your voice assistant answers!\n\n**Benefits:**\n- Real-time credential validation (catch errors before you start)\n- No manual `.env` editing\n- Automatic ngrok detection and setup\n- Step-by-step guidance with helpful links\n\n### Option B: Manual setup\n\n1. From the Amber skill folder: `cd runtime && npm ci`\n2. `cd ../amber-skills/crm && npm ci` if you plan to enable CRM caller memory.\n3. `cd ../..` and copy `references/env.example` to `runtime/.env`, then fill in your values.\n4. Set `AMBER_CRM_ENABLED=true` only if you want local caller memory/known-caller greetings.\n5. `cd runtime && npm run build && npm start`\n6. Point your Twilio voice webhook to `https://<your-domain>/twilio/inbound`\n7. Call your Twilio number — your voice assistant answers!\n\n### Option C: Validation-only (existing setup)\n\n1. Copy `references/env.example` to your own `.env` and replace placeholders.\n2. Export required variables (`TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_CALLER_ID`, `OPENAI_API_KEY`, `OPENAI_PROJECT_ID`, `OPENAI_WEBHOOK_SECRET`, `PUBLIC_BASE_URL`).\n3. Run quick setup:\n   `scripts/setup_quickstart.sh`\n4. If preflight passes, run one inbound and one outbound smoke test.\n5. Only then move to production usage.\n\n## Credential scope (recommended hardening)\n\nUse least-privilege credentials for every provider:\n\n- **Twilio:** use a dedicated subaccount for Amber and rotate auth tokens regularly.\n- **OpenAI:** use a dedicated project API key for this runtime only; avoid reusing keys from unrelated apps.\n- **OpenClaw Gateway token:** only set `OPENCLAW_GATEWAY_TOKEN` if you need brain-in-the-loop lookups; keep token scope minimal.\n- **Dependency integrity:** runtime dependencies are pinned by `runtime/package-lock.json`; review dependency changes before publishing updates.\n- **Secrets in logs:** never print full credentials in scripts, setup output, or call transcripts.\n- **Setup wizard validation scope:** credential checks call only official Twilio/OpenAI API endpoints over HTTPS for auth verification; no arbitrary exfiltration endpoints are used.\n\nThese controls reduce blast radius if a host or config file is exposed.\n\n## Safe defaults\n\n- Outbound calling is enabled by default for the full phone-agent experience. Set `AMBER_ENABLE_OUTBOUND_CALLS=false` to disable the outbound call endpoint.\n- Require explicit approval before outbound calls. **Note on confirmation enforcement:** For MCP-initiated outbound calls (`make_call`), confirmation is enforced at the MCP server layer in code (the tool returns a preview and requires `confirmed=true` on a second call before dialing) — this is not LLM-only instruction. The LLM instruction layer provides an additional reminder, but the code gate is the primary enforcement mechanism.\n- If payment/deposit is requested, stop and escalate to the human operator.\n- Keep greeting short and clear.\n- Use timeout + graceful fallback when `ask_openclaw` is slow/unavailable.\n\n## Workflow\n\n1. **Confirm scope for V1**\n   - Include only stable behavior: call flow, bridge behavior, fallback behavior, and setup steps.\n   - Exclude machine-specific secrets and private paths.\n\n2. **Document architecture + limits**\n   - Read `references/architecture.md`.\n   - Keep claims realistic (latency varies; memory lookups are best-effort).\n\n3. **Run release checklist**\n   - Read `references/release-checklist.md`.\n   - Validate config placeholders, safety guardrails, and failure handling.\n\n4. **Smoke-check runtime assumptions**\n   - Run `scripts/validate_voice_env.sh` on the target host.\n   - Fix missing env/config before publishing.\n\n5. **Publish**\n   - Publish to ClawHub (example):  \n     `clawhub publish <skill-folder> --slug amber-voice-assistant --name \"Amber Voice Assistant\" --version 1.0.0 --tags latest --changelog \"Initial public release\"`\n   - Optional: run your local skill validator/packager before publishing.\n\n6. **Ship updates**\n   - Publish new semver versions (`1.0.1`, `1.1.0`, `2.0.0`) with changelogs.\n   - Keep `latest` on the recommended version.\n\n## Troubleshooting (common)\n\n- **\"Missing env vars\"** → re-check `.env` values and re-run `scripts/validate_voice_env.sh`.\n- **\"Call connects but assistant is silent\"** → verify TTS model setting and provider auth.\n- **\"ask_openclaw timeout\"** → verify gateway URL/token and increase timeout conservatively.\n- **\"CRM lookup fails after a Node upgrade\"** → run `cd amber-skills/crm && npm rebuild better-sqlite3`, then restart the Amber runtime.\n- **\"Webhook unreachable\"** → verify tunnel/domain and Twilio webhook target.\n\n## Guardrails for public release\n\n- Never publish secrets, tokens, phone numbers, webhook URLs with credentials, or personal data.\n- Include explicit safety rules for outbound calls, payments, and escalation.\n- Mark V1 as beta if conversational quality/latency tuning is ongoing.\n\n## Install safety notes\n\n- Amber does **not** execute arbitrary install-time scripts from this repository.\n- Runtime install uses standard Node dependency installation in `runtime/`, with dependencies pinned in `runtime/package-lock.json`.\n- CRM uses `better-sqlite3` (native module), which compiles locally on your machine.\n- Review `runtime/package.json` dependencies before deployment in regulated environments.\n\n## Resources\n\n- **Runtime bridge:** `runtime/` (full source + README)\n- Architecture and behavior notes: `references/architecture.md`\n- Release gate: `references/release-checklist.md`\n- Env template: `references/env.example`\n- Quick setup runner: `scripts/setup_quickstart.sh`\n- Env/config validator: `scripts/validate_voice_env.sh`\n\nFile v5.5.50:skills/amber-phone-agent/SKILL.md\n\n---\nname: amber-phone-agent\ndescription: Give Hermes Agent real phone capabilities through Amber's Twilio/OpenAI voice bridge and MCP tools.\nversion: \"5.5.50\"\nlicense: MIT\ncompatibility: Node.js 20+, Twilio account, OpenAI API key, Hermes Agent with MCP support\nplatforms: [macos, linux]\nmetadata:\n  author: batthis\n  repository: https://github.com/batthis/amber-openclaw-voice-agent\n  hermes:\n    tags: [phone, voice, twilio, openai, mcp, receptionist, calendar, crm]\n    category: communication\n    requires_toolsets: [mcp]\n    config:\n      - key: AMBER_RUNTIME_DIR\n        description: Absolute path to the Amber runtime directory containing dist/mcp-server.js\n        default: ~/amber-openclaw-voice-agent/runtime\n        prompt: Path to Amber runtime directory\n---\n\n# Amber — Phone-Capable Voice Agent for Hermes\n\n## When to Use\n\nUse Amber when the user wants Hermes to interact with the telephone network:\n\n- prepare or place an outbound phone call after explicit user confirmation\n- screen inbound calls through a Twilio number\n- check call history, transcripts, or summaries\n- resolve contacts before calling someone\n- check availability or create calendar entries during a phone workflow\n- use local CRM context for caller follow-up\n\nAmber is a sensitive communications system. Calls are real, may involve third parties, may be transcribed, and may be logged locally. Treat all caller details, transcripts, phone numbers, contact data, and calendar data as private.\n\n## Required Runtime\n\nThis skill is an instruction/activation wrapper for Hermes. The actual phone capability is provided by Amber's Node runtime and MCP server.\n\nBefore using this skill, install and configure Amber:\n\n```bash\ngit clone https://github.com/batthis/amber-openclaw-voice-agent.git\ncd amber-openclaw-voice-agent/runtime\nnpm install\nnpm run setup\nnpm run build\nnpm start\n```\n\nDuring setup, choose **Hermes Agent** when asked for the target platform.\n\n## Connect Amber MCP to Hermes\n\nAdd Amber's MCP server to your Hermes config, adjusting the path to your clone:\n\n```yaml\nmcp_servers:\n  amber_voice:\n    command: \"node\"\n    args:\n      - \"/absolute/path/to/amber-openclaw-voice-agent/runtime/dist/mcp-server.js\"\n    env:\n      AMBER_BRIDGE_URL: \"http://127.0.0.1:8000\"\n      BRIDGE_API_TOKEN: \"\"\n```\n\nRestart Hermes or run `/reload-mcp`, then ask Hermes which MCP tools are available. Amber should expose tools such as `make_call`, `get_call_status`, `get_call_history`, `contacts_lookup`, `calendar_query`, `crm`, and `bridge_health`.\n\n## Safety Rules\n\n### Outbound Calls\n\nNever place a call on the first step. Always:\n\n1. Clarify the recipient and objective.\n2. Resolve contact names with `contacts_lookup` where possible.\n3. Show the user the exact recipient, phone number, and objective.\n4. Only call `make_call` with `confirmed=true` after the user explicitly confirms.\n\nIf the call may involve a payment, deposit, contract, medical/legal/financial advice, or any irreversible commitment, stop and ask for explicit user approval first.\n\n### Inbound Screening\n\nWhen Amber screens calls, collect only what is needed:\n\n- caller name\n- callback number\n- message or purpose\n- any scheduling details the caller volunteers\n\nDo not solicit unnecessary sensitive personal data.\n\n### Calendar\n\nFor calendar lookups, disclose only free/busy availability. Do not reveal event names, locations, attendees, or private details.\n\nFor calendar creation, confirm title, date, start/end time, location/notes, and the person requesting the booking before creating the event.\n\n### CRM / Memory\n\nUse CRM context only when relevant and benign. Do not surface sensitive health, family, legal, financial, political/religious, intimate, or surprising details unless the caller raises them first or the task clearly requires it.\n\n## Useful Prompts\n\n- \"Use Amber to check whether the voice bridge is healthy.\"\n- \"Use Amber to find Miriam in contacts and prepare a call, but do not dial until I confirm.\"\n- \"Show my recent inbound call summaries.\"\n- \"Start inbound call screening.\"\n- \"Check if I am free tomorrow afternoon, but do not reveal event details.\"\n\n## Verification\n\nAfter setup, verify in this order:\n\n1. `npm start` shows the Amber bridge listening on `http://127.0.0.1:8000`.\n2. `curl http://127.0.0.1:8000/healthz` returns `{ \"ok\": true }`.\n3. Hermes shows the Amber MCP tools after restart or `/reload-mcp`.\n4. `bridge_health` succeeds from Hermes.\n5. A test inbound call reaches Amber.\n\n## Pitfalls\n\n- If Hermes cannot see Amber tools, check the `mcp_servers` path and run `/reload-mcp`.\n- If calls ring but Amber does not speak, check `PUBLIC_BASE_URL`, your public HTTPS tunnel or domain, Twilio webhooks, and OpenAI webhook settings.\n- If contact lookup fails on macOS, run `npm run sync-contacts` from the Amber runtime directory.\n- If calendar access fails on macOS, grant the helper access in System Settings → Privacy & Security → Calendar.\n\nFile v5.5.50:dashboard/README.md\n\n# Amber Voice Assistant Call Log Dashboard\n\nA beautiful web dashboard for viewing and managing call logs from the Amber Voice Assistant (Twilio/OpenAI SIP Bridge).\n\n## Features\n\n- 📞 Timeline view of all calls (inbound/outbound)\n- 📝 Full transcript display with captured messages\n- 📊 Statistics and filtering\n- 🔍 Search by name, number, or transcript content\n- 🔔 Follow-up tracking with localStorage persistence\n- ☎️ One-touch localhost test calls through the Amber bridge\n- 💵 Editable cost estimates from call duration and Realtime token usage\n- 🎚️ Per-test-call Realtime model switch for regular or mini\n- ⚡ Auto-refresh when data changes (every 30s)\n\n## Privacy and Access Control\n\nThis dashboard displays call logs, transcripts, captured messages, callback numbers, and contact-resolution data. Treat the generated `data/` directory and any browser/localStorage follow-up markers as sensitive communications records.\n\n- Run the server on loopback only (`127.0.0.1`) unless you put it behind authentication, TLS, and a trusted network boundary.\n- Do not bind this dashboard to all network interfaces on an untrusted LAN or public host.\n- Bridge API tokens entered in the dashboard are used for the active page session only and are not saved to localStorage.\n- Review and delete generated dashboard data according to your caller notice, consent, and retention policy.\n- Do not commit or publish generated dashboard data, contact caches, transcripts, or call logs.\n\n## Setup\n\n### 1. Environment Variables\n\nThe dashboard uses environment variables for configuration. Set these before running:\n\n```bash\n# Required for direction detection\nexport TWILIO_CALLER_ID=\"+16473709139\"\n\n# Optional - customize names\nexport ASSISTANT_NAME=\"Amber\"\nexport OPERATOR_NAME=\"Abe\"\n\n# Optional - customize paths (defaults work for standard setup)\nexport LOGS_DIR=\"$HOME/clawd/skills/amber-voice-assistant/runtime/logs\"\nexport OUTPUT_DIR=\"$HOME/clawd/skills/amber-voice-assistant/dashboard/data\"\n\n# Optional - contact name resolution\nexport CONTACTS_FILE=\"$HOME/clawd/skills/amber-voice-assistant/dashboard/contacts.json\"\n```\n\n**Environment variable defaults:**\n- `TWILIO_CALLER_ID`: *(required, no default)*\n- `ASSISTANT_NAME`: `\"Assistant\"`\n- `OPERATOR_NAME`: `\"the operator\"`\n- `LOGS_DIR`: `../runtime/logs` (relative to dashboard directory)\n- `OUTPUT_DIR`: `./data` (relative to dashboard directory)\n- `CONTACTS_FILE`: `./contacts.json` (relative to dashboard directory)\n\n### 2. Contact Resolution (Optional)\n\nTo resolve phone numbers to names, create a `contacts.json` file:\n\n```bash\ncp contacts.example.json contacts.json\n# Edit contacts.json with your actual contacts\n```\n\n**Format:**\n```json\n{\n  \"+14165551234\": \"John Doe\",\n  \"+16475559876\": \"Jane Smith\"\n}\n```\n\nPhone numbers should be in E.164 format (with `+` and country code).\n\n### 3. Processing Logs\n\nRun the log processor to generate dashboard data:\n\n```bash\n# Using environment variables\nnode process_logs.js\n\n# Or specify paths directly\nnode process_logs.js --logs /path/to/logs --out /path/to/data\n\n# Help\nnode process_logs.js --help\n```\n\nThe processor reads call logs from the `LOGS_DIR` (or `../runtime/logs` by default) and generates:\n- `data/calls.json` - processed call data\n- `data/calls.js` - same data as window.CALL_LOG_CALLS for file:// usage\n- `data/meta.json` - metadata about the processing run\n- `data/meta.js` - metadata as window.CALL_LOG_META\n\n**Quick update script:**\n```bash\n./update_data.sh\n```\n\n### 4. Viewing the Dashboard\n\n**Option 1: Local HTTP Server (Recommended)**\n\n```bash\nnode scripts/serve.js\n# Open http://127.0.0.1:8787/\n\n# Or custom loopback port\nnode scripts/serve.js --port 8080 --host 127.0.0.1\n\n# Only bind to a network interface when you have added authentication/TLS\n# and understand that call logs/transcripts may be exposed to that network.\n```\n\n**Option 2: File Protocol**\n\nOpen `index.html` directly in your browser. Browsing, filtering, and transcript views work with `file://` URLs. One-touch test calls require the local HTTP server above so `/api/call` can proxy safely to the loopback Amber bridge.\n\n### 5. Auto-Update (Optional)\n\nTo automatically reprocess logs when files change:\n\n```bash\nnode scripts/watch.js\n# Watches logs directory and regenerates data on changes (every 1.5s)\n\n# Or specify custom paths\nnode scripts/watch.js --logs /path/to/logs --out /path/to/data --interval-ms 2000\n```\n\n## Usage\n\n### Dashboard Interface\n\n- **Stats Cards:** Click to filter by type (inbound, outbound, messages, etc.)\n- **Search:** Filter by name, number, transcript content, or Call SID\n- **Follow-ups:** Click 🔔 icon on any call to mark for follow-up\n- **One-Touch Call:** Enter a test number/objective, choose regular or mini model, and start a local bridge call\n- **Cost Visibility:** Adjust local rate settings to estimate telephony and Realtime model spend\n- **Refresh:** Click ↻ button or wait for auto-refresh (30s)\n- **Transcript:** Click \"Transcript\" to expand full conversation\n\n### Command-Line Options\n\n**process_logs.js:**\n```\n--logs <dir>       Path to logs directory\n--out <dir>        Path to output directory\n--no-sample        Skip generating sample data\n-h, --help         Show help\n```\n\n**watch.js:**\n```\n--logs <dir>       Path to logs directory\n--out <dir>        Path to output directory\n--interval-ms <n>  Polling interval in milliseconds (default: 1500)\n-h, --help         Show help\n```\n\n**serve.js:**\n```\n--host <ip>        Bind address (default: 127.0.0.1)\n--port <n>         Port number (default: 8787)\n-h, --help         Show help\n```\n\n## File Structure\n\n```\ndashboard/\n├── index.html           # Main dashboard HTML\n├── process_logs.js      # Log processor (generalized)\n├── update_data.sh       # Quick update script\n├── contacts.json        # Your contacts (not tracked in git)\n├── contacts.example.json # Example contacts file\n├── README.md            # This file\n├── scripts/\n│   ├── serve.js         # Local HTTP server\n│   └── watch.js         # Auto-update watcher\n└── data/                # Generated data (git-ignored)\n    ├── calls.json\n    ├── calls.js\n    ├── meta.json\n    └── meta.js\n```\n\n## Integration with Amber Voice Assistant\n\nThis dashboard is designed to work standalone but integrates seamlessly with the Amber Voice Assistant skill:\n\n1. The skill writes logs to `../runtime/logs/` (relative to dashboard)\n2. Run `process_logs.js` to generate dashboard data\n3. View the dashboard via HTTP server or file://\n4. Optionally run `watch.js` for continuous updates\n\n## Customization\n\n**Change dashboard title:**\nEdit the `<title>` and `<h1>` tags in `index.html`.\n\n**Adjust auto-refresh interval:**\nEdit the `setInterval` call at the bottom of `index.html` (default: 30000ms).\n\n**Modify log processing logic:**\nEdit `process_logs.js` - all hardcoded values are now configurable via environment variables.\n\n## Troubleshooting\n\n**No calls showing up:**\n- Check that `LOGS_DIR` points to the correct directory\n- Ensure logs exist (incoming_*.json and rtc_*.txt files)\n- Run `process_logs.js` manually to see any errors\n\n**Direction not detected correctly:**\n- Set `TWILIO_CALLER_ID` to your Twilio phone number\n- The script detects outbound calls by matching the From header\n\n**Names not resolving:**\n- Create `contacts.json` with your phone numbers in E.164 format\n- Verify `CONTACTS_FILE` path is correct\n- Check console for \"Loaded N contacts\" message\n\n**Auto-refresh not working:**\n- Ensure you're using the HTTP server (not file://)\n- Check browser console for fetch errors\n- Verify `data/meta.json` is being updated\n\n## License\n\nPart of the Amber Voice Assistant skill. See parent directory for license information.\n\nArchive v5.5.49: 72 files, 227014 bytes\n\nFiles: AGENT.md (18304b), AMBER_SKILLS_SPEC.md (20389b), amber-skills/calendar/handler.js (8722b), amber-skills/calendar/SKILL.md (3989b), amber-skills/crm/DESIGN.md (19828b), amber-skills/crm/handler.js (17094b), amber-skills/crm/package-lock.json (16675b), amber-skills/crm/package.json (299b), amber-skills/crm/SKILL.md (6080b), amber-skills/send-message/handler.js (3323b), amber-skills/send-message/SKILL.md (2792b), amber-skills/SKILL_MANIFEST.json (255b), ASTERISK-IMPLEMENTATION-PLAN.md (14234b), dashboard/contacts.example.json (132b), dashboard/index.html (38716b), dashboard/process_logs.js (30483b), dashboard/README.md (7775b), dashboard/scripts/serve.js (8417b), dashboard/scripts/watch.js (4032b), dashboard/update_data.sh (609b), demo/demo-wizard.js (6641b), demo/README.md (4327b), DO-NOT-CHANGE.md (2036b), FEEDBACK.md (1431b), LICENSE (911b), NOTICE (158b), packaging/cowork/commands/call.md (1118b), packaging/cowork/commands/calls.md (852b), packaging/cowork/commands/screen.md (1055b), packaging/cowork/commands/voicemail.md (515b), packaging/cowork/README.md (3504b), packaging/cowork/skills/calendar/SKILL.md (1178b), packaging/cowork/skills/call-screening/SKILL.md (1844b), packaging/cowork/skills/contacts/SKILL.md (755b), packaging/cowork/skills/crm/SKILL.md (1747b), packaging/cowork/skills/phone-calls/SKILL.md (1652b), packaging/hermes/mcp_servers.yaml (407b), packaging/hermes/README.md (1264b), packaging/hermes/SKILL.md (4932b), README.md (13388b), references/architecture.md (1509b), references/positioning-backup-2026-04-18.md (1333b), references/release-checklist.md (1152b), runtime/package-lock.json (112565b), runtime/package.json (1051b), runtime/README.md (9110b), runtime/scripts/dist-watcher.cjs (3547b), runtime/scripts/sync-contacts.js (6764b), runtime/setup-wizard.js (21861b), runtime/src/config.ts (4606b), runtime/src/contacts-lookup.ts (5818b), runtime/src/contacts-query.swift (7581b), runtime/src/index.ts (95450b), runtime/src/local-helper-runner.ts (1481b), runtime/src/mcp-server.ts (30161b), runtime/src/providers/index.ts (2302b), runtime/src/providers/telnyx.ts (6969b), runtime/src/providers/twilio.ts (4746b), runtime/src/providers/types.ts (4510b), runtime/src/skills/api.ts (5349b), runtime/src/skills/index.ts (349b), runtime/src/skills/loader.ts (6412b), runtime/src/skills/router.ts (8031b), runtime/src/skills/types.ts (1527b), runtime/tsconfig.json (431b), scripts/setup_quickstart.sh (826b), scripts/validate_voice_env.sh (2790b), skill-card.md (3195b), SKILL.md (17072b), skills/amber-phone-agent/SKILL.md (4932b), UPGRADING.md (2706b), _meta.json (137b)\n\nFile v5.5.49:amber-skills/calendar/SKILL.md\n\n---\nname: calendar\nversion: 1.2.0\ndescription: \"Query and manage the operator's calendar — check availability and create new entries\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": true, \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [\"ical-query\"], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"calendar_query\", \"description\": \"Check the operator's calendar availability or create a new entry. PRIVACY RULE: When reporting availability to callers, NEVER disclose event titles, names, locations, or any details about what the operator is doing. Only share whether they are free or busy at a given time (e.g. 'free from 2pm to 4pm', 'busy until 3pm'). Treat all calendar event details as private and confidential. Calendar creation requires explicit confirmation from the caller before the action proceeds.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup\", \"create\"], \"description\": \"Whether to look up availability or create a new event\"}, \"range\": {\"type\": \"string\", \"description\": \"For lookup: today, tomorrow, week, or a specific date like 2026-02-23\", \"pattern\": \"^(today|tomorrow|week|\\\\d{4}-\\\\d{2}-\\\\d{2})$\"}, \"title\": {\"type\": \"string\", \"description\": \"For create: the event title\", \"maxLength\": 200}, \"start\": {\"type\": \"string\", \"description\": \"For create: start date-time like 2026-02-23T15:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"end\": {\"type\": \"string\", \"description\": \"For create: end date-time like 2026-02-23T16:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"calendar\": {\"type\": \"string\", \"description\": \"Optional: specific calendar name\", \"maxLength\": 100}, \"notes\": {\"type\": \"string\", \"description\": \"For create: event notes\", \"maxLength\": 500}, \"location\": {\"type\": \"string\", \"description\": \"For create: event location\", \"maxLength\": 200}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Required for create actions after the caller explicitly confirms the booking details.\"}}, \"required\": [\"action\"]}}}}\n---\n\n# Calendar Skill\n\nQuery the operator's calendar for availability and create new entries via `ical-query`.\n\n## Capabilities\n\n- **read**: Check free/busy availability for today, tomorrow, this week, or a specific date\n- **act**: Create new calendar entries (explicit confirmation required)\n\n## Privacy Rule\n\n**Event details are never disclosed to callers.** This is enforced at two levels:\n\n1. **Handler level** — the handler strips all event titles, names, locations, and notes from ical-query output before returning results. Only busy time slots (start/end times) are returned.\n2. **Model level** — the function description instructs Amber to only communicate availability (\"free from 2pm to 4pm\") and never reveal what the events are.\n\nAmber should say things like:\n- ✅ \"The operator is free between 2 and 4 this afternoon\"\n- ✅ \"They're busy until 3pm, then free for the rest of the day\"\n- ❌ \"They have a meeting with John at 2pm\" ← never\n- ❌ \"They're at the dentist from 10 to 11\" ← never\n\n## Security — Three Layers\n\nInput validation is enforced at three independent levels:\n\n1. **Schema level** — `range` is constrained by `pattern: ^(today|tomorrow|week|\\d{4}-\\d{2}-\\d{2})$`; `start`/`end` by `pattern: ^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$`; freetext fields have `maxLength` caps. The LLM cannot produce out-of-spec values without violating the schema.\n2. **Handler level** — explicit validation before any exec call; rejects values that don't match expected formats even if schema is bypassed.\n3. **Exec level** — `context.exec()` takes a `string[]` and uses `execFileSync` (no shell spawned); arguments are passed as discrete tokens, not a shell-interpolated string.\n\n## Notes\n\n- Uses `/usr/local/bin/ical-query` — no network access, no gateway round-trip\n- Fast: direct local binary call (~100ms)\n- Calendar name optional — defaults to operator's primary calendar\n\nFile v5.5.49:amber-skills/crm/SKILL.md\n\n---\nname: crm\nversion: 1.0.0\ndescription: \"Local contact memory and interaction log for operator-reviewed phone follow-up\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": false, \"timeout_ms\": 3000, \"permissions\": {\"local_binaries\": [], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"crm\", \"description\": \"Manage local contacts and interaction history for operator-reviewed phone follow-up. Use lookup_contact at the start of inbound calls (automatic, using caller ID) to check if the caller is known and retrieve relevant operator-approved context. Use upsert_contact to save caller-volunteered contact details (name, email, company) when appropriate under the operator's caller notice/consent policy. Use log_interaction at the end of every call to record what happened (summary, outcome). Use context_notes for concise, relevant follow-up context; avoid sensitive, intimate, or unnecessary personal details. Do not ask robotic CRM questions; capture only details naturally relevant to the call purpose and retention policy.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup_contact\", \"upsert_contact\", \"log_interaction\", \"get_history\", \"search_contacts\", \"tag_contact\"], \"description\": \"The CRM action to perform\"}, \"phone\": {\"type\": \"string\", \"description\": \"Contact phone number in E.164 format (e.g. +14165551234)\", \"pattern\": \"^\\\\+[1-9]\\\\d{6,14}$|^$\"}, \"name\": {\"type\": \"string\", \"maxLength\": 200}, \"email\": {\"type\": \"string\", \"maxLength\": 200}, \"company\": {\"type\": \"string\", \"maxLength\": 200}, \"context_notes\": {\"type\": \"string\", \"maxLength\": 1000, \"description\": \"Concise operator-reviewed follow-up context. Avoid sensitive, intimate, or unnecessary personal details.\"}, \"summary\": {\"type\": \"string\", \"maxLength\": 500, \"description\": \"One-liner: what the call was about\"}, \"outcome\": {\"type\": \"string\", \"enum\": [\"message_left\", \"appointment_booked\", \"info_provided\", \"callback_requested\", \"transferred\", \"other\"], \"description\": \"Call outcome\"}, \"details\": {\"type\": \"object\", \"description\": \"Structured extras as key-value pairs (e.g. appointment_date, purpose)\"}, \"query\": {\"type\": \"string\", \"maxLength\": 200}, \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 50, \"default\": 10}, \"add\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}, \"remove\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}}, \"required\": [\"action\"]}}}}\n---\n\n# CRM Skill — Contact Memory for Voice Calls\n\nStores local, operator-reviewed caller context and interaction history for phone follow-up.\n\n## How It Works\n\n### On Every Inbound Call\n\n1. **Lookup** — Call `crm` with `lookup_contact` using the caller's phone number (from Twilio caller ID) only under the operator's caller notice/consent and retention policy.\n2. **If known** — Greet by name and use `context_notes` only when relevant to the call purpose. Avoid surprising rapport-building from intimate or unnecessary details.\n3. **If unknown** — Proceed normally, listen for their name.\n\n### During the Call\n\nWhen someone shares their name, email, company, or relevant follow-up details, upsert it via `crm.upsert_contact` only if that fits the operator's caller notice/consent and retention policy. Avoid collecting sensitive or unnecessary personal details.\n\n### At End of Call\n\n1. Log the interaction: `log_interaction` with summary + outcome\n2. Update context_notes with concise, relevant follow-up context, synthesizing with what was known before\n\n### On Outbound Calls\n\nSame exact flow: lookup at start, upsert + log_interaction at end.\n\n## API Reference\n\n| Action | Purpose |\n|--------|---------|\n| `lookup_contact` | Fetch contact + last 5 interactions + context_notes. Returns null if not found. |\n| `upsert_contact` | Create or update a contact by phone. Only provided fields are updated. |\n| `log_interaction` | Log a call: summary, outcome, details. Auto-creates contact if needed. |\n| `get_history` | Get past interactions for a contact (sorted newest-first). |\n| `search_contacts` | Search by name, email, company, notes. |\n| `tag_contact` | Add/remove tags (e.g. \"vip\", \"callback_later\"). |\n\n## Privacy\n\n- **Event details stay private.** Like the calendar skill, never disclose event details to callers.\n- **CRM context is personal.** The `context_notes` field is for Amber's internal memory, not for sharing call transcripts. Use it to inform conversation, not to recite it.\n- **PII storage.** Phone, name, email, company, context_notes, call summaries, and interaction metadata are stored locally in SQLite. Operators must provide appropriate caller notice/consent and retention/deletion practices. No network transmission, no external CRM by default.\n- **Review and correction.** Operators should periodically review, correct, or delete CRM entries so inaccurate transcript extraction or overly sensitive details do not persist.\n\n## Security\n\n- Synchronous SQLite (better-sqlite3) with parameterized queries — no SQL injection surface\n- Private number detection — calls from anonymous/blocked numbers are skipped entirely\n- Input validation at three levels: schema patterns, handler validation, database constraints\n- Database file created with mode 0600 (owner read/write only)\n\n## Examples\n\n**Greeting a known caller:**\n```\nAmber: \"Hi Sarah, good to hear from you again. I have you down as preferring afternoon callbacks.\"\n[context_notes remembered: \"Prefers afternoon callbacks for appointment changes.\"]\n```\n\n**Capturing relevant follow-up context:**\n```\nCaller: \"By the way, I got married last month!\"\nAmber: [only records this if it is relevant and appropriate under the operator's retention policy]\nAmber (aloud): \"That's wonderful! Congrats!\"\n```\n\n**End-of-call log:**\n```\nAmber: [calls log_interaction: summary=\"Called to reschedule Friday appointment\", outcome=\"appointment_booked\"]\nAmber: [calls upsert_contact with context_notes: \"Prefers afternoon callbacks. Usually calls to reschedule appointments.\"]\n```\n\nFile v5.5.49:amber-skills/send-message/SKILL.md\n\n---\nname: send-message\nversion: 1.0.0\ndescription: \"Leave a message for the operator — saved to call log and delivered via the operator's preferred messaging channel\"\nmetadata: {\"amber\": {\"capabilities\": [\"act\"], \"confirmation_required\": true, \"confirmation_prompt\": \"Would you like me to leave that message?\", \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [], \"telegram\": true, \"openclaw_action\": true, \"network\": false}, \"function_schema\": {\"name\": \"send_message\", \"description\": \"Leave a message for the operator. The message will be saved to the call log and sent to the operator via their messaging channel. IMPORTANT: Always confirm with the caller before calling this function — ask 'Would you like me to leave that message?' and only proceed after they confirm.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"message\": {\"type\": \"string\", \"description\": \"The caller's message to leave for the operator\", \"maxLength\": 1000}, \"caller_name\": {\"type\": \"string\", \"description\": \"The caller's name if they provided it\", \"maxLength\": 100}, \"callback_number\": {\"type\": \"string\", \"description\": \"A callback number if the caller provided one\", \"maxLength\": 30}, \"urgency\": {\"type\": \"string\", \"enum\": [\"normal\", \"urgent\"], \"description\": \"Whether the caller indicated this is urgent\"}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Must be true — only set after the caller has explicitly confirmed their message and given permission to send it. The router will reject this call if confirmed is not true.\"}}, \"required\": [\"message\", \"confirmed\"]}}}}\n---\n\n# Send Message\n\nAllows callers to leave a message for the operator. This skill implements the\n\"leave a message\" pattern that is standard in phone-based assistants.\n\n## Flow\n\n1. Caller indicates they want to leave a message\n2. Amber confirms: \"Would you like me to leave that message?\"\n3. On confirmation, the message is:\n   - **Always** saved to the call log first (audit trail)\n   - **Then** delivered to the operator via their configured messaging channel\n\n## Security\n\n- The recipient is determined by the operator's configuration — never by caller input\n- No parameter in the schema accepts a destination or recipient\n- Confirmation is required before sending (enforced programmatically at the router layer — the router checks `params.confirmed === true` before invoking; LLM prompt guidance is an additional layer, not the sole enforcement)\n- Message content is sanitized (max length, control characters stripped)\n\n## Delivery Failure Handling\n\n- If messaging delivery fails, the call log entry is marked with `delivery_failed`\n- The operator's assistant can check for undelivered messages during heartbeat checks\n- Amber tells the caller \"I've noted your message\" — never promises a specific delivery channel\n\nFile v5.5.49:packaging/cowork/skills/calendar/SKILL.md\n\n---\nname: calendar\ndescription: >\n  Check availability and create calendar entries. Used during calls to\n  book appointments and check schedule conflicts. Use when the user or\n  a caller needs to schedule something or check availability.\n---\n\n# Calendar\n\nQuery and manage the operator's calendar during or outside of calls.\n\n## MCP Tools\n\n### calendar_query\nLook up or create calendar events.\n- `action` (string, required): \"lookup\" or \"create\"\n- `query` (string, required for lookup): Natural language query (e.g., \"am I free Tuesday at 3pm?\")\n- `title` (string, required for create): Event title\n- `start` (string, required for create): Start time (ISO 8601)\n- `end` (string, required for create): End time (ISO 8601)\n- `calendar` (string): Which calendar to use (defaults to operator's primary)\n- `location` (string): Event location\n- `notes` (string): Event notes\n\n## Guidelines\n\n- When checking availability during a call, present options naturally (\"I see an opening at 2pm and 4pm — which works better?\")\n- Always confirm the final date, time, and details before creating an event\n- Include relevant context from the call in the event notes (who requested it, purpose)\n\nFile v5.5.49:packaging/cowork/skills/call-screening/SKILL.md\n\n---\nname: call-screening\ndescription: >\n  Screen incoming phone calls with an AI receptionist. Amber answers calls,\n  identifies the caller, determines the purpose, takes a message, and\n  delivers a structured summary. Use when the user wants to set up call\n  screening, check screened call results, or customize screening behavior.\n---\n\n# Call Screening\n\nAmber acts as an AI receptionist for inbound calls. She answers professionally,\ngathers information, and delivers structured summaries — so you only pick up\ncalls that matter.\n\nPrivacy: screening can process caller audio/metadata through your configured providers and may produce local transcripts/summaries. Configure caller notice/consent, retention, and access controls before production use.\n\n## Screening Flow\n\n1. **Greeting** — Amber answers with a customizable greeting\n2. **Identification** — Asks who's calling and what it's regarding\n3. **Information gathering** — Collects caller name, callback number, message\n4. **CRM lookup** — Checks if the caller is a known contact (auto-enriches context)\n5. **Calendar check** — If the caller wants to book time, checks availability\n6. **Summary delivery** — Sends a structured summary with all captured details\n\n## MCP Tools\n\n### start_screening\nEnable inbound call screening on the configured Twilio number.\n\n### stop_screening\nDisable screening (calls ring through normally).\n\n### get_screening_status\nCheck whether screening is currently active.\n\n## Customization\n\nThe screening personality, greeting, and behavior are defined in AGENT.md.\nUsers can edit this file to:\n- Change the assistant's name and personality\n- Customize the greeting message\n- Set business hours and after-hours behavior\n- Define which callers should be put through vs. screened\n- Add organization-specific context (company name, services, etc.)\n\nFile v5.5.49:packaging/cowork/skills/contacts/SKILL.md\n\n---\nname: contacts\ndescription: >\n  Look up contacts by name to resolve phone numbers before making calls.\n  Use when the user says \"call John\" instead of providing a phone number.\n---\n\n# Contacts\n\nResolve contact names to phone numbers for outbound calls.\n\n## Flow\n\n1. User says \"call [name]\" or \"/amber:call [name] [objective]\"\n2. Look up the name in the CRM via `crm(action: \"lookup\", identifier: \"name\")`\n3. If found, use the stored phone number\n4. If multiple matches, present options and let the user choose\n5. If not found, ask the user for the phone number\n\n## Guidelines\n\n- Be fuzzy with name matching — \"John\" should match \"John Smith\"\n- If ambiguous, always confirm before dialing (\"I found John Smith at +1-416-555-1234 — is that right?\")\n\nFile v5.5.49:packaging/cowork/skills/crm/SKILL.md\n\n---\nname: crm\ndescription: >\n  Contact memory and interaction log. Remembers callers across calls,\n  stores personal context, and logs every conversation. Use when looking\n  up a contact, adding notes about someone, or reviewing interaction history.\n---\n\n# CRM — Contact Memory\n\nAmber remembers everyone she talks to. The CRM stores contact details,\npersonal context, and a log of every interaction.\n\nPrivacy: CRM storage is local and should be opt-in. Enable it only after configuring caller notice/consent, retention/deletion practices, and access controls for the SQLite database.\n\n## MCP Tools\n\n### crm\nManage contacts and interaction history.\n- `action` (string, required): \"lookup\", \"create\", \"update\", \"log\", \"history\"\n- `identifier` (string): Phone number or name to look up\n- `name` (string): Contact name\n- `phone` (string): Phone number\n- `email` (string): Email address\n- `notes` (string): Personal context or notes about the contact\n- `tags` (array): Tags for categorization (e.g., [\"client\", \"vendor\", \"friend\"])\n\n## Automatic Behavior\n\n- On inbound calls, Amber automatically looks up the caller by phone number\n- If the caller is known, their context and history are loaded into the conversation\n- After every call, an interaction log entry is created with: date, summary, sentiment, outcome\n- New callers are added to the CRM only when CRM persistence is enabled and appropriate under your caller notice/consent policy\n\n## Guidelines\n\n- Use the CRM only for relevant follow-up context; avoid surprising personalization from sensitive or unnecessary personal details\n- Keep notes professional but useful — preferences, important dates, relationship context\n- Never expose CRM data to callers beyond what's socially appropriate\n\nFile v5.5.49:packaging/cowork/skills/phone-calls/SKILL.md\n\n---\nname: phone-calls\ndescription: >\n  Make and manage real phone calls through Twilio. Handles outbound calls\n  with a stated objective, monitors call progress, and returns transcripts\n  and summaries. Use when the user wants to call someone, check on a call,\n  or review call history.\n---\n\n# Phone Calls\n\nAmber can make and receive real phone calls via Twilio. This skill covers\nthe core telephony capabilities.\n\n## MCP Tools\n\n### make_call\nInitiate an outbound phone call.\n- `to` (string, required): Phone number in E.164 format (e.g., +14165551234)\n- `objective` (string, required): What to accomplish on the call\n- `mode` (string): \"conversation\" (default) or \"message\" (one-way delivery)\n\n### get_call_status\nCheck the status of an active or recent call.\n- `callId` (string, required): The call ID returned by make_call\n\n### end_call\nTerminate an active call.\n- `callId` (string, required): The call ID to end\n\n### get_call_history\nRetrieve recent call logs with transcripts.\n- `filter` (string): \"all\", \"inbound\", \"outbound\", \"missed\"\n- `limit` (number): Number of calls to return (default: 10)\n\n## Guidelines\n\n- Always confirm the recipient number and call objective with the user before dialing\n- If the objective involves payment, deposits, or financial commitments, explicitly ask the user for approval first\n- After each call, provide a summary including: who was called, outcome, key information exchanged, and caller sentiment\n- For outbound calls, Amber pursues the stated objective autonomously — she's not just reading a script\n- Calls have real-world consequences. Treat every call as if you're representing the user professionally\n\nFile v5.5.49:packaging/hermes/SKILL.md\n\n---\nname: amber-phone-agent\ndescription: Give Hermes Agent real phone capabilities through Amber's Twilio/OpenAI voice bridge and MCP tools.\nversion: \"5.5.39\"\nlicense: MIT\ncompatibility: Node.js 20+, Twilio account, OpenAI API key, Hermes Agent with MCP support\nplatforms: [macos, linux]\nmetadata:\n  author: batthis\n  repository: https://github.com/batthis/amber-openclaw-voice-agent\n  hermes:\n    tags: [phone, voice, twilio, openai, mcp, receptionist, calendar, crm]\n    category: communication\n    requires_toolsets: [mcp]\n    config:\n      - key: AMBER_RUNTIME_DIR\n        description: Absolute path to the Amber runtime directory containing dist/mcp-server.js\n        default: ~/amber-openclaw-voice-agent/runtime\n        prompt: Path to Amber runtime directory\n---\n\n# Amber — Phone-Capable Voice Agent for Hermes\n\n## When to Use\n\nUse Amber when the user wants Hermes to interact with the telephone network:\n\n- prepare or place an outbound phone call after explicit user confirmation\n- screen inbound calls through a Twilio number\n- check call history, transcripts, or summaries\n- resolve contacts before calling someone\n- check availability or create calendar entries during a phone workflow\n- use local CRM context for caller follow-up\n\nAmber is a sensitive communications system. Calls are real, may involve third parties, may be transcribed, and may be logged locally. Treat all caller details, transcripts, phone numbers, contact data, and calendar data as private.\n\n## Required Runtime\n\nThis skill is an instruction/activation wrapper for Hermes. The actual phone capability is provided by Amber's Node runtime and MCP server.\n\nBefore using this skill, install and configure Amber:\n\n```bash\ngit clone https://github.com/batthis/amber-openclaw-voice-agent.git\ncd amber-openclaw-voice-agent/runtime\nnpm install\nnpm run setup\nnpm run build\nnpm start\n```\n\nDuring setup, choose **Hermes Agent** when asked for the target platform.\n\n## Connect Amber MCP to Hermes\n\nAdd Amber's MCP server to your Hermes config, adjusting the path to your clone:\n\n```yaml\nmcp_servers:\n  amber_voice:\n    command: \"node\"\n    args:\n      - \"/absolute/path/to/amber-openclaw-voice-agent/runtime/dist/mcp-server.js\"\n    env:\n      AMBER_BRIDGE_URL: \"http://127.0.0.1:8000\"\n      BRIDGE_API_TOKEN: \"\"\n```\n\nRestart Hermes or run `/reload-mcp`, then ask Hermes which MCP tools are available. Amber should expose tools such as `make_call`, `get_call_status`, `get_call_history`, `contacts_lookup`, `calendar_query`, `crm`, and `bridge_health`.\n\n## Safety Rules\n\n### Outbound Calls\n\nNever place a call on the first step. Always:\n\n1. Clarify the recipient and objective.\n2. Resolve contact names with `contacts_lookup` where possible.\n3. Show the user the exact recipient, phone number, and objective.\n4. Only call `make_call` with `confirmed=true` after the user explicitly confirms.\n\nIf the call may involve a payment, deposit, contract, medical/legal/financial advice, or any irreversible commitment, stop and ask for explicit user approval first.\n\n### Inbound Screening\n\nWhen Amber screens calls, collect only what is needed:\n\n- caller name\n- callback number\n- message or purpose\n- any scheduling details the caller volunteers\n\nDo not solicit unnecessary sensitive personal data.\n\n### Calendar\n\nFor calendar lookups, disclose only free/busy availability. Do not reveal event names, locations, attendees, or private details.\n\nFor calendar creation, confirm title, date, start/end time, location/notes, and the person requesting the booking before creating the event.\n\n### CRM / Memory\n\nUse CRM context only when relevant and benign. Do not surface sensitive health, family, legal, financial, political/religious, intimate, or surprising details unless the caller raises them first or the task clearly requires it.\n\n## Useful Prompts\n\n- \"Use Amber to check whether the voice bridge is healthy.\"\n- \"Use Amber to find Miriam in contacts and prepare a call, but do not dial until I confirm.\"\n- \"Show my recent inbound call summaries.\"\n- \"Start inbound call screening.\"\n- \"Check if I am free tomorrow afternoon, but do not reveal event details.\"\n\n## Verification\n\nAfter setup, verify in this order:\n\n1. `npm start` shows the Amber bridge listening on `http://127.0.0.1:8000`.\n2. `curl http://127.0.0.1:8000/healthz` returns `{ \"ok\": true }`.\n3. Hermes shows the Amber MCP tools after restart or `/reload-mcp`.\n4. `bridge_health` succeeds from Hermes.\n5. A test inbound call reaches Amber.\n\n## Pitfalls\n\n- If Hermes cannot see Amber tools, check the `mcp_servers` path and run `/reload-mcp`.\n- If calls ring but Amber does not speak, check `PUBLIC_BASE_URL`, your public HTTPS tunnel or domain, Twilio webhooks, and OpenAI webhook settings.\n- If contact lookup fails on macOS, run `npm run sync-contacts` from the Amber runtime directory.\n- If calendar access fails on macOS, grant the helper access in System Settings → Privacy & Security → Calendar.\n\nFile v5.5.49:SKILL.md\n\n---\nname: amber-voice-assistant\ntitle: \"Amber — Give Your Agent Real Phone Capabilities\"\ndescription: \"Real phone assistant runtime with Twilio/OpenAI Realtime calling, inbound screening, confirmed outbound calls, local call logs/transcripts, optional local CRM/contact memory, calendar booking, contacts lookup, MCP tools, and a loopback-only dashboard.\"\nhomepage: https://github.com/batthis/amber-openclaw-voice-agent\nmetadata: {\"openclaw\":{\"emoji\":\"☎️\",\"requires\":{\"env\":[],\"optionalEnv\":[\"AMBER_ENABLE_OUTBOUND_CALLS\",\"AMBER_REALTIME_MODEL\",\"AMBER_REALTIME_VAD_THRESHOLD\",\"AMBER_REALTIME_VAD_PREFIX_PADDING_MS\",\"AMBER_REALTIME_VAD_SILENCE_DURATION_MS\",\"AMBER_CRM_ENABLED\",\"AMBER_CRM_TRANSCRIPT_ENRICHMENT\",\"OPENCLAW_GATEWAY_URL\",\"TWILIO_WEBHOOK_STRICT\",\"VOICE_PROVIDER\",\"VOICE_WEBHOOK_SECRET\",\"ASSISTANT_NAME\",\"OPERATOR_NAME\",\"AMBER_CRM_DB_PATH\",\"AGENT_MD_PATH\",\"DEFAULT_CALENDAR\",\"AMBER_CONTACTS_EXTENDED\"],\"anyBins\":[\"node\",\"ical-query\"]},\"permissions\":{\"network\":true,\"env\":true,\"webhooks\":true,\"localFiles\":[\"runtime/logs/\",\"runtime/contacts-cache.json\",\"~/.config/amber/crm.sqlite\"],\"localBinaries\":[\"node\",\"ical-query\"],\"mcpTools\":[\"prepare_call\",\"start_call\",\"call_history\",\"crm\",\"contacts_lookup\",\"calendar\",\"screening_control\",\"bridge_health\"],\"externalServices\":[\"Twilio or compatible voice provider\",\"OpenAI Realtime/API\",\"optional OpenClaw Gateway\"]},\"install\":[{\"id\":\"runtime\",\"kind\":\"node\",\"cwd\":\"runtime\",\"label\":\"Install Amber runtime (cd runtime && npm ci && npm run build)\"},{\"id\":\"crm-skill\",\"kind\":\"node\",\"cwd\":\"amber-skills/crm\",\"label\":\"Install optional CRM skill dependencies (cd amber-skills/crm && npm ci)\"}]}}\n---\n\n# Amber — Give Your Agent Real Phone Capabilities\n\n## Overview\n\nAmber gives any OpenClaw deployment **real phone capabilities for agents**. It ships with a **production-ready Twilio + OpenAI Realtime bridge** (`runtime/`) for confirmed phone workflows: inbound answering, call screening, prepared outbound workflows, confirmed scheduling over a real telephone number, local call logs/transcripts, optional local CRM/contact memory, contacts lookup, MCP tools, and a loopback-only dashboard.\n\nAmber is a sensitive communications system. It can process call audio/transcripts through configured voice and AI providers, store local call logs, maintain a local CRM, read/write the operator calendar, expose local MCP tools, and optionally use an Apple Contacts export for name-to-number resolution. Operators should configure caller notice/consent, retention/deletion practices, and least-privilege provider credentials before production use.\n\nPrivacy defaults: local CRM lookup/logging is disabled unless `AMBER_CRM_ENABLED=true`, and post-call transcript enrichment is disabled unless `AMBER_CRM_TRANSCRIPT_ENRICHMENT=true`. Enable those only after setting caller notice/consent and retention/deletion practices.\n\n**✨ New in v5.4.0:** Amber now ships as an **MCP plugin** with 9 tools — prepare confirmed calls by name, check call history, query CRM contacts, manage calendar, and control call screening. It works with Claude Desktop/Cowork and other MCP-capable clients or agent harnesses once configured. Includes Apple Contacts integration and a code-enforced call confirmation safeguard to prevent wrong-number dials.\n\n**✨ Also:** Interactive setup wizard (`npm run setup`) validates credentials in real-time and generates a working `.env` file — no manual configuration needed. Once setup is complete, Amber is prompt-based: ask your OpenClaw agent to prepare confirmed calls, answer/screen callers, schedule confirmed appointments, or handle phone workflows in natural language.\n\n## See it in action\n\n![Setup Wizard Demo](demo/demo.gif)\n\n**[▶️ Watch the interactive demo on asciinema.org](https://asciinema.org/a/l1nOHktunybwAheQ)** (copyable text, adjustable speed)\n\n*The interactive wizard validates credentials, detects ngrok, and generates a complete `.env` file in minutes.*\n\n### What's included\n\n- **Runtime bridge** (`runtime/`) — a complete Node.js server that connects Twilio phone calls to OpenAI Realtime with OpenClaw brain-in-the-loop\n- **Amber Skills** (`amber-skills/`) — modular mid-call capabilities (CRM, calendar, log & forward message) with a spec for building your own\n- **Built-in CRM** — local SQLite contact database; Amber can greet callers by name and use operator-approved context naturally on calls, with operator review/correction responsibility\n- **Call log dashboard** (`dashboard/`) — browse call history, transcripts, captured messages, estimated costs, and one-touch localhost test calls with regular/mini Realtime model selection\n- **Setup & validation scripts** — preflight checks, env templates, quickstart runner\n- **Architecture docs & troubleshooting** — call flow diagrams, common failure runbooks\n- **Safety guardrails** — outbound calls require code-enforced confirmation; payment escalation, consent boundaries, and explicit confirmation for calendar writes are documented\n\n## 🔌 Amber Skills — Extensible by Design\n\nAmber ships with a growing library of **Amber Skills** — modular capabilities that plug directly into live voice conversations. Each skill exposes a structured function that Amber can call mid-call, letting you compose powerful voice workflows without touching the bridge code.\n\n### 👤 CRM — Contact Memory *(v5.3.0)*\n\nAmber can maintain operator-reviewed caller memory across calls, limited to relevant follow-up context under the operator's notice, consent, and retention policy.\n\n- **Opt-in runtime management** — set `AMBER_CRM_ENABLED=true` to enable automatic known-caller lookup and interaction logging\n- **Personalized greeting** — known callers can be greeted by name; optional notes are used only when relevant to the call objective\n- **Optional enrichment** — set `AMBER_CRM_TRANSCRIPT_ENRICHMENT=true` to allow post-call extraction to propose caller details and notes for the local CRM\n- **Operator review expected** — review, correct, or delete CRM records periodically so bad transcript extraction, misleading caller input, or overly sensitive details do not persist indefinitely\n- **Symmetric** — works identically for inbound and outbound calls\n- **Local SQLite CRM** — contact memory is stored at `~/.config/amber/crm.sqlite`; CRM records are not cloud-hosted. Live call audio/transcripts still pass through Twilio/OpenAI as part of the phone bridge. Tell callers when calls are handled by an AI assistant and may be logged/used for follow-up, according to your local consent requirements.\n- **Native dependency** — requires `better-sqlite3` (native build). macOS: `sudo xcodebuild -license accept` before `npm install`. Linux: `build-essential` + `python3`.\n\n### 📅 Calendar\n\nQuery the operator's calendar for availability or schedule a new event — all during a live call.\n\n- **Availability lookups** — free/busy slots for today, tomorrow, this week, or any specific date\n- **Event creation** — create calendar events from a phone conversation only after the required details are collected and the caller explicitly confirms the slot\n- **Privacy by default** — callers are only told whether the operator is free or busy; event titles, names, and locations are never disclosed\n- Powered by `ical-query` — local-only, zero network latency\n\n### 📬 Log & Forward Message\n\nLet callers leave a message that is automatically saved and forwarded to the operator.\n\n- Captures the caller's message, name, and optional callback number\n- **Always saves to the call log first** (audit trail), then delivers via the operator's configured messaging channel\n- Confirmation-gated — Amber confirms with the caller before sending\n- Delivery destination is operator-configured — callers cannot redirect messages\n\n### Build Your Own Skills\n\nAmber's skill system is designed to grow. Each skill is a self-contained directory with a `SKILL.md` (metadata + function schema) and a `handler.js`. You can:\n\n- **Customize the included skills** to fit your own setup\n- **Build new skills** for your use case — CRM lookups, inventory checks, custom notifications, anything callable mid-call\n- **Share skills** with the OpenClaw community via [ClawHub](https://clawhub.com)\n\nSee [`amber-skills/`](amber-skills/) for examples and the full specification to get started.\n\n**Contacts privacy:** Apple Contacts sync is opt-in. By default it exports only names and phone numbers needed for call-by-name. Set `AMBER_CONTACTS_EXTENDED=true` only if you explicitly want extra local-only fields such as email, organization, relationships, addresses, and notes in `runtime/contacts-cache.json`.\n\n> **Note:** Each skill's `handler.js` is reviewed against its declared permissions. When building or installing third-party skills, review the handler source as you would any Node.js module.\n\n### Call log dashboard\n\n```bash\ncd dashboard && node scripts/serve.js   # → http://localhost:8787\n```\n\n- **⬇ Sync button** (green) — immediately pulls new calls from `runtime/logs/` and refreshes the dashboard. Use this right after a call ends rather than waiting for the background watcher.\n- **↻ Refresh button** (blue) — reloads existing data from disk without re-processing logs.\n- **One-touch test calls** — when opened through `node scripts/serve.js`, the dashboard can call a test number through the local Amber bridge and choose `gpt-realtime` or `gpt-realtime-mini` per call.\n- **Cost visibility** — estimates telephony and Realtime token cost from call duration and saved usage metadata; rates are editable in the dashboard.\n- Background watcher (`node scripts/watch.js`) auto-syncs every 30 seconds when running.\n\n## Why Amber\n\n- **Ship a voice assistant in minutes** — `npm install`, configure `.env`, `npm start`\n- Full inbound screening: greeting, message-taking, appointment booking with calendar integration\n- Outbound calls with structured call plans (reservations, inquiries, follow-ups), with confirmation gates and a runtime disable switch\n- **OpenClaw gateway lookup (least-privilege)** — voice agent consults your OpenClaw gateway only for call-critical needs (availability checks, confirmed scheduling, required factual lookups), not for unrelated tasks\n- VAD tuning + verbal fillers to keep conversations natural (no dead air during lookups)\n- Fully configurable: assistant name, operator info, org name, calendar, screening style — all via env vars\n- Operator safety guardrails for approvals/escalation/payment handling\n\n## Personalization requirements\n\nBefore deploying, users must personalize:\n- assistant name/voice and greeting text,\n- own Twilio number and account credentials,\n- own OpenAI project + webhook secret,\n- own OpenClaw gateway/session endpoint,\n- own call safety policy (approval, escalation, payment handling).\n\nDo not reuse example values from another operator.\n\n## 5-minute quickstart\n\n### Option A: Interactive Setup Wizard (recommended) ✨\n\nThe easiest way to get started:\n\n1. `cd runtime`\n2. `npm run setup`\n3. Follow the interactive prompts — the wizard will:\n   - Validate your Twilio and OpenAI credentials in real-time\n   - Auto-detect and configure ngrok if available\n   - Ask whether to enable opt-in local CRM caller memory\n   - Generate a working `.env` file\n   - Optionally install dependencies and build the project\n4. Configure your Twilio webhook (wizard shows you the exact URL)\n5. Start the server: `npm start`\n6. Call your Twilio number — your voice assistant answers!\n\n**Benefits:**\n- Real-time credential validation (catch errors before you start)\n- No manual `.env` editing\n- Automatic ngrok detection and setup\n- Step-by-step guidance with helpful links\n\n### Option B: Manual setup\n\n1. From the Amber skill folder: `cd runtime && npm ci`\n2. `cd ../amber-skills/crm && npm ci` if you plan to enable CRM caller memory.\n3. `cd ../..` and copy `references/env.example` to `runtime/.env`, then fill in your values.\n4. Set `AMBER_CRM_ENABLED=true` only if you want local caller memory/known-caller greetings.\n5. `cd runtime && npm run build && npm start`\n6. Point your Twilio voice webhook to `https://<your-domain>/twilio/inbound`\n7. Call your Twilio number — your voice assistant answers!\n\n### Option C: Validation-only (existing setup)\n\n1. Copy `references/env.example` to your own `.env` and replace placeholders.\n2. Export required variables (`TWILIO_ACCOUNT_SID`, `TWILIO_AUTH_TOKEN`, `TWILIO_CALLER_ID`, `OPENAI_API_KEY`, `OPENAI_PROJECT_ID`, `OPENAI_WEBHOOK_SECRET`, `PUBLIC_BASE_URL`).\n3. Run quick setup:\n   `scripts/setup_quickstart.sh`\n4. If preflight passes, run one inbound and one outbound smoke test.\n5. Only then move to production usage.\n\n## Credential scope (recommended hardening)\n\nUse least-privilege credentials for every provider:\n\n- **Twilio:** use a dedicated subaccount for Amber and rotate auth tokens regularly.\n- **OpenAI:** use a dedicated project API key for this runtime only; avoid reusing keys from unrelated apps.\n- **OpenClaw Gateway token:** only set `OPENCLAW_GATEWAY_TOKEN` if you need brain-in-the-loop lookups; keep token scope minimal.\n- **Dependency integrity:** runtime dependencies are pinned by `runtime/package-lock.json`; review dependency changes before publishing updates.\n- **Secrets in logs:** never print full credentials in scripts, setup output, or call transcripts.\n- **Setup wizard validation scope:** credential checks call only official Twilio/OpenAI API endpoints over HTTPS for auth verification; no arbitrary exfiltration endpoints are used.\n\nThese controls reduce blast radius if a host or config file is exposed.\n\n## Safe defaults\n\n- Outbound calling is enabled by default for the full phone-agent experience. Set `AMBER_ENABLE_OUTBOUND_CALLS=false` to disable the outbound call endpoint.\n- Require explicit approval before outbound calls. **Note on confirmation enforcement:** For MCP-initiated outbound calls (`make_call`), confirmation is enforced at the MCP server layer in code (the tool returns a preview and requires `confirmed=true` on a second call before dialing) — this is not LLM-only instruction. The LLM instruction layer provides an additional reminder, but the code gate is the primary enforcement mechanism.\n- If payment/deposit is requested, stop and escalate to the human operator.\n- Keep greeting short and clear.\n- Use timeout + graceful fallback when `ask_openclaw` is slow/unavailable.\n\n## Workflow\n\n1. **Confirm scope for V1**\n   - Include only stable behavior: call flow, bridge behavior, fallback behavior, and setup steps.\n   - Exclude machine-specific secrets and private paths.\n\n2. **Document architecture + limits**\n   - Read `references/architecture.md`.\n   - Keep claims realistic (latency varies; memory lookups are best-effort).\n\n3. **Run release checklist**\n   - Read `references/release-checklist.md`.\n   - Validate config placeholders, safety guardrails, and failure handling.\n\n4. **Smoke-check runtime assumptions**\n   - Run `scripts/validate_voice_env.sh` on the target host.\n   - Fix missing env/config before publishing.\n\n5. **Publish**\n   - Publish to ClawHub (example):  \n     `clawhub publish <skill-folder> --slug amber-voice-assistant --name \"Amber Voice Assistant\" --version 1.0.0 --tags latest --changelog \"Initial public release\"`\n   - Optional: run your local skill validator/packager before publishing.\n\n6. **Ship updates**\n   - Publish new semver versions (`1.0.1`, `1.1.0`, `2.0.0`) with changelogs.\n   - Keep `latest` on the recommended version.\n\n## Troubleshooting (common)\n\n- **\"Missing env vars\"** → re-check `.env` values and re-run `scripts/validate_voice_env.sh`.\n- **\"Call connects but assistant is silent\"** → verify TTS model setting and provider auth.\n- **\"ask_openclaw timeout\"** → verify gateway URL/token and increase timeout conservatively.\n- **\"CRM lookup fails after a Node upgrade\"** → run `cd amber-skills/crm && npm rebuild better-sqlite3`, then restart the Amber runtime.\n- **\"Webhook unreachable\"** → verify tunnel/domain and Twilio webhook target.\n\n## Guardrails for public release\n\n- Never publish secrets, tokens, phone numbers, webhook URLs with credentials, or personal data.\n- Include explicit safety rules for outbound calls, payments, and escalation.\n- Mark V1 as beta if conversational quality/latency tuning is ongoing.\n\n## Install safety notes\n\n- Amber does **not** execute arbitrary install-time scripts from this repository.\n- Runtime install uses standard Node dependency installation in `runtime/`, with dependencies pinned in `runtime/package-lock.json`.\n- CRM uses `better-sqlite3` (native module), which compiles locally on your machine.\n- Review `runtime/package.json` dependencies before deployment in regulated environments.\n\n## Resources\n\n- **Runtime bridge:** `runtime/` (full source + README)\n- Architecture and behavior notes: `references/architecture.md`\n- Release gate: `references/release-checklist.md`\n- Env template: `references/env.example`\n- Quick setup runner: `scripts/setup_quickstart.sh`\n- Env/config validator: `scripts/validate_voice_env.sh`\n\nFile v5.5.49:skills/amber-phone-agent/SKILL.md\n\n---\nname: amber-phone-agent\ndescription: Give Hermes Agent real phone capabilities through Amber's Twilio/OpenAI voice bridge and MCP tools.\nversion: \"5.5.49\"\nlicense: MIT\ncompatibility: Node.js 20+, Twilio account, OpenAI API key, Hermes Agent with MCP support\nplatforms: [macos, linux]\nmetadata:\n  author: batthis\n  repository: https://github.com/batthis/amber-openclaw-voice-agent\n  hermes:\n    tags: [phone, voice, twilio, openai, mcp, receptionist, calendar, crm]\n    category: communication\n    requires_toolsets: [mcp]\n    config:\n      - key: AMBER_RUNTIME_DIR\n        description: Absolute path to the Amber runtime directory containing dist/mcp-server.js\n        default: ~/amber-openclaw-voice-agent/runtime\n        prompt: Path to Amber runtime directory\n---\n\n# Amber — Phone-Capable Voice Agent for Hermes\n\n## When to Use\n\nUse Amber when the user wants Hermes to interact with the telephone network:\n\n- prepare or place an outbound phone call after explicit user confirmation\n- screen inbound calls through a Twilio number\n- check call history, transcripts, or summaries\n- resolve contacts before calling someone\n- check availability or create calendar entries during a phone workflow\n- use local CRM context for caller follow-up\n\nAmber is a sensitive communications system. Calls are real, may involve third parties, may be transcribed, and may be logged locally. Treat all caller details, transcripts, phone numbers, contact data, and calendar data as private.\n\n## Required Runtime\n\nThis skill is an instruction/activation wrapper for Hermes. The actual phone capability is provided by Amber's Node runtime and MCP server.\n\nBefore using this skill, install and configure Amber:\n\n```bash\ngit clone https://github.com/batthis/amber-openclaw-voice-agent.git\ncd amber-openclaw-voice-agent/runtime\nnpm install\nnpm run setup\nnpm run build\nnpm start\n```\n\nDuring setup, choose **Hermes Agent** when asked for the target platform.\n\n## Connect Amber MCP to Hermes\n\nAdd Amber's MCP server to your Hermes config, adjusting the path to your clone:\n\n```yaml\nmcp_servers:\n  amber_voice:\n    command: \"node\"\n    args:\n      - \"/absolute/path/to/amber-openclaw-voice-agent/runtime/dist/mcp-server.js\"\n    env:\n      AMBER_BRIDGE_URL: \"http://127.0.0.1:8000\"\n      BRIDGE_API_TOKEN: \"\"\n```\n\nRestart Hermes or run `/reload-mcp`, then ask Hermes which MCP tools are available. Amber should expose tools such as `make_call`, `get_call_status`, `get_call_history`, `contacts_lookup`, `calendar_query`, `crm`, and `bridge_health`.\n\n## Safety Rules\n\n### Outbound Calls\n\nNever place a call on the first step. Always:\n\n1. Clarify the recipient and objective.\n2. Resolve contact names with `contacts_lookup` where possible.\n3. Show the user the exact recipient, phone number, and objective.\n4. Only call `make_call` with `confirmed=true` after the user explicitly confirms.\n\nIf the call may involve a payment, deposit, contract, medical/legal/financial advice, or any irreversible commitment, stop and ask for explicit user approval first.\n\n### Inbound Screening\n\nWhen Amber screens calls, collect only what is needed:\n\n- caller name\n- callback number\n- message or purpose\n- any scheduling details the caller volunteers\n\nDo not solicit unnecessary sensitive personal data.\n\n### Calendar\n\nFor calendar lookups, disclose only free/busy availability. Do not reveal event names, locations, attendees, or private details.\n\nFor calendar creation, confirm title, date, start/end time, location/notes, and the person requesting the booking before creating the event.\n\n### CRM / Memory\n\nUse CRM context only when relevant and benign. Do not surface sensitive health, family, legal, financial, political/religious, intimate, or surprising details unless the caller raises them first or the task clearly requires it.\n\n## Useful Prompts\n\n- \"Use Amber to check whether the voice bridge is healthy.\"\n- \"Use Amber to find Miriam in contacts and prepare a call, but do not dial until I confirm.\"\n- \"Show my recent inbound call summaries.\"\n- \"Start inbound call screening.\"\n- \"Check if I am free tomorrow afternoon, but do not reveal event details.\"\n\n## Verification\n\nAfter setup, verify in this order:\n\n1. `npm start` shows the Amber bridge listening on `http://127.0.0.1:8000`.\n2. `curl http://127.0.0.1:8000/healthz` returns `{ \"ok\": true }`.\n3. Hermes shows the Amber MCP tools after restart or `/reload-mcp`.\n4. `bridge_health` succeeds from Hermes.\n5. A test inbound call reaches Amber.\n\n## Pitfalls\n\n- If Hermes cannot see Amber tools, check the `mcp_servers` path and run `/reload-mcp`.\n- If calls ring but Amber does not speak, check `PUBLIC_BASE_URL`, your public HTTPS tunnel or domain, Twilio webhooks, and OpenAI webhook settings.\n- If contact lookup fails on macOS, run `npm run sync-contacts` from the Amber runtime directory.\n- If calendar access fails on macOS, grant the helper access in System Settings → Privacy & Security → Calendar.\n\nFile v5.5.49:dashboard/README.md\n\n# Amber Voice Assistant Call Log Dashboard\n\nA beautiful web dashboard for viewing and managing call logs from the Amber Voice Assistant (Twilio/OpenAI SIP Bridge).\n\n## Features\n\n- 📞 Timeline view of all calls (inbound/outbound)\n- 📝 Full transcript display with captured messages\n- 📊 Statistics and filtering\n- 🔍 Search by name, number, or transcript content\n- 🔔 Follow-up tracking with localStorage persistence\n- ☎️ One-touch localhost test calls through the Amber bridge\n- 💵 Editable cost estimates from call duration and Realtime token usage\n- 🎚️ Per-test-call Realtime model switch for regular or mini\n- ⚡ Auto-refresh when data changes (every 30s)\n\n## Privacy and Access Control\n\nThis dashboard displays call logs, transcripts, captured messages, callback numbers, and contact-resolution data. Treat the generated `data/` directory and any browser/localStorage follow-up markers as sensitive communications records.\n\n- Run the server on loopback only (`127.0.0.1`) unless you put it behind authentication, TLS, and a trusted network boundary.\n- Do not bind this dashboard to all network interfaces on an untrusted LAN or public host.\n- Bridge API tokens entered in the dashboard are used for the active page session only and are not saved to localStorage.\n- Review and delete generated dashboard data according to your caller notice, consent, and retention policy.\n- Do not commit or publish generated dashboard data, contact caches, transcripts, or call logs.\n\n## Setup\n\n### 1. Environment Variables\n\nThe dashboard uses environment variables for configuration. Set these before running:\n\n```bash\n# Required for direction detection\nexport TWILIO_CALLER_ID=\"+16473709139\"\n\n# Optional - customize names\nexport ASSISTANT_NAME=\"Amber\"\nexport OPERATOR_NAME=\"Abe\"\n\n# Optional - customize paths (defaults work for standard setup)\nexport LOGS_DIR=\"$HOME/clawd/skills/amber-voice-assistant/runtime/logs\"\nexport OUTPUT_DIR=\"$HOME/clawd/skills/amber-voice-assistant/dashboard/data\"\n\n# Optional - contact name resolution\nexport CONTACTS_FILE=\"$HOME/clawd/skills/amber-voice-assistant/dashboard/contacts.json\"\n```\n\n**Environment variable defaults:**\n- `TWILIO_CALLER_ID`: *(required, no default)*\n- `ASSISTANT_NAME`: `\"Assistant\"`\n- `OPERATOR_NAME`: `\"the operator\"`\n- `LOGS_DIR`: `../runtime/logs` (relative to dashboard directory)\n- `OUTPUT_DIR`: `./data` (relative to dashboard directory)\n- `CONTACTS_FILE`: `./contacts.json` (relative to dashboard directory)\n\n### 2. Contact Resolution (Optional)\n\nTo resolve phone numbers to names, create a `contacts.json` file:\n\n```bash\ncp contacts.example.json contacts.json\n# Edit contacts.json with your actual contacts\n```\n\n**Format:**\n```json\n{\n  \"+14165551234\": \"John Doe\",\n  \"+16475559876\": \"Jane Smith\"\n}\n```\n\nPhone numbers should be in E.164 format (with `+` and country code).\n\n### 3. Processing Logs\n\nRun the log processor to generate dashboard data:\n\n```bash\n# Using environment variables\nnode process_logs.js\n\n# Or specify paths directly\nnode process_logs.js --logs /path/to/logs --out /path/to/data\n\n# Help\nnode process_logs.js --help\n```\n\nThe processor reads call logs from the `LOGS_DIR` (or `../runtime/logs` by default) and generates:\n- `data/calls.json` - processed call data\n- `data/calls.js` - same data as window.CALL_LOG_CALLS for file:// usage\n- `data/meta.json` - metadata about the processing run\n- `data/meta.js` - metadata as window.CALL_LOG_META\n\n**Quick update script:**\n```bash\n./update_data.sh\n```\n\n### 4. Viewing the Dashboard\n\n**Option 1: Local HTTP Server (Recommended)**\n\n```bash\nnode scripts/serve.js\n# Open http://127.0.0.1:8787/\n\n# Or custom loopback port\nnode scripts/serve.js --port 8080 --host 127.0.0.1\n\n# Only bind to a network interface when you have added authentication/TLS\n# and understand that call logs/transcripts may be exposed to that network.\n```\n\n**Option 2: File Protocol**\n\nOpen `index.html` directly in your browser. Browsing, filtering, and transcript views work with `file://` URLs. One-touch test calls require the local HTTP server above so `/api/call` can proxy safely to the loopback Amber bridge.\n\n### 5. Auto-Update (Optional)\n\nTo automatically reprocess logs when files change:\n\n```bash\nnode scripts/watch.js\n# Watches logs directory and regenerates data on changes (every 1.5s)\n\n# Or specify custom paths\nnode scripts/watch.js --logs /path/to/logs --out /path/to/data --interval-ms 2000\n```\n\n## Usage\n\n### Dashboard Interface\n\n- **Stats Cards:** Click to filter by type (inbound, outbound, messages, etc.)\n- **Search:** Filter by name, number, transcript content, or Call SID\n- **Follow-ups:** Click 🔔 icon on any call to mark for follow-up\n- **One-Touch Call:** Enter a test number/objective, choose regular or mini model, and start a local bridge call\n- **Cost Visibility:** Adjust local rate settings to estimate telephony and Realtime model spend\n- **Refresh:** Click ↻ button or wait for auto-refresh (30s)\n- **Transcript:** Click \"Transcript\" to expand full conversation\n\n### Command-Line Options\n\n**process_logs.js:**\n```\n--logs <dir>       Path to logs directory\n--out <dir>        Path to output directory\n--no-sample        Skip generating sample data\n-h, --help         Show help\n```\n\n**watch.js:**\n```\n--logs <dir>       Path to logs directory\n--out <dir>        Path to output directory\n--interval-ms <n>  Polling interval in milliseconds (default: 1500)\n-h, --help         Show help\n```\n\n**serve.js:**\n```\n--host <ip>        Bind address (default: 127.0.0.1)\n--port <n>         Port number (default: 8787)\n-h, --help         Show help\n```\n\n## File Structure\n\n```\ndashboard/\n├── index.html           # Main dashboard HTML\n├── process_logs.js      # Log processor (generalized)\n├── update_data.sh       # Quick update script\n├── contacts.json        # Your contacts (not tracked in git)\n├── contacts.example.json # Example contacts file\n├── README.md            # This file\n├── scripts/\n│   ├── serve.js         # Local HTTP server\n│   └── watch.js         # Auto-update watcher\n└── data/                # Generated data (git-ignored)\n    ├── calls.json\n    ├── calls.js\n    ├── meta.json\n    └── meta.js\n```\n\n## Integration with Amber Voice Assistant\n\nThis dashboard is designed to work standalone but integrates seamlessly with the Amber Voice Assistant skill:\n\n1. The skill writes logs to `../runtime/logs/` (relative to dashboard)\n2. Run `process_logs.js` to generate dashboard data\n3. View the dashboard via HTTP server or file://\n4. Optionally run `watch.js` for continuous updates\n\n## Customization\n\n**Change dashboard title:**\nEdit the `<title>` and `<h1>` tags in `index.html`.\n\n**Adjust auto-refresh interval:**\nEdit the `setInterval` call at the bottom of `index.html` (default: 30000ms).\n\n**Modify log processing logic:**\nEdit `process_logs.js` - all hardcoded values are now configurable via environment variables.\n\n## Troubleshooting\n\n**No calls showing up:**\n- Check that `LOGS_DIR` points to the correct directory\n- Ensure logs exist (incoming_*.json and rtc_*.txt files)\n- Run `process_logs.js` manually to see any errors\n\n**Direction not detected correctly:**\n- Set `TWILIO_CALLER_ID` to your Twilio phone number\n- The script detects outbound calls by matching the From header\n\n**Names not resolving:**\n- Create `contacts.json` with your phone numbers in E.164 format\n- Verify `CONTACTS_FILE` path is correct\n- Check console for \"Loaded N contacts\" message\n\n**Auto-refresh not working:**\n- Ensure you're using the HTTP server (not file://)\n- Check browser console for fetch errors\n- Verify `data/meta.json` is being updated\n\n## License\n\nPart of the Amber Voice Assistant skill. See parent directory for license information.\n\nArchive v5.5.48: 72 files, 226234 bytes\n\nFiles: AGENT.md (18304b), AMBER_SKILLS_SPEC.md (20389b), amber-skills/calendar/handler.js (8722b), amber-skills/calendar/SKILL.md (3989b), amber-skills/crm/DESIGN.md (19828b), amber-skills/crm/handler.js (16777b), amber-skills/crm/package-lock.json (16675b), amber-skills/crm/package.json (299b), amber-skills/crm/SKILL.md (6080b), amber-skills/send-message/handler.js (3323b), amber-skills/send-message/SKILL.md (2792b), amber-skills/SKILL_MANIFEST.json (255b), ASTERISK-IMPLEMENTATION-PLAN.md (14234b), dashboard/contacts.example.json (132b), dashboard/index.html (38716b), dashboard/process_logs.js (30483b), dashboard/README.md (7775b), dashboard/scripts/serve.js (8417b), dashboard/scripts/watch.js (4032b), dashboard/update_data.sh (609b), demo/demo-wizard.js (6641b), demo/README.md (4327b), DO-NOT-CHANGE.md (2036b), FEEDBACK.md (1431b), LICENSE (911b), NOTICE (158b), packaging/cowork/commands/call.md (1118b), packaging/cowork/commands/calls.md (852b), packaging/cowork/commands/screen.md (1055b), packaging/cowork/commands/voicemail.md (515b), packaging/cowork/README.md (3504b), packaging/cowork/skills/calendar/SKILL.md (1178b), packaging/cowork/skills/call-screening/SKILL.md (1844b), packaging/cowork/skills/contacts/SKILL.md (755b), packaging/cowork/skills/crm/SKILL.md (1747b), packaging/cowork/skills/phone-calls/SKILL.md (1652b), packaging/hermes/mcp_servers.yaml (407b), packaging/hermes/README.md (1264b), packaging/hermes/SKILL.md (4932b), README.md (13388b), references/architecture.md (1509b), references/positioning-backup-2026-04-18.md (1333b), references/release-checklist.md (1152b), runtime/package-lock.json (112565b), runtime/package.json (1051b), runtime/README.md (8781b), runtime/scripts/dist-watcher.cjs (3547b), runtime/scripts/sync-contacts.js (6764b), runtime/setup-wizard.js (21723b), runtime/src/config.ts (3779b), runtime/src/contacts-lookup.ts (5818b), runtime/src/contacts-query.swift (7581b), runtime/src/index.ts (95286b), runtime/src/local-helper-runner.ts (1481b), runtime/src/mcp-server.ts (30161b), runtime/src/providers/index.ts (2302b), runtime/src/providers/telnyx.ts (6969b), runtime/src/providers/twilio.ts (4746b), runtime/src/providers/types.ts (4510b), runtime/src/skills/api.ts (5349b), runtime/src/skills/index.ts (349b), runtime/src/skills/loader.ts (6412b), runtime/src/skills/router.ts (8031b), runtime/src/skills/types.ts (1527b), runtime/tsconfig.json (431b), scripts/setup_quickstart.sh (826b), scripts/validate_voice_env.sh (2574b), skill-card.md (3061b), SKILL.md (16961b), skills/amber-phone-agent/SKILL.md (4932b), UPGRADING.md (2706b), _meta.json (137b)\n\nFile v5.5.48:amber-skills/calendar/SKILL.md\n\n---\nname: calendar\nversion: 1.2.0\ndescription: \"Query and manage the operator's calendar — check availability and create new entries\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": true, \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [\"ical-query\"], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"calendar_query\", \"description\": \"Check the operator's calendar availability or create a new entry. PRIVACY RULE: When reporting availability to callers, NEVER disclose event titles, names, locations, or any details about what the operator is doing. Only share whether they are free or busy at a given time (e.g. 'free from 2pm to 4pm', 'busy until 3pm'). Treat all calendar event details as private and confidential. Calendar creation requires explicit confirmation from the caller before the action proceeds.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup\", \"create\"], \"description\": \"Whether to look up availability or create a new event\"}, \"range\": {\"type\": \"string\", \"description\": \"For lookup: today, tomorrow, week, or a specific date like 2026-02-23\", \"pattern\": \"^(today|tomorrow|week|\\\\d{4}-\\\\d{2}-\\\\d{2})$\"}, \"title\": {\"type\": \"string\", \"description\": \"For create: the event title\", \"maxLength\": 200}, \"start\": {\"type\": \"string\", \"description\": \"For create: start date-time like 2026-02-23T15:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"end\": {\"type\": \"string\", \"description\": \"For create: end date-time like 2026-02-23T16:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"calendar\": {\"type\": \"string\", \"description\": \"Optional: specific calendar name\", \"maxLength\": 100}, \"notes\": {\"type\": \"string\", \"description\": \"For create: event notes\", \"maxLength\": 500}, \"location\": {\"type\": \"string\", \"description\": \"For create: event location\", \"maxLength\": 200}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Required for create actions after the caller explicitly confirms the booking details.\"}}, \"required\": [\"action\"]}}}}\n---\n\n# Calendar Skill\n\nQuery the operator's calendar for availability and create new entries via `ical-query`.\n\n## Capabilities\n\n- **read**: Check free/busy availability for today, tomorrow, this week, or a specific date\n- **act**: Create new calendar entries (explicit confirmation required)\n\n## Privacy Rule\n\n**Event details are never disclosed to callers.** This is enforced at two levels:\n\n1. **Handler level** — the handler strips all event titles, names, locations, and notes from ical-query output before returning results. Only busy time slots (start/end times) are returned.\n2. **Model level** — the function description instructs Amber to only communicate availability (\"free from 2pm to 4pm\") and never reveal what the events are.\n\nAmber should say things like:\n- ✅ \"The operator is free between 2 and 4 this afternoon\"\n- ✅ \"They're busy until 3pm, then free for the rest of the day\"\n- ❌ \"They have a meeting with John at 2pm\" ← never\n- ❌ \"They're at the dentist from 10 to 11\" ← never\n\n## Security — Three Layers\n\nInput validation is enforced at three independent levels:\n\n1. **Schema level** — `range` is constrained by `pattern: ^(today|tomorrow|week|\\d{4}-\\d{2}-\\d{2})$`; `start`/`end` by `pattern: ^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}$`; freetext fields have `maxLength` caps. The LLM cannot produce out-of-spec values without violating the schema.\n2. **Handler level** — explicit validation before any exec call; rejects values that don't match expected formats even if schema is bypassed.\n3. **Exec level** — `context.exec()` takes a `string[]` and uses `execFileSync` (no shell spawned); arguments are passed as discrete tokens, not a shell-interpolated string.\n\n## Notes\n\n- Uses `/usr/local/bin/ical-query` — no network access, no gateway round-trip\n- Fast: direct local binary call (~100ms)\n- Calendar name optional — defaults to operator's primary calendar\n\nFile v5.5.48:amber-skills/crm/SKILL.md\n\n---\nname: crm\nversion: 1.0.0\ndescription: \"Local contact memory and interaction log for operator-reviewed phone follow-up\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": false, \"timeout_ms\": 3000, \"permissions\": {\"local_binaries\": [], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"crm\", \"description\": \"Manage local contacts and interaction history for operator-reviewed phone follow-up. Use lookup_contact at the start of inbound calls (automatic, using caller ID) to check if the caller is known and retrieve relevant operator-approved context. Use upsert_contact to save caller-volunteered contact details (name, email, company) when appropriate under the operator's caller notice/consent policy. Use log_interaction at the end of every call to record what happened (summary, outcome). Use context_notes for concise, relevant follow-up context; avoid sensitive, intimate, or unnecessary personal details. Do not ask robotic CRM questions; capture only details naturally relevant to the call purpose and retention policy.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup_contact\", \"upsert_contact\", \"log_interaction\", \"get_history\", \"search_contacts\", \"tag_contact\"], \"description\": \"The CRM action to perform\"}, \"phone\": {\"type\": \"string\", \"description\": \"Contact phone number in E.164 format (e.g. +14165551234)\", \"pattern\": \"^\\\\+[1-9]\\\\d{6,14}$|^$\"}, \"name\": {\"type\": \"string\", \"maxLength\": 200}, \"email\": {\"type\": \"string\", \"maxLength\": 200}, \"company\": {\"type\": \"string\", \"maxLength\": 200}, \"context_notes\": {\"type\": \"string\", \"maxLength\": 1000, \"description\": \"Concise operator-reviewed follow-up context. Avoid sensitive, intimate, or unnecessary personal details.\"}, \"summary\": {\"type\": \"string\", \"maxLength\": 500, \"description\": \"One-liner: what the call was about\"}, \"outcome\": {\"type\": \"string\", \"enum\": [\"message_left\", \"appointment_booked\", \"info_provided\", \"callback_requested\", \"transferred\", \"other\"], \"description\": \"Call outcome\"}, \"details\": {\"type\": \"object\", \"description\": \"Structured extras as key-value pairs (e.g. appointment_date, purpose)\"}, \"query\": {\"type\": \"string\", \"maxLength\": 200}, \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 50, \"default\": 10}, \"add\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}, \"remove\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}}, \"required\": [\"action\"]}}}}\n---\n\n# CRM Skill — Contact Memory for Voice Calls\n\nStores local, operator-reviewed caller context and interaction history for phone follow-up.\n\n## How It Works\n\n### On Every Inbound Call\n\n1. **Lookup** — Call `crm` with `lookup_contact` using the caller's phone number (from Twilio caller ID) only under the operator's caller notice/consent and retention policy.\n2. **If known** — Greet by name and use `context_notes` only when relevant to the call purpose. Avoid surprising rapport-building from intimate or unnecessary details.\n3. **If unknown** — Proceed normally, listen for their name.\n\n### During the Call\n\nWhen someone shares their name, email, company, or relevant follow-up details, upsert it via `crm.upsert_contact` only if that fits the operator's caller notice/consent and retention policy. Avoid collecting sensitive or unnecessary personal details.\n\n### At End of Call\n\n1. Log the interaction: `log_interaction` with summary + outcome\n2. Update context_notes with concise, relevant follow-up context, synthesizing with what was known before\n\n### On Outbound Calls\n\nSame exact flow: lookup at start, upsert + log_interaction at end.\n\n## API Reference\n\n| Action | Purpose |\n|--------|---------|\n| `lookup_contact` | Fetch contact + last 5 interactions + context_notes. Returns null if not found. |\n| `upsert_contact` | Create or update a contact by phone. Only provided fields are updated. |\n| `log_interaction` | Log a call: summary, outcome, details. Auto-creates contact if needed. |\n| `get_history` | Get past interactions for a contact (sorted newest-first). |\n| `search_contacts` | Search by name, email, company, notes. |\n| `tag_contact` | Add/remove tags (e.g. \"vip\", \"callback_later\"). |\n\n## Privacy\n\n- **Event details stay private.** Like the calendar skill, never disclose event details to callers.\n- **CRM context is personal.** The `context_notes` field is for Amber's internal memory, not for sharing call transcripts. Use it to inform conversation, not to recite it.\n- **PII storage.** Phone, name, email, company, context_notes, call summaries, and interaction metadata are stored locally in SQLite. Operators must provide appropriate caller notice/consent and retention/deletion practices. No network transmission, no external CRM by default.\n- **Review and correction.** Operators should periodically review, correct, or delete CRM entries so inaccurate transcript extraction or overly sensitive details do not persist.\n\n## Security\n\n- Synchronous SQLite (better-sqlite3) with parameterized queries — no SQL injection surface\n- Private number detection — calls from anonymous/blocked numbers are skipped entirely\n- Input validation at three levels: schema patterns, handler validation, database constraints\n- Database file created with mode 0600 (owner read/write only)\n\n## Examples\n\n**Greeting a known caller:**\n```\nAmber: \"Hi Sarah, good to hear from you again. I have you down as preferring afternoon callbacks.\"\n[context_notes remembered: \"Prefers afternoon callbacks for appointment changes.\"]\n```\n\n**Capturing relevant follow-up context:**\n```\nCaller: \"By the way, I got married last month!\"\nAmber: [only records this if it is relevant and appropriate under the operator's retention policy]\nAmber (aloud): \"That's wonderful! Congrats!\"\n```\n\n**End-of-call log:**\n```\nAmber: [calls log_interaction: summary=\"Called to reschedule Friday appointment\", outcome=\"appointment_booked\"]\nAmber: [calls upsert_contact with context_notes: \"Prefers afternoon callbacks. Usually calls to reschedule appointments.\"]\n```\n\nFile v5.5.48:amber-skills/send-message/SKILL.md\n\n---\nname: send-message\nversion: 1.0.0\ndescription: \"Leave a message for the operator — saved to call log and delivered via the operator's preferred messaging channel\"\nmetadata: {\"amber\": {\"capabilities\": [\"act\"], \"confirmation_required\": true, \"confirmation_prompt\": \"Would you like me to leave that message?\", \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [], \"telegram\": true, \"openclaw_action\": true, \"network\": false}, \"function_schema\": {\"name\": \"send_message\", \"description\": \"Leave a message for the operator. The message will be saved to the call log and sent to the operator via their messaging channel. IMPORTANT: Always confirm with the caller before calling this function — ask 'Would you like me to leave that message?' and only proceed after they confirm.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"message\": {\"type\": \"string\", \"description\": \"The caller's message to leave for the operator\", \"maxLength\": 1000}, \"caller_name\": {\"type\": \"string\", \"description\": \"The caller's name if they provided it\", \"maxLength\": 100}, \"callback_number\": {\"type\": \"string\", \"description\": \"A callback number if the caller provided one\", \"maxLength\": 30}, \"urgency\": {\"type\": \"string\", \"enum\": [\"normal\", \"urgent\"], \"description\": \"Whether the caller indicated this is urgent\"}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Must be true — only set after the caller has explicitly confirmed their message and given permission to send it. The router will reject this call if confirmed is not true.\"}}, \"required\": [\"message\", \"confirmed\"]}}}}\n---\n\n# Send Message\n\nAllows callers to leave a message for the operator. This skill implements the\n\"leave a message\" pattern that is standard in phone-based assistants.\n\n## Flow\n\n1. Caller indicates they want to leave a message\n2. Amber confirms: \"Would you like me to leave that message?\"\n3. On confirmation, the message is:\n   - **Always** saved to the call log first (audit trail)\n   - **Then** delivered to the operator via their configured messaging channel\n\n## Security\n\n- The recipient is determined by the operator's configuration — never by caller input\n- No parameter in the schema accepts a destination or recipient\n- Confirmation is required before sending (enforced programmatically at the router layer — the router checks `params.confirmed === true` before invoking; LLM prompt guidance is an additional layer, not the sole enforcement)\n- Message content is sanitized (max length, control characters stripped)\n\n## Delivery Failure Handling\n\n- If messaging delivery fails, the call log entry is marked with `delivery_failed`\n- The operator's assistant can check for undelivered messages during heartbeat checks\n- Amber tells the caller \"I've noted your message\" — never promises a specific delivery channel\n\nFile v5.5.48:packaging/cowork/skills/calendar/SKILL.md\n\n---\nname: calendar\ndescription: >\n  Check availability and create calendar entries. Used during calls to\n  book appointments and check schedule conflicts. Use when the user or\n  a caller needs to schedule something or check availability.\n---\n\n# Calendar\n\nQuery and manage the operator's calendar during or outside of calls.\n\n## MCP Tools\n\n### calendar_query\nLook up or create calendar events.\n- `action` (string, required): \"lookup\" or \"create\"\n- `query` (string, required for lookup): Natural language query (e.g., \"am I free Tuesday at 3pm?\")\n- `title` (string, required for create): Event title\n- `start` (string, required for create): Start time (ISO 8601)\n- `end` (string, required for create): End time (ISO 8601)\n- `calendar` (string): Which calendar to use (defaults to operator's primary)\n- `location` (string): Event location\n- `notes` (string): Event notes\n\n## Guidelines\n\n- When checking availability during a call, present options naturally (\"I see an opening at 2pm and 4pm — which works better?\")\n- Always confirm the final date, time, and details before creating an event\n- Include relevant context from the call in the event notes (who requested it, purpose)\n\nFile v5.5.48:packaging/cowork/skills/call-screening/SKILL.md\n\n---\nname: call-screening\ndescription: >\n  Screen incoming phone calls with an AI receptionist. Amber answers calls,\n  identifies the caller, determines the purpose, takes a message, and\n  delivers a structured summary. Use when the user wants to set up call\n  screening, check screened call results, or customize screening behavior.\n---\n\n# Call Screening\n\nAmber acts as an AI receptionist for inbound calls. She answers professionally,\ngathers information, and delivers structured summaries — so you only pick up\ncalls that matter.\n\nPrivacy: screening can process caller audio/metadata through your configured providers and may produce local transcripts/summaries. Configure caller notice/consent, retention, and access controls before production use.\n\n## Screening Flow\n\n1. **Greeting** — Amber answers with a customizable greeting\n2. **Identification** — Asks who's calling and what it's regarding\n3. **Information gathering** — Collects caller name, callback number, message\n4. **CRM lookup** — Checks if the caller is a known contact (auto-enriches context)\n5. **Calendar check** — If the caller wants to book time, checks availability\n6. **Summary delivery** — Sends a structured summary with all captured details\n\n## MCP Tools\n\n### start_screening\nEnable inbound call screening on the configured Twilio number.\n\n### stop_screening\nDisable screening (calls ring through normally).\n\n### get_screening_status\nCheck whether screening is currently active.\n\n## Customization\n\nThe screening personality, greeting, and behavior are defined in AGENT.md.\nUsers can edit this file to:\n- Change the assistant's name and personality\n- Customize the greeting message\n- Set business hours and after-hours behavior\n- Define which callers should be put through vs. screened\n- Add organization-specific context (company name, services, etc.)\n\nFile v5.5.48:packaging/cowork/skills/contacts/SKILL.md\n\n---\nname: contacts\ndescription: >\n  Look up contacts by name to resolve phone numbers before making calls.\n  Use when the user says \"call John\" instead of providing a phone number.\n---\n\n# Contacts\n\nResolve contact names to phone numbers for outbound calls.\n\n## Flow\n\n1. User says \"call [name]\" or \"/amber:call [name] [objective]\"\n2. Look up the name in the CRM via `crm(action: \"lookup\", identifier: \"name\")`\n3. If found, use the stored phone number\n4. If multiple matches, present options and let the user choose\n5. If not found, ask the user for the phone number\n\n## Guidelines\n\n- Be fuzzy with name matching — \"John\" should match \"John Smith\"\n- If ambiguous, always confirm before dialing (\"I found John Smith at +1-416-555-1234 — is that right?\")\n\nFile v5.5.48:packaging/cowork/skills/crm/SKILL.md\n\n---\nname: crm\ndescription: >\n  Contact memory and interaction log. Remembers callers across calls,\n  stores personal context, and logs every conversation. Use when looking\n  up a contact, adding notes about someone, or reviewing interaction history.\n---\n\n# CRM — Contact Memory\n\nAmber remembers everyone she talks to. The CRM stores contact details,\npersonal context, and a log of every interaction.\n\nPrivacy: CRM storage is local and should be opt-in. Enable it only after configuring caller notice/consent, retention/deletion practices, and access controls for the SQLite database.\n\n## MCP Tools\n\n### crm\nManage contacts and interaction history.\n- `action` (string, required): \"lookup\", \"create\", \"update\", \"log\", \"history\"\n- `identifier` (string): Phone number or name to look up\n- `name` (string): Contact name\n- `phone` (string): Phone number\n- `email` (string): Email address\n- `notes` (string): Personal context or notes about the contact\n- `tags` (array): Tags for categorization (e.g., [\"client\", \"vendor\", \"friend\"])\n\n## Automatic Behavior\n\n- On inbound calls, Amber automatically looks up the caller by phone number\n- If the caller is known, their context and history are loaded into the conversation\n- After every call, an interaction log entry is created with: date, summary, sentiment, outcome\n- New callers are added to the CRM only when CRM persistence is enabled and appropriate under your caller notice/consent policy\n\n## Guidelines\n\n- Use the CRM only for relevant follow-up context; avoid surprising personalization from sensitive or unnecessary personal details\n- Keep notes professional but useful — preferences, important dates, relationship context\n- Never expose CRM data to callers beyond what's socially appropriate\n\nFile v5.5.48:packaging/cowork/skills/phone-calls/SKILL.md\n\n---\nname: phone-calls\ndescription: >\n  Make and manage real phone calls through Twilio. Handles outbound calls\n  with a stated objective, monitors call progress, and returns transcripts\n  and summaries. Use when the user wants to call someone, check on a call,\n  or review call history.\n---\n\n# Phone Calls\n\nAmber can make and receive real phone calls via Twilio. This skill covers\nthe core telephony capabilities.\n\n## MCP Tools\n\n### make_call\nInitiate an outbound phone call.\n- `to` (string, required): Phone number in E.164 format (e.g., +14165551234)\n- `objective` (string, required): What to accomplish on the call\n- `mode` (string): \"conversation\" (default) or \"message\" (one-way delivery)\n\n### get_call_status\nCheck the status of an active or recent call.\n- `callId` (string, required): The call ID returned by make_call\n\n### end_call\nTerminate an active call.\n- `callId` (string, required): The call ID to end\n\n### get_call_history\nRetrieve recent call logs with transcripts.\n- `filter` (string): \"all\", \"inbound\", \"outbound\", \"missed\"\n- `limit` (number): Number of calls to return (default: 10)\n\n## Guidelines\n\n- Always confirm the recipient number and call objective with the user before dialing\n- If the objective involves payment, deposits, or financial commitments, explicitly ask the user for approval first\n- After each call, provide a summary including: who was called, outcome, key information exchanged, and caller sentiment\n- For outbound calls, Amber pursues the stated objective autonomously — she's not just reading a script\n- Calls have real-world consequences. Treat every call as if you're representing the user professionally\n\nFile v5.5.48:packaging/hermes/SKILL.md\n\n---\nname: amber-phone-agent\ndescription: Give Hermes Agent real phone capabilities through Amber's Twilio/OpenAI voice bridge and MCP tools.\nversion: \"5.5.39\"\nlicense: MIT\ncompatibility: Node.js 20+, Twilio account, OpenAI API key, Hermes Agent with MCP support\nplatforms: [macos, linux]\nmetadata:\n  author: batthis\n  repository: https://github.com/batthis/amber-openclaw-voice-agent\n  hermes:\n    tags: [phone, voice, twilio, openai, mcp, receptionist, calendar, crm]\n    category: communication\n    requires_toolsets: [mcp]\n    config:\n      - key: AMBER_RUNTIME_DIR\n        description: Absolute path to the Amber runtime directory containing dist/mcp-server.js\n        default: ~/amber-openclaw-voice-agent/runtime\n        prompt: Path to Amber runtime directory\n---\n\n# Amber — Phone-Capable Voice Agent for Hermes\n\n## When to Use\n\nUse Amber when the user wants Hermes to interact with the telephone network:\n\n- prepare or place an outbound phone call after explicit user confirmation\n- screen inbound calls through a Twilio number\n- check call history, transcripts, or summaries\n- resolve contacts before calling someone\n- check availability or create calendar entries during a phone workflow\n- use local CRM context for caller follow-up\n\nAmber is a sensitive communications system. Calls are real, may involve third parties, may be transcribed, and may be logged locally. Treat all caller details, transcripts, phone numbers, contact data, and calendar data as private.\n\n## Required Runtime\n\nThis skill is an instruction/activation wrapper for Hermes. The actual phone capability is provided by Amber's Node runtime and MCP server.\n\nBefore using this skill, install and configure Amber:\n\n```bash\ngit clone https://github.com/batthis/amber-openclaw-voice-agent.git\ncd amber-openclaw-voice-agent/runtime\nnpm install\nnpm run setup\nnpm run build\nnpm start\n```\n\nDuring setup, choose **Hermes Agent** when asked for the target platform.\n\n## Connect Amber MCP to Hermes\n\nAdd Amber's MCP server to your Hermes config, adjusting the path to your clone:\n\n```yaml\nmcp_servers:\n  amber_voice:\n    command: \"node\"\n    args:\n      - \"/absolute/path/to/amber-openclaw-voice-agent/runtime/dist/mcp-server.js\"\n    env:\n      AMBER_BRIDGE_URL: \"http://127.0.0.1:8000\"\n      BRIDGE_API_TOKEN: \"\"\n```\n\nRestart Hermes or run `/reload-mcp`, then ask Hermes which MCP tools are available. Amber should expose tools such as `make_call`, `get_call_status`, `get_call_history`, `contacts_lookup`, `calendar_query`, `crm`, and `bridge_health`.\n\n## Safety Rules\n\n### Outbound Calls\n\nNever place a call on the first step. Always:\n\n1. Clarify the recipient and objective.\n2. Resolve contact names with `contacts_lookup` where possible.\n3. Show the user the exact recipient, phone number, and objective.\n4. Only call `make_call` with `confirmed=true` after the user explicitly confirms.\n\nIf the call may involve a payment, deposit, contract, medical/legal/financial advice, or any irreversible commitment, stop and ask for explicit user approval first.\n\n### Inbound Screening\n\nWhen Amber screens calls, collect only what is needed:\n\n- caller name\n- callback number\n- message or purpose\n- any scheduling details the caller volunteers\n\nDo not solicit unnecessary sensitive personal data.\n\n### Calendar\n\nFor calendar lookups, disclose only free/busy availability. Do not reveal event names, locations, attendees, or private details.\n\nFor calendar creation, confirm title, date, start/end time, location/notes, and the person requesting the booking before creating the event.\n\n### CRM / Memory\n\nUse CRM context only when relevant and benign. Do not surface sensitive health, family, legal, financial, political/religious, intimate, or surprising details unless the caller raises them first or the task clearly requires it.\n\n## Useful Prompts\n\n- \"Use Amber to check whether the voice bridge is healthy.\"\n- \"Use Amber to find Miriam in contacts and prepare a call, but do not dial until I confirm.\"\n- \"Show my recent inbound call summaries.\"\n- \"Start inbound call screening.\"\n- \"Check if I am free tomorrow afternoon, but do not reveal event details.\"\n\n## Verification\n\nAfter setup, verify in this order:\n\n1. `npm start` shows the Amber bridge listening on `http://127.0.0.1:8000`.\n2. `curl http://127.0.0.1:8000/healthz` returns `{ \"ok\": true }`.\n3. Hermes shows the Amber MCP tools after restart or `/reload-mcp`.\n4. `bridge_health` succeeds from Hermes.\n5. A test inbound call reaches Amber.\n\n## Pitfalls\n\n- If Hermes cannot see Amber tools, check the `mcp_servers` path and run `/reload-mcp`.\n- If calls ring but Amber does not speak, check `PUBLIC_BASE_URL`, your public HTTPS tunnel or domain, Twilio webhooks, and OpenAI webhook settings.\n- If contact lookup fails on macOS, run `npm run sync-contacts` from the Amber runtime directory.\n- If calendar access fails on macOS, grant the helper access in System Settings → Privacy & Security → Calendar.\n\nFile v5.5.48:SKILL.md\n\n---\nname: amber-voice-assistant\ntitle: \"Amber — Give Your Agent Real Phone Capabilities\"\ndescription: \"Real phone assistant runtime with Twilio/OpenAI Realtime calling, inbound screening, confirmed outbound calls, local call logs/transcripts, optional local CRM/contact memory, calendar booking, contacts lookup, MCP tools, and a loopback-only dashboard.\"\nhomepage: https://github.com/batthis/amber-openclaw-voice-agent\nmetadata: {\"openclaw\":{\"emoji\":\"☎️\",\"requires\":{\"env\":[],\"optionalEnv\":[\"AMBER_ENABLE_OUTBOUND_CALLS\",\"AMBER_REALTIME_MODEL\",\"AMBER_CRM_ENABLED\",\"AMBER_CRM_TRANSCRIPT_ENRICHMENT\",\"OPENCLAW_GATEWAY_URL\",\"TWILIO_WEBHOOK_STRICT\",\"VOICE_PROVIDER\",\"VOICE_WEBHOOK_SECRET\",\"ASSISTANT_NAME\",\"OPERATOR_NAME\",\"AMBER_CRM_DB_PATH\",\"AGENT_MD_PATH\",\"DEFAULT_CALENDAR\",\"AMBER_CONTACTS_EXTENDED\"],\"anyBins\":[\"node\",\"ical-query\"]},\"permissions\":{\"network\":true,\"env\":true,\"webhooks\":true,\"localFiles\":[\"runtime/logs/\",\"runtime/contacts-cache.json\",\"~/.config/amber/crm.sqlite\"],\"localBinaries\":[\"node\",\"ical-query\"],\"mcpTools\":[\"prepare_call\",\"start_call\",\"call_history\",\"crm\",\"contacts_lookup\",\"calendar\",\"screening_control\",\"bridge_health\"],\"externalServices\":[\"Twilio or compatible voice provider\",\"OpenAI Realtime/API\",\"optional OpenClaw Gateway\"]},\"install\":[{\"id\":\"runtime\",\"kind\":\"node\",\"cwd\":\"runtime\",\"label\":\"Install Amber runtime (cd runtime && npm ci && npm run build)\"},{\"id\":\"crm-skill\",\"kind\":\"node\",\"cwd\":\"amber-skills/crm\",\"label\":\"Install optional CRM skill dependencies (cd amber-skills/crm && npm ci)\"}]}}\n---\n\n# Amber — Give Your Agent Real Phone Capabilities\n\n## Overview\n\nAmber gives any OpenClaw deployment **real phone capabilities for agents**. It ships with a **production-ready Twilio + OpenAI Realtime bridge** (`runtime/`) for confirmed phone workflows: inbound answering, call screening, prepared outbound workflows, confirmed scheduling over a real telephone number, local call logs/transcripts, optional local CRM/contact memory, contacts lookup, MCP tools, and a loopback-only dashboard.\n\nAmber is a sensitive communications system. It can process call audio/transcripts through configured voice and AI providers, store local call logs, maintain a local CRM, read/write the operator calendar, expose local MCP tools, and optionally use an Apple Contacts export for name-to-number resolution. Operators should configure caller notice/consent, retention/deletion practices, and least-privilege provider credentials before production use.\n\nPrivacy defaults: local CRM lookup/logging is disabled unless `AMBER_CRM_ENABLED=true`, and post-call transcript enrichment is disabled unless `AMBER_CRM_TRANSCRIPT_ENRICHMENT=true`. Enable those only after setting caller notice/consent and retention/deletion practices.\n\n**✨ New in v5.4.0:** Amber now ships as an **MCP plugin** with 9 tools — prepare confirmed calls by name, check call history, query CRM contacts, manage calendar, and control call screening. It works with Claude Desktop/Cowork and other MCP-capable clients or agent harnesses once configured. Includes Apple Contacts integration and a code-enforced call confirmation safeguard to prevent wrong-number dials.\n\n**✨ Also:** Interactive setup wizard (`npm run setup`) validates credentials in real-time and generates a working `.env` file — no manual configuration needed. Once setup is complete, Amber is prompt-based: ask your OpenClaw agent to prepare confirmed calls, answer/screen callers, schedule confirmed appointments, or handle phone workflows in natural language.\n\n## See it in action\n\n![Setup Wizard Demo](demo/demo.gif)\n\n**[▶️ Watch the interactive demo on asciinema.org](https://asciinema.org/a/l1nOHktunybwAheQ)** (copyable text, adjustable speed)\n\n*The interactive wizard validates credentials, detects ngrok, and generates a complete `.env` file in minutes.*\n\n### What's included\n\n- **Runtime bridge** (`runtime/`) — a complete Node.js server that connects Twilio phone calls to OpenAI Realtime with OpenClaw brain-in-the-loop\n- **Amber Skills** (`amber-skills/`) — modular mid-call capabilities (CRM, calendar, log & forward message) with a spec for building your own\n- **Built-in CRM** — local SQLite contact database; Amber can greet callers by name and use operator-approved context naturally on calls, with operator review/correction responsibility\n- **Call log dashboard** (`dashboard/`) — browse call history, transcripts, captured messages, estimated costs, and one-touch localhost test calls with regular/mini Realtime model selection\n- **Setup & validation scripts** — preflight checks, env templates, quickstart runner\n- **Architecture docs & troubleshooting** — call flow diagrams, common failure runbooks\n- **Safety guardrails** — outbound calls require code-enforced confirmation; payment escalation, consent boundaries, and explicit confirmation for calendar writes are documented\n\n## 🔌 Amber Skills — Extensible by Design\n\nAmber ships with a growing library of **Amber Skills** — modular capabilities that plug directly into live voice conversations. Each skill exposes a structured function that Amber can call mid-call, letting you compose powerful voice workflows without touching the bridge code.\n\n### 👤 CRM — Contact Memory *(v5.3.0)*\n\nAmber can maintain operator-reviewed caller memory across calls, limited to relevant follow-up context under the operator's notice, consent, and reten\n\nArchive v5.5.47: 72 files, 226194 bytes\n\nFiles: AGENT.md (18304b), AMBER_SKILLS_SPEC.md (20389b), amber-skills/calendar/handler.js (8722b), amber-skills/calendar/SKILL.md (3989b), amber-skills/crm/DESIGN.md (19828b), amber-skills/crm/handler.js (16777b), amber-skills/crm/package-lock.json (16675b), amber-skills/crm/package.json (299b), amber-skills/crm/SKILL.md (6080b), amber-skills/send-message/handler.js (3323b), amber-skills/send-message/SKILL.md (2792b), amber-skills/SKILL_MANIFEST.json (255b), ASTERISK-IMPLEMENTATION-PLAN.md (14234b), dashboard/contacts.example.json (132b), dashboard/index.html (38716b), dashboard/process_logs.js (30483b), dashboard/README.md (7775b), dashboard/scripts/serve.js (8417b), dashboard/scripts/watch.js (4032b), dashboard/update_data.sh (609b), demo/demo-wizard.js (6641b), demo/README.md (4327b), DO-NOT-CHANGE.md (2036b), FEEDBACK.md (1431b), LICENSE (911b), NOTICE (158b), packaging/cowork/commands/call.md (1118b), packaging/cowork/commands/calls.md (852b), packaging/cowork/commands/screen.md (1055b), packaging/cowork/commands/voicemail.md (515b), packaging/cowork/README.md (3504b), packaging/cowork/skills/calendar/SKILL.md (1178b), packaging/cowork/skills/call-screening/SKILL.md (1844b), packaging/cowork/skills/contacts/SKILL.md (755b), packaging/cowork/skills/crm/SKILL.md (1747b), packaging/cowork/skills/phone-calls/SKILL.md (1652b), packaging/hermes/mcp_server...","readmeExcerpt":"Skill: Amber — Phone-Capable Voice Agent Owner: batthis Summary: Give your agent a phone number. Amber answers calls, places confirmed outbound calls, completes phone tasks, logs transcripts, and exposes MCP tools. Tags: ai-phone:5.5.48, answering-service:5.5.48, assistant:5.5.48, calendar:5.5.48, call-screening:5.5.48, inbound_calls:5.5.48, latest:5.5.50, openclaw:5.5.48, outbound_calls:5.5.48, phone:5.5.48, phone-s","codeSnippets":[],"executableExamples":[{"language":"text","snippet":"Amber: \"Hi Sarah, good to hear from you again. I have you down as preferring afternoon callbacks.\"\n[context_notes remembered: \"Prefers afternoon callbacks for appointment changes.\"]"},{"language":"text","snippet":"Caller: \"By the way, I got married last month!\"\nAmber: [only records this if it is relevant and appropriate under the operator's retention policy]\nAmber (aloud): \"That's wonderful! Congrats!\""},{"language":"text","snippet":"Amber: [calls log_interaction: summary=\"Called to reschedule Friday appointment\", outcome=\"appointment_booked\"]\nAmber: [calls upsert_contact with context_notes: \"Prefers afternoon callbacks. Usually calls to reschedule appointments.\"]"},{"language":"bash","snippet":"git clone https://github.com/batthis/amber-openclaw-voice-agent.git\ncd amber-openclaw-voice-agent/runtime\nnpm install\nnpm run setup\nnpm run build\nnpm start"},{"language":"yaml","snippet":"mcp_servers:\n  amber_voice:\n    command: \"node\"\n    args:\n      - \"/absolute/path/to/amber-openclaw-voice-agent/runtime/dist/mcp-server.js\"\n    env:\n      AMBER_BRIDGE_URL: \"http://127.0.0.1:8000\"\n      BRIDGE_API_TOKEN: \"\""},{"language":"bash","snippet":"cd dashboard && node scripts/serve.js   # → http://localhost:8787"}],"parameters":null,"dependencies":[],"permissions":[],"extractedFiles":[{"path":"amber-skills/calendar/SKILL.md","content":"---\nname: calendar\nversion: 1.2.0\ndescription: \"Query and manage the operator's calendar — check availability and create new entries\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": true, \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [\"ical-query\"], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"calendar_query\", \"description\": \"Check the operator's calendar availability or create a new entry. PRIVACY RULE: When reporting availability to callers, NEVER disclose event titles, names, locations, or any details about what the operator is doing. Only share whether they are free or busy at a given time (e.g. 'free from 2pm to 4pm', 'busy until 3pm'). Treat all calendar event details as private and confidential. Calendar creation requires explicit confirmation from the caller before the action proceeds.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup\", \"create\"], \"description\": \"Whether to look up availability or create a new event\"}, \"range\": {\"type\": \"string\", \"description\": \"For lookup: today, tomorrow, week, or a specific date like 2026-02-23\", \"pattern\": \"^(today|tomorrow|week|\\\\d{4}-\\\\d{2}-\\\\d{2})$\"}, \"title\": {\"type\": \"string\", \"description\": \"For create: the event title\", \"maxLength\": 200}, \"start\": {\"type\": \"string\", \"description\": \"For create: start date-time like 2026-02-23T15:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"end\": {\"type\": \"string\", \"description\": \"For create: end date-time like 2026-02-23T16:00\", \"pattern\": \"^\\\\d{4}-\\\\d{2}-\\\\d{2}T\\\\d{2}:\\\\d{2}$\"}, \"calendar\": {\"type\": \"string\", \"description\": \"Optional: specific calendar name\", \"maxLength\": 100}, \"notes\": {\"type\": \"string\", \"description\": \"For create: event notes\", \"maxLength\": 500}, \"location\": {\"type\": \"string\", \"description\": \"For create: event location\", \"maxLength\": 200}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Required for create actions after the caller explicitly confirms the booking details.\"}}, \"required\": [\"action\"]}}}}\n---\n\n# Calendar Skill\n\nQuery the operator's calendar for availability and create new entries via `ical-query`.\n\n## Capabilities\n\n- **read**: Check free/busy availability for today, tomorrow, this week, or a specific date\n- **act**: Create new calendar entries (explicit confirmation required)\n\n## Privacy Rule\n\n**Event details are never disclosed to callers.** This is enforced at two levels:\n\n1. **Handler level** — the handler strips all event titles, names, locations, and notes from ical-query output before returning results. Only busy time slots (start/end times) are returned.\n2. **Model level** — the function description instructs Amber to only communicate availability (\"free from 2pm to 4pm\") and never reveal what the events are.\n\nAmber should say things like:\n- ✅ \"The operator is free between 2 and 4 this afternoon\"\n- ✅ \"They're busy until 3pm, then free for the rest of the day\"\n- ❌ \"They have a me"},{"path":"amber-skills/crm/SKILL.md","content":"---\nname: crm\nversion: 1.0.0\ndescription: \"Local contact memory and interaction log for operator-reviewed phone follow-up\"\nmetadata: {\"amber\": {\"capabilities\": [\"read\", \"act\"], \"confirmation_required\": false, \"timeout_ms\": 3000, \"permissions\": {\"local_binaries\": [], \"telegram\": false, \"openclaw_action\": false, \"network\": false}, \"function_schema\": {\"name\": \"crm\", \"description\": \"Manage local contacts and interaction history for operator-reviewed phone follow-up. Use lookup_contact at the start of inbound calls (automatic, using caller ID) to check if the caller is known and retrieve relevant operator-approved context. Use upsert_contact to save caller-volunteered contact details (name, email, company) when appropriate under the operator's caller notice/consent policy. Use log_interaction at the end of every call to record what happened (summary, outcome). Use context_notes for concise, relevant follow-up context; avoid sensitive, intimate, or unnecessary personal details. Do not ask robotic CRM questions; capture only details naturally relevant to the call purpose and retention policy.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"action\": {\"type\": \"string\", \"enum\": [\"lookup_contact\", \"upsert_contact\", \"log_interaction\", \"get_history\", \"search_contacts\", \"tag_contact\"], \"description\": \"The CRM action to perform\"}, \"phone\": {\"type\": \"string\", \"description\": \"Contact phone number in E.164 format (e.g. +14165551234)\", \"pattern\": \"^\\\\+[1-9]\\\\d{6,14}$|^$\"}, \"name\": {\"type\": \"string\", \"maxLength\": 200}, \"email\": {\"type\": \"string\", \"maxLength\": 200}, \"company\": {\"type\": \"string\", \"maxLength\": 200}, \"context_notes\": {\"type\": \"string\", \"maxLength\": 1000, \"description\": \"Concise operator-reviewed follow-up context. Avoid sensitive, intimate, or unnecessary personal details.\"}, \"summary\": {\"type\": \"string\", \"maxLength\": 500, \"description\": \"One-liner: what the call was about\"}, \"outcome\": {\"type\": \"string\", \"enum\": [\"message_left\", \"appointment_booked\", \"info_provided\", \"callback_requested\", \"transferred\", \"other\"], \"description\": \"Call outcome\"}, \"details\": {\"type\": \"object\", \"description\": \"Structured extras as key-value pairs (e.g. appointment_date, purpose)\"}, \"query\": {\"type\": \"string\", \"maxLength\": 200}, \"limit\": {\"type\": \"integer\", \"minimum\": 1, \"maximum\": 50, \"default\": 10}, \"add\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}, \"remove\": {\"type\": \"array\", \"items\": {\"type\": \"string\", \"maxLength\": 50}, \"maxItems\": 10}}, \"required\": [\"action\"]}}}}\n---\n\n# CRM Skill — Contact Memory for Voice Calls\n\nStores local, operator-reviewed caller context and interaction history for phone follow-up.\n\n## How It Works\n\n### On Every Inbound Call\n\n1. **Lookup** — Call `crm` with `lookup_contact` using the caller's phone number (from Twilio caller ID) only under the operator's caller notice/consent and retention policy.\n2. **If known** — Greet by name and use `context_notes` only when relevant to the call purpose. Avoid surprising"},{"path":"amber-skills/send-message/SKILL.md","content":"---\nname: send-message\nversion: 1.0.0\ndescription: \"Leave a message for the operator — saved to call log and delivered via the operator's preferred messaging channel\"\nmetadata: {\"amber\": {\"capabilities\": [\"act\"], \"confirmation_required\": true, \"confirmation_prompt\": \"Would you like me to leave that message?\", \"timeout_ms\": 5000, \"permissions\": {\"local_binaries\": [], \"telegram\": true, \"openclaw_action\": true, \"network\": false}, \"function_schema\": {\"name\": \"send_message\", \"description\": \"Leave a message for the operator. The message will be saved to the call log and sent to the operator via their messaging channel. IMPORTANT: Always confirm with the caller before calling this function — ask 'Would you like me to leave that message?' and only proceed after they confirm.\", \"parameters\": {\"type\": \"object\", \"properties\": {\"message\": {\"type\": \"string\", \"description\": \"The caller's message to leave for the operator\", \"maxLength\": 1000}, \"caller_name\": {\"type\": \"string\", \"description\": \"The caller's name if they provided it\", \"maxLength\": 100}, \"callback_number\": {\"type\": \"string\", \"description\": \"A callback number if the caller provided one\", \"maxLength\": 30}, \"urgency\": {\"type\": \"string\", \"enum\": [\"normal\", \"urgent\"], \"description\": \"Whether the caller indicated this is urgent\"}, \"confirmed\": {\"type\": \"boolean\", \"description\": \"Must be true — only set after the caller has explicitly confirmed their message and given permission to send it. The router will reject this call if confirmed is not true.\"}}, \"required\": [\"message\", \"confirmed\"]}}}}\n---\n\n# Send Message\n\nAllows callers to leave a message for the operator. This skill implements the\n\"leave a message\" pattern that is standard in phone-based assistants.\n\n## Flow\n\n1. Caller indicates they want to leave a message\n2. Amber confirms: \"Would you like me to leave that message?\"\n3. On confirmation, the message is:\n   - **Always** saved to the call log first (audit trail)\n   - **Then** delivered to the operator via their configured messaging channel\n\n## Security\n\n- The recipient is determined by the operator's configuration — never by caller input\n- No parameter in the schema accepts a destination or recipient\n- Confirmation is required before sending (enforced programmatically at the router layer — the router checks `params.confirmed === true` before invoking; LLM prompt guidance is an additional layer, not the sole enforcement)\n- Message content is sanitized (max length, control characters stripped)\n\n## Delivery Failure Handling\n\n- If messaging delivery fails, the call log entry is marked with `delivery_failed`\n- The operator's assistant can check for undelivered messages during heartbeat checks\n- Amber tells the caller \"I've noted your message\" — never promises a specific delivery channel"},{"path":"packaging/cowork/skills/calendar/SKILL.md","content":"---\nname: calendar\ndescription: >\n  Check availability and create calendar entries. Used during calls to\n  book appointments and check schedule conflicts. Use when the user or\n  a caller needs to schedule something or check availability.\n---\n\n# Calendar\n\nQuery and manage the operator's calendar during or outside of calls.\n\n## MCP Tools\n\n### calendar_query\nLook up or create calendar events.\n- `action` (string, required): \"lookup\" or \"create\"\n- `query` (string, required for lookup): Natural language query (e.g., \"am I free Tuesday at 3pm?\")\n- `title` (string, required for create): Event title\n- `start` (string, required for create): Start time (ISO 8601)\n- `end` (string, required for create): End time (ISO 8601)\n- `calendar` (string): Which calendar to use (defaults to operator's primary)\n- `location` (string): Event location\n- `notes` (string): Event notes\n\n## Guidelines\n\n- When checking availability during a call, present options naturally (\"I see an opening at 2pm and 4pm — which works better?\")\n- Always confirm the final date, time, and details before creating an event\n- Include only the minimum scheduling context needed in event notes (for example, requester name and appointment purpose).\n- Do not store sensitive personal, medical, financial, legal, or unnecessary caller details in calendar notes unless the caller explicitly confirms those details are needed for the appointment."},{"path":"packaging/cowork/skills/call-screening/SKILL.md","content":"---\nname: call-screening\ndescription: >\n  Screen incoming phone calls with an AI receptionist. Amber answers calls,\n  identifies the caller, determines the purpose, takes a message, and\n  delivers a structured summary. Use when the user wants to set up call\n  screening, check screened call results, or customize screening behavior.\n---\n\n# Call Screening\n\nAmber acts as an AI receptionist for inbound calls. She answers professionally,\ngathers information, and delivers structured summaries — so you only pick up\ncalls that matter.\n\nPrivacy: screening can process caller audio/metadata through your configured providers and may produce local transcripts/summaries. Configure caller notice/consent, retention, and access controls before production use.\n\n## Screening Flow\n\n1. **Greeting** — Amber answers with a customizable greeting\n2. **Identification** — Asks who's calling and what it's regarding\n3. **Information gathering** — Collects caller name, callback number, message\n4. **CRM lookup** — Checks if the caller is a known contact (auto-enriches context)\n5. **Calendar check** — If the caller wants to book time, checks availability\n6. **Summary delivery** — Sends a structured summary with all captured details\n\n## MCP Tools\n\n### start_screening\nEnable inbound call screening on the configured Twilio number.\n\n### stop_screening\nDisable screening (calls ring through normally).\n\n### get_screening_status\nCheck whether screening is currently active.\n\n## Customization\n\nThe screening personality, greeting, and behavior are defined in AGENT.md.\nUsers can edit this file to:\n- Change the assistant's name and personality\n- Customize the greeting message\n- Set business hours and after-hours behavior\n- Define which callers should be put through vs. screened\n- Add organization-specific context (company name, services, etc.)"}],"languages":[],"docsSourceLabel":"CLAWHUB","editorialOverview":null,"editorialQuality":{"score":100,"threshold":65,"status":"thin","wordCount":2191,"uniquenessScore":37,"reasons":["uniqueness-below-45"]}},"media":{"evidence":{"source":"no-media","verified":false,"confidence":"low","updatedAt":"2026-10-09T04:23:34.821Z","emptyReason":"No screenshots, media assets, or demo links are available."},"primaryImageUrl":null,"mediaAssetCount":0,"assets":[],"demoUrl":null},"ownerResources":{"evidence":{"source":"unclaimed","verified":false,"confidence":"low","updatedAt":"2026-10-09T04:23:34.821Z","emptyReason":"This page has not been claimed by the agent owner."},"hasCustomPage":false,"customPageUpdatedAt":null,"customLinks":[],"structuredLinks":{"docsUrl":null,"demoUrl":null,"supportUrl":null,"pricingUrl":null,"statusUrl":null},"customPage":null},"relatedAgents":{"evidence":{"source":"protocol-neighbors","verified":false,"confidence":"medium","updatedAt":"2026-10-10T00:36:24.917Z","emptyReason":null},"items":[{"id":"8ebccd8e-3863-4187-8355-c3f14e1f9edf","entityType":"agent","canonicalPath":"/agent/iofficeai-aionui","slug":"iofficeai-aionui","name":"AionUi","description":"Free, local, open-source 24/7 Cowork app and OpenClaw for Gemini CLI, Claude Code, Codex, OpenCode, Qwen Code, Goose CLI, Auggie, and more | 🌟 Star if you like it!","url":"https://github.com/iOfficeAI/AionUi","homepage":"https://www.aionui.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-10-09T19:11:12.944Z","createdAt":"2026-02-25T03:38:16.584Z","downloads":null},{"id":"b917f68a-ebff-438e-84f8-3f4b2494c0bc","entityType":"agent","canonicalPath":"/agent/activepieces-activepieces","slug":"activepieces-activepieces","name":"activepieces","description":"AI Agents & MCPs & AI Workflow Automation • (~400 MCP servers for AI agents) • AI Automation / AI Agent with MCPs • AI Workflows & AI Agents • MCPs for AI Agents","url":"https://github.com/activepieces/activepieces","homepage":"https://www.activepieces.com","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-15T02:22:12.426Z","createdAt":"2026-02-25T03:38:12.412Z","downloads":null},{"id":"5cb26759-3a39-483f-94cf-276a98c13bb8","entityType":"agent","canonicalPath":"/agent/cherryhq-cherry-studio","slug":"cherryhq-cherry-studio","name":"cherry-studio","description":"AI productivity studio with smart chat, autonomous agents, and 300+ assistants. Unified access to frontier LLMs","url":"https://github.com/CherryHQ/cherry-studio","homepage":"https://cherry-ai.com","source":"GITHUB_REPOS","protocols":["MCP","OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-04-11T14:38:40.986Z","createdAt":"2026-02-25T03:38:19.379Z","downloads":null},{"id":"6f6582d0-5d76-4f0f-b81d-86520247950b","entityType":"agent","canonicalPath":"/agent/copilotkit-copilotkit","slug":"copilotkit-copilotkit","name":"CopilotKit","description":"The Frontend for Agents & Generative UI. React + Angular","url":"https://github.com/CopilotKit/CopilotKit","homepage":"https://docs.copilotkit.ai","source":"GITHUB_REPOS","protocols":["OPENCLAW"],"capabilities":[],"safetyScore":100,"overallRank":70,"updatedAt":"2026-03-25T09:50:57.846Z","createdAt":"2026-02-25T03:39:14.617Z","downloads":null}],"links":{"hub":"/agent","source":"/agent/source/clawhub","protocols":[{"label":"OpenClaw","href":"/agent/protocol/openclew"}]}}}