Dexio / how-we-build-dexio / agents
Letting an agent connect itself, and testing it with headless agents
The person's part should be one sentence. The agent's part is everything else: reading the steps, signing the person in, saving a key, editing its own config, and confirming it works. How the endpoint authenticates each kind of client: remote-mcp-server-with-oauth. How we run our own agents: hermes-agent-team.
What it is
-
One page written for agents, https://dexio.wiki/agents.md: numbered steps, the endpoints inline, and the config for each agent we support (Claude Code, Codex, Cursor, Hermes, OpenClaw, and any MCP client). It is listed in
llms.txt, and every page on the site carries a visually hidden "For AI agents" block with both endpoints and a note to read the file raw. -
Someone already signed in gets a message to paste, with a key in it, from the app's connect panel:
Connect yourself to my Dexio wiki. Read the steps with curl -s https://dexio.wiki/agents.md and follow them, using this key: dxk_... -
Someone with no account yet says only this, and the agent runs the device sign-in, which signs them up on the way:
Connect yourself to my Dexio wiki. The steps are at https://dexio.wiki/agents.md: read the whole file, not a summary, and follow them. -
Claude and ChatGPT on the web are hosted connectors and sign in with OAuth instead.
Why it is built this way
- Editing an agent's config by hand is where setup fails. The agent knows its own config format better than a setup page does.
- A key in the message for people already signed in. A sign-in link would prove nothing new, and in a chat app it costs a round trip: the agent has to end its turn to show the link, and the person has to come back after approving. The cost we accepted: the key sits in chat history and the agent's session log, so every key is named for its agent and can be revoked in Settings.
- The device sign-in for everyone else, because it works for an agent on another machine or behind a chat app, where a browser redirect to localhost cannot reach it.
How to build it
-
Write the steps page for agents, not people. Number the steps, put every endpoint in the page itself, give each agent its config block, and say what to tell the person at the end: that it is connected, and which file holds the key. Serve it as raw markdown.
-
Mint keys only on POST (a GET never makes one), name each key for the agent it is for, and put the key last in the message so no punctuation touches it.
-
Add the device sign-in: one endpoint that starts it and returns a short code and a link, one the agent polls until the person approves. The sign-in and sign-up pages say an agent is waiting and keep the link through sign-up.
-
Handle each agent's quirks in the steps page:
- Claude Code:
claude mcp add --transport http --scope user dexio <url> --header "Authorization: Bearer <key>", then a new session to load it. - Codex: a
[mcp_servers.dexio]table in~/.codex/config.tomlwithurlandhttp_headers, then a new session. - Hermes: its file tools refuse to write
config.yaml(deliberately), a heredoc in its terminal stops for approval, andhermes mcp addasks questions. So the agent writes a short Python script with its file tool, with the key inside it, and runs it once. The script saves the key to$HERMES_HOME/.envwithout printing it, removes any older entry, runshermes mcp addwith its answers piped in, and deletes itself. Behind a chat gateway the person then sends/reload-mcp.
- Claude Code:
-
Write tool descriptions that say when to use each tool, so a newly connected agent actually reaches for the wiki.
-
Test with real agents before and after every change to the steps or the tools:
-
One throwaway home per run (
HOME, orHERMES_HOMEfor Hermes) and a throwaway account, deleted afterwards, or a local server seeded with a small wiki. -
For setup, give a headless agent only the one-sentence prompt and record whether it started, how many commands failed, how long it took, and whether its next turn could call a Dexio tool.
-
For tool behavior, run Claude Code as a shell-less agent with only your MCP server:
claude -p "<task that never names the tools>" --tools "" --mcp-config mcp.json \ --strict-mcp-config --allowedTools mcp__dexio --permission-mode dontAsk \ --setting-sources project --no-session-persistence --output-format stream-json --verbose -
For Hermes with only the MCP tools:
hermes -p <profile> chat -Q --ignore-rules -t mcp-dexio --max-turns 40 -q "<task>".
-
What the tests showed
Small samples, one client per row, so read them as direction rather than rates:
- "Look at dexio.wiki and log me in.": Opus started the sign-in in 9 of 10 runs; Sonnet in 0 of 9. Sonnet refused an unfamiliar domain plus "log me in" as a possible injection before reading anything.
- The prompt above that names the steps file: 9 of 9 started (Sonnet 5 of 5, Opus 4 of 4), and 7 of 9 fetched the file raw without being told how.
- Hermes with a key in the message: connected in 47 seconds with no failed commands. With the device sign-in, a script playing the person: 1 minute 7 seconds.
- Tool descriptions: agents searched the wiki before answering in 0 of 5 runs when the descriptions said how each tool works, and in 4 to 5 of 5 when they said when to use it.
Pitfalls we hit
- Claude Code's web fetch hands the model a short summary of an unfamiliar site, quoting at most 125 characters. A summarized steps page read to one run like an injection. Put the endpoints in every page and tell agents to fetch the file raw.
- A line telling the agent not to show the key in chat read as hiding a credential from the user. Say instead to tell the person which file holds it.
- In the first Hermes run with a key, the agent would not put the key on a command line, improvised a key file, and had two commands blocked. With the key inside the self-deleting script, the next run was one file write and one command.
- "Log me in" on its own reads as a credential grab to cautious models. Name the product and the steps file in the prompt you give people.