Skip to main content
Instinct is an assistant you text instead of an app you open: it has its own phone line and email address, runs errands on its own computer, and texts you first. This guide builds that product on Agent37: one persistent computer per user running Hermes (asleep between conversations), one Inkbox identity per user for iMessage, email, and calls, and a small web workspace for chat, reminders, memory, connected apps, and the assistant’s persona.
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 Agent37 sk_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.
The owner whitelist is the other half. A new Inkbox identity accepts anyone who knows its handle or its email address, and whoever gets through runs a full turn with the user’s memory, connected apps, and terminal. So signup asks for the user’s number and email address, and your server locks the identity to both before handing out the connect code. Everything else (the user’s chat history, memory, connected accounts) lives on that user’s own instance.
1

Create the user's computer

One instance per user at signup, with a public port on 8765 (where the Inkbox plugin listens), auto-sleep, a budget, and a notify token:
Keep only the token’s hash: 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:
node
The identity comes with its email address (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_URL switches 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-ai sets the identity’s incoming calls to Inkbox Voice AI, a hosted voice agent with its own instructions: it does not read SOUL.md or the memory files. Per the plugin’s docs, your agent gets the transcript when the call ends.
The exec returns in a few seconds and the restart in a few more: the example app’s whole signup, from the form to the QR code, took under a minute in testing.
4

Give it a name and a personality

Hermes reads ~/.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
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/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 sms: link with the command pre-drafted, and a QR code of the same draft.
curl
Show the QR code on desktop and the 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 inkbox_send_imessage. Your app creates them from a form:
And the agent creates its own when a user texts “remind me to call mom on Sunday”, because 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 GET /v1/instances/{id}/integrations/toolkits, and start a connection with a callbackUrl that returns the user to a page of yours:
curl
Open 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 the curl 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 @handle before 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}/update resets the Hermes venv, where the Inkbox SDK lives; the install adds a line to ~/.agent37/hooks/post-restart.sh that reinstalls it on the next boot. The plugin and its settings live under ~/.hermes and survive.
  • Texts and emails show up as threads. The plugin runs its conversations in Hermes sessions of its own, and GET /v1/sessions lists 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’s preview is too short to reach it, so read those sessions once and cache the result. Show them read-only: a reply sent into one with POST /v1/responses stays in that session and never goes out by email or iMessage. USER.md and MEMORY.md are 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.md line about other people is a prompt, not a control.
  • Deleting a user means DELETE /v1/instances/{id} and Inkbox DELETE /identities/{handle}. Count a 404 as 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.md has 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.
This guide and the example are not affiliated with Instinct or Spear Street Technology.