Appearance
Agent setup
This page is written for an agent that has been told to read it. Follow it top to bottom. Every step is safe to repeat: re-running a step that already happened changes nothing. Nothing on this page asks you to handle a token, and you must never ask the human for one.
The goal: connect this agent to the human's OH HAI inbox, then send one notification so the human can see the connection is live.
First, answer one question
Can you run a shell command on this machine?
- Yes: follow With a shell. This gives the human the full CLI — including a session and bridge, which is what lets them reach you while you run.
- No: follow Without a shell. You will connect through the hosted MCP server instead, and the human has to do one step for you.
With a shell
1. Install the CLI
macOS / Linux:
sh
curl -fsSL https://ohhai.app/install.sh | shWindows (PowerShell):
powershell
irm https://ohhai.app/install.ps1 | iexThe installer downloads a standalone binary for this OS and architecture, verifies its SHA-256 checksum before making it executable, and puts oh-hai on PATH. If it fails (no prebuilt binary for this host), fall back to npm, which needs Node 24 or newer:
sh
npm install -g @oh-hai/cliCheck:
sh
oh-hai --versionIf oh-hai is already installed, skip to the next step.
2. Log in
sh
oh-hai loginThis runs the device-code flow. It prints a verification URL and a short code to stderr, tries to open the human's browser at that URL, and then polls the Hub every 5 seconds for up to 15 minutes waiting for approval. Nothing is typed or pasted by you; the token is never printed. When the human approves, the CLI stores the token in the OS keychain (or a 0600 file where there is no keychain) and exits 0.
Tell the human, while the command is running:
Open the URL
oh-hai loginprinted (or enter the short code there), approve this device, and pick an existing agent or create a new one for me. I will wait.
If the command times out (exit non-zero after 15 minutes), run it again and ask the human again.
If oh-hai whoami --check already reports an agent id and a reachable Hub, this machine is logged in — skip this step.
3. Teach the project
In the project directory:
sh
oh-hai teach --yesOnce per machine, also:
sh
oh-hai teach --global --yesteach writes a vendor-neutral OH HAI block — the send verbs, how to stay reachable, and, since 0.11.1, what a webhook source is and oh-hai ingest add <label> --to agent:<id> — into the instruction files agents read — always AGENTS.md (created if absent; ~/.codex/AGENTS.md with --global), and, only where they already exist, CLAUDE.md, GEMINI.md, .github/copilot-instructions.md, .cursorrules, .windsurfrules (with --global: ~/.claude/CLAUDE.md, ~/.gemini/GEMINI.md). The block is fenced with <!-- oh-hai:teach start --> … <!-- oh-hai:teach end -->, so re-running replaces it in place and a file that already matches is reported unchanged. It embeds no secret. --yes skips the interactive confirmation; use --dry-run first if you want to show the human the plan.
4. Verify
sh
oh-hai whoami --check && oh-hai doctorwhoami --check is the gate: it probes the Hub with the stored credential and exits 3 if the Hub rejects it (a revoked or wrong token) and 5 if the Hub is unreachable. On exit 3, go back to step 2 and log in again; do not continue. doctor agrees with it: a token the Hub rejects (401/403) is a connectivity failure and doctor exits 3 too. Only an unreachable Hub or a 5xx stays a warning.
doctor checks the config, the stored token, the keychain, and connectivity to the Hub. Go by the exit code, not by every line reading pass. Exit 0 means the setup is usable. On a machine with no OS keychain, step 2 stored the credential in the 0600 fallback file and doctor reports the keychain line as warn (!) while still exiting 0 — that is expected; do not repeat the login for it. Only a fail (✖, non-zero exit) — no token, or the Hub rejecting it with a 401/403 (exit 3) — sends you back to step 2. doctor also prints a scan row listing any stale oh-hai guidance it found on this machine; those findings are advisory and never change the exit code.
5. Send the first notification
sh
oh-hai notify --title "Connected" --body "<agent name> is set up."Replace <agent name> with the name the human gave this agent (or the tool and project you are running in, e.g. "Claude Code in acme-api"). This is a fire-and-forget notify: it lands in the human's inbox immediately and needs no reply. The first line of stdout is the result — SENT <id> <status>, or NOT SENT <code> <reason> with a non-zero exit, or MAYBE SENT … when the failure cannot prove the message was not accepted (do not blindly retry that one: a notify has no idempotency key, so a retry can duplicate). SENT and exit 0 mean the outbound side is done. For text containing backticks or $(…), pass it with --body-file - on stdin so the shell cannot execute it — zsh and bash run those before oh-hai starts, so a send can succeed with the text already gone. If the CLI prints a note that an inline --body carries an unpaired backtick or an unclosed $(, the send went out unchanged; resend with --body-file if the text matters. A title over 200 characters is cut and the full title is prepended to the body, so the stored body is then not the text you sent — pass --strict-title to refuse instead and keep it byte-identical.
6. Stay reachable (optional)
Everything above lets you reach the human. For the human (or a peer agent) to reach you while you run, run the bridge as a background task:
sh
oh-hai bridgeThere is one oh-hai bridge, with no modes and no other flags needed. It opens this run's session for you, prints every message waiting — or waits for the next one, up to about nine minutes — and exits 0. Act on what it printed, then run it again, after every exit. If your harness killed it, just run it again: a background connection kept draining and you get everything you had not read yet, in order. Your sends (notify, ask, task) attach this session automatically, so a peer's reply comes back to you — there is no session start and nothing to export.
Branch on the exit code instead of looping blindly — 0 means run it again; 3 (dead credential), 12 (verification failure) and 14 (a human closed your session) mean stop and tell the human; 13 means the Hub is unreachable, re-run with backoff; 11 means a session you pinned is dead (clear the pin); 10 means two agents appear to share this session (give each a --session <name>); 15 means you stood yourself down. The full table is in Staying reachable.
Which peers may ask/task you is the human's choice, not yours. oh-hai setup normally wrote that sender policy already (every agent in the account, into [bridge] allow_from), and since 0.12.2 oh-hai upgrade can write it on a machine that holds only an agent token. If the bridge says on stderr that no policy is declared, peer asks and tasks are refused while the human's directives still arrive; the fix it names is oh-hai setup or oh-hai upgrade, run by the human. If the bridge instead refuses a named sender, say so plainly: a policy the tool generated earlier is never refreshed, so the human has to edit [bridge] allow_from in ~/.config/oh-hai/config.toml or clear it and re-run. Passing --allow-from by hand is possible, but if you were not told which policy the human wants, ask; never widen it to make a command run.
Once the bridge has a state home to read, every exit also prints one stderr line saying when this run's lease expires on the Hub's clock and whether a connection is alive to renew it — plus a ⚠️ line when nothing is. Do not compute a time remaining from it: that would mean subtracting your clock from theirs. If the warning says the lease has gone longer than its whole TTL without a renewal, your address is dead — run oh-hai bridge again and tell anyone holding the old agent:<id>#sess_… the new one.
If a run exits 10, read the pid it names before doing anything: that is the live holder, and killing it is the wrong move — it is what keeps this address alive.
Check yourself with oh-hai doctor --self-test, and when the run is over stand down with oh-hai session close. Skip this step if your run is short or you cannot hold a background task, and say so in the summary.
Without a shell
Without a shell you cannot install anything, and you cannot add an MCP server to the client you are running in — only the human can change your host's configuration. So the connection is made by the human, in two steps, and then you use it.
Tell the human exactly this:
- Add
https://mcp.ohhai.appas a connector in the client I run in:
- Claude.ai or Claude Desktop: Customize → Connectors → Add custom connector, paste the URL, click Add, then Connect.
- Cursor or VS Code: use the install buttons on https://ohhai.app/docs/mcp/hosted.
- Claude Code:
claude mcp add --transport http oh-hai https://mcp.ohhai.app, then/mcpto sign in.- Anything else: add a remote (Streamable HTTP) MCP server with that URL.
- When your browser opens, sign in to your OH HAI account and approve the connector.
Then tell me it is done and I will send the first notification.
There is no token to paste. The client signs in with OAuth and keeps its own credential.
When the human says it is done, you will have five tools named oh_hai_notify, oh_hai_ask, oh_hai_task, oh_hai_inbox and oh_hai_list. Call the first one:
json
oh_hai_notify { "title": "Connected", "body": "<agent name> is set up." }title is required; body is optional. The result carries { id, status } with status: "delivered". If the tool is not there, or the call returns an authorization error, the connector has not been added or approved yet — ask the human to finish the two steps above.
One limit to state plainly: over MCP nothing can wake you. Mail the human sends you (a directive, an answer) waits until you call oh_hai_inbox, so call it at the start of a turn and whenever you are about to ask something; the human cannot reach you between turns.
What to tell the human
Send back these two lines, filled in:
Connected to your OH HAI inbox as
<agent name>— I sent a "Connected" notification; you should see it now. From here I will use OH HAI to notify you, ask you decisions, and hand you tasks. [Shell, bridge running: "A bridge is listening, so a directive from the inbox reaches me while I run."] [Shell, no bridge: "I am not listening for directives yet; say the word and I will runoh-hai bridge."] [MCP: "I only see your replies and directives when I check the inbox (oh_hai_inbox), so I will check it each turn — I cannot be woken between turns."]
Pick the bracketed line that is true and drop the other two.
Next
- Quickstart — the same setup, written for the human.
- Staying reachable — run
oh-hai bridge, and re-run it after every exit, so a human or a peer agent can reach you while you run (shell only). - Hosted MCP server — every client's configuration and the tool schemas.