Paste this into your coding agent
instinct: this guide as a working app
Signup that provisions the computer and the phone line in about a minute, a “Start texting” screen with the QR code, and a warm-paper workspace with chat, reminders, memory, connectors, and persona. Express plus vanilla JS, no build step. Clone it, add both keys,
npm start.Your server owns the phone line
Two keys live on your server and nowhere else. The Agent37sk_live_ key manages every instance in your workspace; the Inkbox admin key manages every identity in your Inkbox organization, including who may reach each one. Neither enters an instance. What the agent gets is narrow:
- An Inkbox key scoped to its own identity: it can send and receive as that one line, and cannot change who is allowed to text it.
- A notify token in its env, so it can post a notification to your app and your app can tell which instance sent it.
1
Create the user's computer
One instance per user at signup, with a public port on Keep only the token’s hash:
8765 (where the Inkbox plugin listens), auto-sleep, a budget, and a notify token:env is write-only, so the raw token lives in the container alone. The create returns once the computer runs; poll GET /v1/health on the instance URL until healthy is true before the next step.The user tag is what makes a retry safe. A slow create can outlast its response (a server restart, or fetch giving up after its 5-minute header timeout), and the instance exists anyway. Before creating, look for it in GET /v1/instances, where each instance carries its user, and reuse it rather than leaving one billing with no owner. Save the token’s hash before the create, so it still matches an instance a retry finds.2
Give it a phone line and an inbox
Create the user’s Inkbox identity, upload its contact-card photo, lock it to the user’s number and email address, and mint a key scoped to it. Each call is one request with the admin key; Text your agent on iMessage shows every one in curl and Node:The identity comes with its email address (
node
identity.email_address) already live. The handle is what the user texts to connect, so generate a readable one: the assistant’s name plus a few random characters, since handles are globally unique and never freed. Save the handle before the create; on a retry, GET /identities/{handle} finds an identity whose response was lost.Phone whitelist mode covers iMessage, SMS, and calls in both directions. Mail is whitelisted inbound only, so the assistant can still email anyone for the user, while mail from any other sender is stored by Inkbox and never delivered: no webhook, no turn. Keep the rule ids. When the user changes their number or address, create the new rule, then DELETE the old one by its id (.../contact-rules/{id} or .../mail-contact-rules/{id}); a rule you never delete keeps working.3
Install iMessage, email, and calls
One exec call installs the Inkbox SDK into the Hermes venv, installs the vendor’s Hermes plugin, points it at the public port, and runs its non-interactive bootstrap with the scoped key on stdin. Then restart the instance so the Hermes gateway loads the plugin:The script is step 5 of Text your agent on iMessage. Two parts of it matter for a consumer product:
INKBOX_PUBLIC_URLswitches the plugin from an outbound tunnel to signed webhooks on the public port, so a text wakes a sleeping instance and each user’s computer bills disk alone between conversations.--voice-aisets the identity’s incoming calls to Inkbox Voice AI, a hosted voice agent with its own instructions: it does not readSOUL.mdor the memory files. Per the plugin’s docs, your agent gets the transcript when the call ends.
4
Give it a name and a personality
Hermes reads The example composes the file from the user’s settings every time they save the persona, so a persona edit and a changed app URL both land the same way, from the next conversation on. Memory lives beside it:
~/.hermes/SOUL.md as its identity when a conversation starts (a text thread, an email thread, a web chat, or a cron firing) and keeps that version for the rest of the conversation, so an edit reaches new conversations only. Write it with the Files API on the instance URL. Besides the persona, it has to say three things the agent cannot know on its own: it can follow up later (the gateway otherwise tells it a conversation ends when the turn does), how to text its owner, and how to notify your app.~/.hermes/SOUL.md
~/.hermes/memories/USER.md (what the agent knows about the user) and MEMORY.md (its own notes). Read and write them with the same endpoint to give users a memory page they can edit.5
Show the Start texting screen
Inkbox returns the whole screen in one call: the router number, the connect command, an Show the QR code on desktop and the
sms: link with the command pre-drafted, and a QR code of the same draft.curl
sms_link as a button on a phone. The user sends the drafted text, the router answers with the assistant’s contact card, and from then on they text it like anyone else. Put the email address beside it: forwarding a thread or CCing the assistant works from the first minute.6
Reminders that text first
Reminders are crons: each firing wakes the instance, even from sleep, and runs the prompt as a fresh turn in which the agent texts the result with And the agent creates its own when a user texts “remind me to call mom on Sunday”, because
inkbox_send_imessage. Your app creates them from a form:SOUL.md told it about agent37 cron. Both kinds show up in GET /v1/instances/{id}/crons; the example labels the ones it did not create as set by the assistant. POST .../crons/{cronId}/run fires one now, and .../runs lists firings with the session_id each opened, so the reminder’s conversation is one click away.7
Connect apps by link
Managed Composio is on every instance. List the catalog with Open
GET /v1/instances/{id}/integrations/toolkits, and start a connection with a callbackUrl that returns the user to a page of yours:curl
redirectUrl; the callback page says “Gmail connected. You can go back to your messages now.” Then confirm with GET .../integrations/connections. The agent can also start a connection itself over its built-in Composio tools and text the user the link, which is how Instinct connects apps.Messages you first, in the app too
A text is the main way the assistant reaches the user, and a web notification is the fallback for someone who has not connected their phone yet. The agent runs thecurl from its SOUL.md; your endpoint finds the user by instance_id, compares the SHA-256 of the presented token with the stored hash, and saves the note for the page to show:
node
AGENT37_INSTANCE_ID is set in every container, so the agent always knows which instance it is.
Worth knowing
- Cost per user. An instance on the default 2 vCPU / 4 GB shape bills about $0.36 a month asleep and $4.76 if it never sleeps, plus the model spend its budget caps. Inkbox is free for 3 identities, $30 a month for 10, and $200 a month for 100; past that is Inkbox Enterprise. See choosing a vendor.
- The user texts first. On Inkbox’s shared lines, a user connects with
connect @handlebefore the agent can message them. A line that starts conversations cold comes with Inkbox’s Startup plan. - Instance limit. Your workspace’s instance limit counts sleeping and stopped instances, so one instance per user caps self-serve at 200 users until you ask for more.
- Updates keep the plugin.
POST /v1/instances/{id}/updateresets the Hermes venv, where the Inkbox SDK lives; the install adds a line to~/.agent37/hooks/post-restart.shthat reinstalls it on the next boot. The plugin and its settings live under~/.hermesand survive. - Texts and emails show up as threads. The plugin runs its conversations in Hermes sessions of its own, and
GET /v1/sessionslists those beside your web chat’s, so your app can show them. Their first message carries a marker such as[inkbox:email from=...]that names the channel; the list’spreviewis too short to reach it, so read those sessions once and cache the result. Show them read-only: a reply sent into one withPOST /v1/responsesstays in that session and never goes out by email or iMessage.USER.mdandMEMORY.mdare shared across all of them. - What the lock does not cover. A mail rule matches the sender’s From address, and From addresses can be forged, so treat email as a weaker lock than the phone. Nothing verifies that the number or address belongs to the user unless you add a code check. And the agent still reads the web and the user’s connected apps, which can carry instructions of their own; the
SOUL.mdline about other people is a prompt, not a control. - Deleting a user means
DELETE /v1/instances/{id}and InkboxDELETE /identities/{handle}. Count a404as done, and drop your own record only after both succeed, or a failed delete leaves an instance billing with no owner. The instance’s data stays in backup storage for seven days before it is purged, so do not promise immediate erasure. - No purchases. The example’s
SOUL.mdhas the agent prepare a checkout and hand the link back rather than pay. - WhatsApp and Telegram connect from your own app too: see Messaging channels.
- You hold your own Inkbox account; Agent37 never provisions one. See Text your agent on iMessage for the vendor terms.