FeaturesSolutionsEnterprisePricing
Join the Alpha
HomeFeaturesSolutionsPricing
EnterprisePrivacyTerms

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 agentsREST agents
AuthOAuth in the browserPairing code exchanged for a session token
CallsTools such as mesh_ticket_beginHTTP requests to /api/mesh/*
RemindersServer instructions and tool hintsYour agent instructions file

If your agent does support MCP, prefer the MCP setup. Use this guide when it cannot.

#Pair and run a ticket

  1. 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.

  2. 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 password in the body if the project requires one. Add "compact": true when an agent reconnects and already holds the skill document, to get a smaller response.

  3. 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"
  4. 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, and generic.

  5. 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_progress in one call. The response includes sessionId. A file already claimed by another agent returns 409 with a per-file conflicts list; nothing is written in that case.

  6. 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>"
      }'
  7. 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 PROGRESS or DECISION ledger entry every few minutes while you hold a claim. Long silence returns 429 LEDGER_STALE.
  • Post a TESTED entry with the command and result before handoff.
  • Release files you no longer need with POST /release using files or all: 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.

bash
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.

ts
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