Install with Codex or Claude Copy this prompt, paste it into Codex, Claude, or another assistant, and let it review the skill page and install it for you.
A direct command skips the review prompt. Inspect the source before running it.
Destination policy: Outbound SMS and calls support NANP (+1) destinations only, including all NANP territories. Non-NANP international destinations are rejected before any Dialpad API request. Always use E.164 format (e.g., +14155551234); SMS country inference normalizes ten-digit NANP input to explicit +1 E.164. The generated message schedules.send_now command is disabled because stored recipients cannot be validated locally; schedule updates must repeat phone recipients through --data as a JSON array; meeting updates must set call_out through --data as a JSON boolean; and generated meeting create/update commands cannot enable call-out.
Escaping: Use single quotes for inline --message values containing $ to prevent shell expansion (e.g., 'Price is $10').
Safer message input: Prefer --message-file or --message-stdin for pricing text, multi-line copy, or anything shell-sensitive.
Supported agent interface: use bin/*.py wrappers for normal work. They are the stable command contract for agents.
Operator-only surfaces:generated/dialpad and scripts/* are for manual troubleshooting, storage inspection, or operational maintenance, not normal agent task execution.
Auth canonical source:DIALPAD_API_KEY is canonical. DIALPAD_TOKEN is only needed for manual generated CLI troubleshooting (bridge command in Setup below).
SMS sender safety:--from and --profile work|sales are supported. Prefer explicit --from for deterministic routing.
--profile maps to configured env vars:
work: DIALPAD_PROFILE_WORK_FROM
sales: DIALPAD_PROFILE_SALES_FROM
default fallback order: DIALPAD_DEFAULT_FROM_NUMBER, then DIALPAD_DEFAULT_PROFILE
--allow-profile-mismatch permits explicit/profile mismatches when intentional
--dry-run prints sender resolution and the exact message/request preview without an API call
For merged agent-draft flow, keep DIALPAD_DRAFT_CALLBACK_URL aligned with the
OpenClaw dialpad-draft-callback plugin callbackUrl config. The default
host.docker.internal URL is for gateway-container to host-webhook delivery.
Group intro:bin/send_group_intro.py mirrors intro messages as two one-to-one SMS sends (mirrored_fallback) because true group threads are unsupported via this wrapper.
Call history:bin/list_calls.py is the supported call-history command for agents. Use --json when downstream automation needs a deterministic response envelope.
Call transcripts:bin/get_call_transcript.py is the supported transcript retrieval command for agents. It uses Dialpad's plural transcript endpoints (GET /api/v2/transcripts/{call_id} and optional review URL GET /api/v2/transcripts/{call_id}/url); singular /api/v2/transcript/{id} is not the supported endpoint. It is transcript-only; AI recap, CRM enrichment, and follow-up drafting are intentionally separate work.
SMS thread history: Before saying a contact was not already messaged, run bin/list_sms_thread.py --phone PHONE --json and check has_outbound / outbound_count. This local SQLite history is the supported current-turn response-state check. Set DIALPAD_SMS_DB when the runtime SMS database lives outside the default /home/art/clawd/logs/sms.db path; AlphaClaw uses /home/art/niemand/logs/sms.db.
SMS export sync:bin/sync_sms_export.py imports Dialpad Stats text export metadata into local SQLite for direct Dialpad UI sends and other out-of-band messages. It skips existing message IDs to preserve webhook-captured text.
Create/Update Contact Behavior:bin/create_contact.py upserts shared/local contacts by phone/email match (or forces create with --allow-duplicate). bin/update_contact.py updates by --id with partial fields.
Current-turn verification: "Already sent" and "Already updated" are only valid after a fresh current-turn tool result, not from stale session memory. If the current turn has not verified the action yet, say that plainly and run the tool now.
SMS receipt ledger: Successful sends through bin/send_sms.py, both legs of bin/send_group_intro.py, and approval-lane sends append authoritative JSONL receipt evidence to DIALPAD_SMS_RECEIPT_LEDGER, defaulting to /data/.openclaw/state/dialpad/sms-receipts.jsonl. Failed sends and dry runs do not write receipts.
Receipt phrasing: When confirming an SMS send to an operator, always include To: <number> in the receipt text so the downstream guard can bind the claim to the ledger recipient.
Identity guardrail: For first-contact work, soft signals like first name, area code, industry, or job title are not enough to merge or update a contact. Keep uncertain identity draft-only and let the CRM layer prove the match before mutating anything.
Inbound context guardrail: Webhook inboundContext briefs explain identity evidence, recent SMS/call continuity, source status, and draft basis. Low-confidence Sales SMS and missed calls may get generic approval drafts, but not personalized claims. Known contacts only get context-aware, CRM-aware, meeting-aware, or availability-aware approval drafts when identity confidence is high and relevant continuity is no older than 14 days; stale or degraded context stays brief-only. Calendar lookup is only for obvious meeting logistics and demo-prospect availability requests, not every inbound SMS. If availability cannot be verified, do not turn the CRM generic fallback into a scheduling reply. Demo-context missed calls may include operator-only prior-comms provenance from SMS/Gmail counts; raw comms bodies must not be copied into customer-facing draft text. If a model is used for final wording, it must receive compact tool-call facts plus the deterministic fallback and fail closed to that fallback on unsafe or unsupported output.
Inbound automation guardrail: Dialpad inbound hooks may create SMS approval drafts, but they must not send customer SMS directly. Use bin/approve_sms_draft.py only with a real human actor id and an operator-only DIALPAD_SMS_APPROVAL_TOKEN; agent/bot actors are rejected by the trusted approval ledger.
Operator-approved agent sends: Agents may send SMS with bin/send_sms.py after explicit current-turn operator approval. When resolving a shown approval draft, pass --resolve-draft-id plus --approval-actor-id/--approval-actor-username so the draft closes as an audited agent_direct_send; that actor context is agent-asserted unless it came through a trusted Telegram/shell approval surface. Risky drafts still require the existing two-step approval state before --confirm-risk can send.
Opt-out guardrail: Explicit opt-out language is a hard stop. Do not create override drafts or send follow-ups on those threads unless a human operator handles the conversation outside automation.
Operator notification ownership: One inbound SMS or missed call should create one operator-visible Telegram message per target by default. When the local Dialpad Telegram approval card and OpenClaw hook route point at the same Telegram destination, the local card owns visibility and the hook is context-only with deliver=false. Use DIALPAD_ALLOW_DUPLICATE_OPERATOR_DELIVERY=1 only for intentional same-target fanout.