Give your OpenClaw agent its own Inkbox identity:
a mailbox, iMessage, a phone number for calls and SMS, voice, contacts, notes, and an internet address.
Keep OpenClaw reachable from anywhere without forking OpenClaw.
Email · Calls · SMS / MMS · iMessage · Contacts · Notes
Status: outbound tools, read tools, bundled skills, setup wizard, doctor checks, SMS/MMS batching, 1:1 and group text conversations, inbound email/SMS/iMessage/voice, realtime phone calls, post-call actions, and package-included skills are implemented. ClawHub publishing is still pending.
- An installed OpenClaw agent,
2026.5.19or newer. Start at openclaw.ai or follow the OpenClaw install docs. - The recommended OpenClaw installer for macOS, Linux, or WSL2:
curl -fsSL https://openclaw.ai/install.sh | bash
openclaw --versionThen onboard OpenClaw and configure a model provider. We recommend using either an OpenAI API key or a ChatGPT/Codex subscription:
openclaw onboard
openclaw configureIf you already manage Node yourself, the OpenClaw docs also support installing the CLI with npm before running the same onboard/configure commands:
npm install -g openclaw@latest- An Inkbox account or API key.
openclaw inkbox setupcan guide a new agent identity through signup/setup.
Run these from the plugin checkout after the OpenClaw prerequisite above is installed:
git clone https://github.com/inkbox-ai/openclaw-plugin.git
cd openclaw-plugin
npm install
npm run build
openclaw --version
openclaw plugins install -l ./Configure Inkbox:
openclaw inkbox setup
openclaw inkbox doctorThe setup wizard writes channels.inkbox into the active OpenClaw profile and adds the Inkbox tool group to the profile's tool policy.
Start the gateway:
openclaw gateway runKeep that process running. On startup the plugin opens an Inkbox tunnel, configures mail/text/iMessage webhook subscriptions and the incoming-call URL, and routes inbound email, SMS, iMessage, and calls into OpenClaw sessions.
Restart the gateway after changing Inkbox config, updating the plugin, or re-running setup:
openclaw gateway restartIf you started the gateway in the foreground with openclaw gateway run, press Ctrl+C in that terminal and start it again:
openclaw gateway runopenclaw inkbox setup walks the current OpenClaw profile through Inkbox configuration:
- Authenticates to Inkbox or uses the API key already present in config.
- Resolves or creates the Inkbox agent identity for this OpenClaw agent.
- Stores an agent-scoped API key, the identity handle, and webhook signing key in
channels.inkbox. - Optionally provisions a local SMS + voice phone number without asking for a state.
- Offers to enable iMessage for the agent (existing or freshly created), then walks you through connecting your iPhone: text the connect command to the Inkbox iMessage router, message the agent once, and receive a welcome reply confirming the channel.
- Points the identity's mailbox, phone number, and iMessage events at the agent-owned Inkbox tunnel.
Existing phone numbers are configured the same way as freshly provisioned numbers: inbound SMS goes to the gateway webhook, and calls use
auto_acceptwith the gateway media WebSocket. - Prints the final mailbox/phone summary.
If setup provisions a new local phone number, it waits for any inbound SMS START to that number before finishing. It also seeds ~/.openclaw/inkbox/identity-state.json so openclaw inkbox doctor can show useful channel state.
Inkbox reachability is controlled server-side with mailbox and phone contact rules in the Inkbox Console. The plugin does not create a second local inbound allowlist unless you explicitly set allowedInboundContactIds.
Preferred config shape:
{
"channels": {
"inkbox": {
"apiKey": "ApiKey_xxxxxxxxxxxx",
"identity": "my-agent-handle",
"signingKey": "whsec_xxxxxxxxxxxx"
}
},
"tools": {
"allow": ["inkbox"]
}
}Equivalent config commands:
openclaw config set channels.inkbox.enabled true --strict-json
openclaw config set channels.inkbox.apiKey "ApiKey_xxxxxxxxxxxx"
openclaw config set channels.inkbox.identity "my-agent-handle"
openclaw config set channels.inkbox.signingKey "whsec_xxxxxxxxxxxx"
openclaw config set tools.allow '["inkbox"]' --strict-json
openclaw config validateEnv vars are also supported by the plugin and CLI:
export INKBOX_API_KEY="ApiKey_xxxxxxxxxxxx"
export INKBOX_IDENTITY="my-agent-handle"
export INKBOX_SIGNING_KEY="whsec_xxxxxxxxxxxx"
export INKBOX_BASE_URL="https://your-inkbox-api.example"Legacy plugin-scoped config under plugins.entries.inkbox.config still works, but new installs should use channels.inkbox.
"inkbox" in tools.allow enables the required tools. Optional tools must be listed by name.
Common full-access smoke allowlist, excluding vault plaintext tools:
openclaw config set tools.allow '[
"inkbox",
"inkbox_forward_email",
"inkbox_place_call",
"inkbox_mark_emails_read",
"inkbox_list_texts",
"inkbox_get_text",
"inkbox_mark_text_read",
"inkbox_mark_text_conversation_read",
"inkbox_imessage_triage_number",
"inkbox_list_imessage_assignments",
"inkbox_send_imessage_reaction",
"inkbox_mark_imessage_conversation_read",
"inkbox_update_note",
"inkbox_delete_note",
"inkbox_list_mail_contact_rules",
"inkbox_create_mail_contact_rule",
"inkbox_update_mail_contact_rule",
"inkbox_delete_mail_contact_rule",
"inkbox_list_phone_contact_rules",
"inkbox_create_phone_contact_rule",
"inkbox_update_phone_contact_rule",
"inkbox_delete_phone_contact_rule",
"inkbox_list_contact_access",
"inkbox_grant_contact_access",
"inkbox_revoke_contact_access",
"inkbox_list_note_access",
"inkbox_grant_note_access",
"inkbox_revoke_note_access",
"inkbox_whoami"
]' --strict-jsonAdd vault tools only when the identity has vault access and the gateway environment has the vault unlock key:
export INKBOX_VAULT_KEY="..."
openclaw config set tools.allow '[
"inkbox",
"inkbox_credentials_list",
"inkbox_credentials_get_login",
"inkbox_credentials_get_api_key",
"inkbox_credentials_get_ssh_key",
"inkbox_totp_code"
]' --strict-jsonCalls can use raw Inkbox call media through OpenAI Realtime. OpenAI GA Realtime requires an OpenAI API key; ChatGPT/Codex subscription OAuth profiles are not used for this path. During openclaw inkbox setup, the wizard looks for an existing OpenAI API key in channels.inkbox.voiceRealtime.providers.openai.apiKey, INKBOX_REALTIME_API_KEY, an OpenClaw openai API-key auth profile, or OPENAI_API_KEY. Environment keys are setup-time discovery inputs unless the wizard validates and persists them into channels.inkbox.voiceRealtime.providers.openai.apiKey. If it finds one, it asks whether to enable Realtime calls, validates access to gpt-realtime-2, and stores the validated key in the Inkbox Realtime provider config. If no key is found, it prompts for one and validates it before enabling Realtime.
export INKBOX_REALTIME_API_KEY="sk-..."
openclaw configure
openclaw inkbox setup
openclaw gateway runRealtime calls receive the agent's Inkbox handle, mailbox, phone number, caller contact metadata, and outbound-call purpose before greeting. The realtime voice model can call openclaw_agent_consult, inkbox_register_post_call_action, inkbox_edit_post_call_action, inkbox_delete_post_call_action, and inkbox_hang_up_call. If realtime auth/provider config is unavailable or validation fails, calls use Inkbox STT/TTS unless voiceRealtime.fallbackToInkboxSttTts is set to false.
Optional realtime overrides:
openclaw config set channels.inkbox.voiceRealtime.provider openai
openclaw config set channels.inkbox.voiceRealtime.model gpt-realtime-2
openclaw config set channels.inkbox.voiceRealtime.voice cedarDisable realtime:
openclaw config set channels.inkbox.voiceRealtime.enabled false --strict-jsonCalls — inbound and outbound — can run over either of two lines, and the agent picks the one that matches the channel it's talking on:
- The dedicated phone number. The agent's own number (the same line SMS uses). Outbound calls present this number; inbound calls to it ring the agent.
- The shared Inkbox iMessage line. The agent can also place and receive voice calls with a person it's connected to over iMessage, over the same shared line that person already messages. The underlying number is never surfaced — Inkbox resolves it from the iMessage connection — and it only works for people already connected over iMessage (an unknown caller is rejected; an outbound call with no connection is refused).
Inbound answering is configured once per identity (auto_accept → open the call bridge WebSocket), so a single setting governs both lines. Outbound, the agent sets origination on inkbox_place_call (dedicated_number / shared_imessage_number), or omits it — the plugin then uses whichever line is the only one available, or the line matching the conversation's channel when both are.
iMessage works differently from SMS: the agent does not get its own iMessage number. People connect to the agent through the Inkbox iMessage router, and each connected person gets a dedicated thread with the agent.
- Enable iMessage for the agent during
openclaw inkbox setup(or later by re-running it). Enablement is stored on the Inkbox identity, not in local config. - From an iPhone, text the connect command (for example
connect @my-agent-handle) to the Inkbox iMessage router number. The wizard prints both, and the agent can also share them via theinkbox_imessage_triage_numbertool. - Inkbox texts back from the number assigned to that conversation. Send any first message there — the agent can only reply after you message it first (recipient-first; there is no cold outreach over iMessage).
- The setup wizard waits for that first message and replies with a welcome confirming the channel. From then on, the gateway routes the thread into the same contact-keyed OpenClaw session as email/SMS/voice, and the agent replies over iMessage in that thread.
If a person disconnects the agent, outbound sends to that conversation fail until they reconnect through the router and message the agent again. Conversation rows expose assignmentStatus (active/released) so the agent can see this, and inkbox_list_imessage_assignments lists who is currently connected. Outbound delivery transitions (imessage.sent, imessage.delivered, imessage.delivery_failed) arrive as webhooks and are logged by the gateway without waking the agent, matching the SMS lifecycle handling.
While the agent composes a reply, the recipient sees a typing indicator — the gateway pulses it until the response sends (or the agent decides no reply is warranted). Inbound tapbacks (imessage.reaction_received) do wake the agent: the turn carries the reaction, the message it targets, and a response policy — a question tapback usually warrants a reply, while love/like/laugh/dislike usually resolve to [SILENT] and nothing is sent.
Once someone is connected over iMessage, the agent can also place and receive voice calls with them over that same shared line — see Two calling lines. This works even for an agent that has no dedicated phone number.
openclaw inkbox setup
openclaw inkbox doctor
openclaw inkbox whoami
openclaw doctor
openclaw statusUseful OpenClaw commands while iterating:
openclaw config file
openclaw config get channels.inkbox
openclaw config validate
openclaw plugins list
openclaw skills list
openclaw logsOptional provider-specific auth examples:
openclaw models auth login --provider openai --set-default
openclaw models auth login --provider openai-codex --set-defaultAfter the gateway prints [gateway] ready, [inkbox] tunnel open, mail/text subscriptions configured, and the incoming-call URL wired:
- Run
openclaw inkbox doctor. - Text
STARTto the agent's Inkbox phone number from every phone the agent should text. - Send the agent an SMS and verify it replies in the same SMS thread.
- If iMessage is enabled, connect via the Inkbox iMessage router, message the agent, and verify it replies in the same iMessage thread.
- Send the agent an email and verify it replies from its Inkbox mailbox.
- Call the agent phone number and ask for its handle, email, and phone.
- Ask during a call for a post-call SMS or email follow-up, then verify it sends after hangup.
- Ask the agent to save a contact and an Inkbox note, then ask it to read them back.
| Field | Required | Default | Description |
|---|---|---|---|
apiKey |
yes | - | Agent-scoped Inkbox API key. Admin keys are accepted by setup only so it can mint an agent-scoped key. |
identity |
yes | - | Inkbox agent identity handle. |
signingKey |
inbound | - | Webhook HMAC secret. Required for inbound email/SMS/iMessage/calls. |
baseUrl |
no | SDK default | Override Inkbox API base URL. |
tunnelName |
no | identity handle | Override Inkbox tunnel name. |
publicUrl |
no | - | Public OpenClaw URL. If omitted, the plugin opens an Inkbox tunnel. |
allowedRecipients |
no | - | Outbound recipient allowlist. Empty means no local outbound filtering. |
allowedInboundContactIds |
no | - | Optional local inbound allowlist by Inkbox contact UUID. Empty means Inkbox contact rules decide reachability. |
sms.batchDelayMs |
no | 0 |
Inbound SMS and iMessage fragment batching window. |
voiceTranscriptCoalesceMs |
no | plugin default | Non-realtime voice transcript coalescing window. |
voiceAgentPrewarm |
no | plugin default | Prewarm the voice path when the gateway starts. |
voiceRealtime.enabled |
no | auto | Use raw phone media with an OpenClaw realtime voice provider. Set false to force Inkbox STT/TTS. |
voiceRealtime.provider |
no | openai |
Realtime provider id, for example openai. |
voiceRealtime.model |
no | provider default | Realtime model override, for example gpt-realtime-2. |
voiceRealtime.voice |
no | cedar |
Realtime voice name. |
voiceRealtime.toolPolicy |
no | owner |
Tool policy for realtime openclaw_agent_consult. |
voiceRealtime.consultPolicy |
no | substantive |
When realtime calls should consult the main OpenClaw agent. |
voiceRealtime.providers.openai.apiKey |
no | - | OpenAI API key validated by setup and used for Realtime calls. |
voiceRealtime.fallbackToInkboxSttTts |
no | true |
Fall back to Inkbox STT/TTS when realtime is unavailable. |
vault.keyEnvVar |
no | INKBOX_VAULT_KEY |
Env var containing the vault unlock key. |
Required by default:
- Outbound:
inkbox_send_email,inkbox_send_sms,inkbox_send_imessage - Email reads:
inkbox_list_unread_emails,inkbox_list_emails,inkbox_get_email,inkbox_get_email_thread - SMS reads:
inkbox_list_text_conversations,inkbox_get_text_conversation(conversation-ID aware, groups included by default) - iMessage reads:
inkbox_list_imessage_conversations,inkbox_get_imessage_conversation - Voice reads:
inkbox_list_calls,inkbox_list_call_transcripts - Contacts:
inkbox_lookup_contact,inkbox_get_contact,inkbox_list_contacts,inkbox_create_contact,inkbox_update_contact,inkbox_delete_contact - Notes:
inkbox_list_notes,inkbox_get_note,inkbox_create_note
Optional:
- Outbound:
inkbox_forward_email,inkbox_place_call - Lifecycle:
inkbox_mark_emails_read,inkbox_list_texts,inkbox_get_text,inkbox_mark_text_read,inkbox_mark_text_conversation_read,inkbox_mark_imessage_conversation_read - iMessage:
inkbox_imessage_triage_number,inkbox_list_imessage_assignments,inkbox_send_imessage_reaction - Notes:
inkbox_update_note,inkbox_delete_note - Contact rules:
inkbox_list_mail_contact_rules,inkbox_create_mail_contact_rule,inkbox_update_mail_contact_rule,inkbox_delete_mail_contact_rule,inkbox_list_phone_contact_rules,inkbox_create_phone_contact_rule,inkbox_update_phone_contact_rule,inkbox_delete_phone_contact_rule - Identity access:
inkbox_list_contact_access,inkbox_grant_contact_access,inkbox_revoke_contact_access,inkbox_list_note_access,inkbox_grant_note_access,inkbox_revoke_note_access - Vault:
inkbox_credentials_list,inkbox_credentials_get_login,inkbox_credentials_get_api_key,inkbox_credentials_get_ssh_key,inkbox_totp_code - Diagnostic:
inkbox_whoami
The package includes all skills/*/SKILL.md files in npm tarballs.
| Skill | Trigger |
|---|---|
inkbox-troubleshooting |
Runtime/config errors, failed tools, readiness issues |
inkbox-email-triage |
Checking or replying to Inkbox email |
inkbox-sms-responder |
Sending, replying to, or triaging SMS |
inkbox-imessage-responder |
Sending, replying to, or triaging iMessage |
inkbox-outbound-calling |
Placing calls to numbers or contacts |
inkbox-call-review |
Reviewing calls and transcripts |
inkbox-contact-lookup |
Resolving, creating, or updating contacts |
inkbox-contact-rules |
Managing mail/phone allow and block rules |
inkbox-identity-access |
Granting/revoking contact or note visibility |
inkbox-notes-memory |
Saving, retrieving, or updating Inkbox notes |
inkbox-credential-use |
Fetching vault credentials or TOTP codes |
inkbox-outreach-sequence |
Multi-step outreach over email/SMS |
npm run typecheck
npm test
npm run build
npm_config_cache=/tmp/npm-cache npm pack --dry-run- Plugin, not fork: uses OpenClaw plugin SDK, channel gateway, tools, HTTP routes, CLI, and bundled skills.
- Agent-scoped: runtime should use an Inkbox agent-scoped API key.
- Tunnel-first inbound: with a signing key, gateway opens an Inkbox tunnel, creates mail/text webhook subscriptions (plus an identity-owned iMessage subscription when enabled), and wires the incoming-call URL.
- Voice: Inkbox STT/TTS fallback path and realtime raw-media path both route through the same call WebSocket.
- Post-call actions: realtime calls can register, edit, delete, and dispatch work for the main OpenClaw agent after hangup.
- Hangup: realtime calls expose a two-step hangup tool so the agent can say goodbye before dropping the phone leg.
- Identity-aware calls: call prompts include agent handle/mailbox/phone/tunnel and known caller contact metadata.
See PLAN.md for the longer architecture history and roadmap.
MIT - see LICENSE.
