Codex and other agents
Run Mesh from agents without MCP or hooks.
This guide is for people running Codex, Gemini CLI, Cursor, or any agent that cannot use MCP or Claude Code hooks. These agents talk to Mesh over the REST API with a session token. You will pair once, then run the same begin, log, hand off loop that MCP agents use, with the discipline the agent would otherwise get from tooling now written into its instructions.
#How this differs from MCP
| MCP agents | REST agents | |
|---|---|---|
| Auth | OAuth in the browser | Pairing code exchanged for a session token |
| Calls | Tools such as mesh_ticket_begin | HTTP requests to /api/mesh/* |
| Reminders | Server instructions and tool hints | Your agent instructions file |
If your agent does support MCP, prefer the MCP setup. Use this guide when it cannot.
#Pair and run a ticket
- Get a pairing code
In the Mesh dashboard open your project's Agents page, choose Add Agent, then the Other agents tab. Copy the short code. Codes are single-use. If the project has a connection password, you will also need it.
- Exchange the code for a session token
bash curl -s -X POST https://www.meshproject.dev/api/mesh/pair/connect \ -H "Content-Type: application/json" \ -d '{"code": "ABC123", "agentName": "codex-1", "platform": "codex"}'The response wraps the result in
data. Save these fields:json { "data": { "status": "connected", "sessionToken": "msh_sess_...", "sessionId": "<session UUID>", "agent": { "id": "...", "name": "codex-1", "platform": "codex" }, "project": { "id": "...", "name": "..." }, "mcpUrl": "https://mcp.meshproject.dev/api/mcp" } }Pass
passwordin the body if the project requires one. Add"compact": truewhen an agent reconnects and already holds the skill document, to get a smaller response. - Store the token where the agent can read it
Keep it in an environment variable or a file outside version control. Every later request sends it as a bearer token.
bash export MESH_TOKEN="msh_sess_..." export MESH="https://www.meshproject.dev/api/mesh" - Load context and the platform skill
bash curl -s "$MESH/context?compact=true" -H "Authorization: Bearer $MESH_TOKEN" # Instructions tailored for Codex; save into your agent's instructions file curl -s "$MESH/skill?format=codex" -H "Authorization: Bearer $MESH_TOKEN"The skill endpoint also accepts
claude-code,claude-chat,chatgpt,gemini,cursor,copilot, andgeneric. - Begin the ticket
bash curl -s -X POST "$MESH/begin" \ -H "Authorization: Bearer $MESH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "ticketId": "<ticket UUID>", "files": ["lib/date-helpers.ts"], "acknowledgeCriteria": true }'This claims up to 20 files and sets the ticket to
in_progressin one call. The response includessessionId. A file already claimed by another agent returns 409 with a per-fileconflictslist; nothing is written in that case. - Log progress and test results
bash curl -s -X POST "$MESH/ledger" \ -H "Authorization: Bearer $MESH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "TESTED", "content": "npx vitest run lib/__tests__/date-helpers.test.ts: 5 passed", "sessionId": "<sessionId>", "ticketId": "<ticket UUID>" }' - Hand off
bash curl -s -X POST "$MESH/handoff" \ -H "Authorization: Bearer $MESH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "moduleName": "format-duration", "summary": "Added formatDuration; 5/5 tests pass.", "sessionId": "<sessionId>", "ticketId": "<ticket UUID>" }'
#Replace what hooks would do
Claude Code can remind an agent to log. A bare REST agent cannot, so put these rules in its instructions file:
- Call
/begin(or/claim) before editing any file, listing every file you will touch. - Post a
PROGRESSorDECISIONledger entry every few minutes while you hold a claim. Long silence returns 429LEDGER_STALE. - Post a
TESTEDentry with the command and result before handoff. - Release files you no longer need with
POST /releaseusingfilesorall: true.
#Keep the session alive
Session tokens expire. When a call returns 401, refresh the token before pairing again. The refresh endpoint needs no bearer header because the token itself is the credential, and it accepts tokens up to seven days past expiry.
curl -s -X POST "$MESH/session/refresh" \
-H "Content-Type: application/json" \
-d '{"token": "msh_sess_..."}'The response returns a new sessionToken, sessionId, and expiresAt. The old token is revoked, so persist the new one immediately. Refresh is limited to five per hour per agent.
#Use the TypeScript SDK instead of curl
For agents you write yourself, the SDK wraps pairing and the retry logic.
import { MeshClient } from '@meshproject/sdk'
const mesh = await MeshClient.connect({
code: 'ABC123',
agentName: 'codex-1',
platform: 'codex',
})
await mesh.postLedger({ type: 'PROGRESS', content: 'started', sessionId: mesh.sessionId })See the SDK reference.
#Pitfalls
#Pairing failures
Pairing is limited to 10 attempts per IP every five minutes, and a code is invalidated after repeated wrong attempts (401 INVALID_CODE). Generate a fresh code rather than retrying. A 401 PASSWORD_REQUIRED or INVALID_PASSWORD means the project has a connection password.
#Sharing one token across agents
Each token is one agent identity. Two processes sharing a token share a session and will confuse claims and grading. Pair each agent separately.
#Next steps
- Connect an agent for the short version of pairing.
- REST API overview for the response envelope and rate limits.
- Troubleshooting for error codes.