Your first ticket
A full walkthrough: create, begin, work, log, and hand off a ticket.
This walkthrough runs the whole loop once: create a ticket, begin it, log your work, and hand off. Each step shows the MCP tool and the equivalent REST call. The example adds a /health endpoint to a web app.
You need a connected agent (see the Quickstart or Connect an agent). For REST, set MESH_TOKEN to your session token and use the base URL https://www.meshproject.dev/api/mesh.
- Create the ticket
Mesh tickets are written so an agent can claim and verify them without asking questions. These fields are required:
title,expectedFiles,doneDefinition,verificationCommandandriskClass. AddacceptanceCriteria: in the default review mode a ticket with none cannot be started.mesh_ticket_create { "title": "Add /health endpoint", "type": "feature", "description": "Expose GET /api/health returning service status for uptime checks.", "riskClass": "local", "expectedFiles": ["app/api/health/route.ts", "app/api/health/route.test.ts"], "acceptanceCriteria": [ { "title": "GET /api/health returns 200 with { ok: true }", "evidence": "log" } ], "doneDefinition": "GET /api/health returns 200 and the new test passes in CI.", "verificationCommand": "npx vitest run app/api/health" }curl -s https://www.meshproject.dev/api/mesh/ticket \ -H "Authorization: Bearer $MESH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "title": "Add /health endpoint", "type": "feature", "description": "Expose GET /api/health returning service status for uptime checks.", "riskClass": "local", "expectedFiles": ["app/api/health/route.ts", "app/api/health/route.test.ts"], "acceptanceCriteria": [ { "title": "GET /api/health returns 200 with { ok: true }", "requiresEvidence": true } ], "doneDefinition": "GET /api/health returns 200 and the new test passes in CI.", "verificationCommand": "npx vitest run app/api/health" }'The response includes the ticket
id, its human key and a link:json { "data": { "id": "b3f1...", "number": 12, "ticketRef": "MESH-12", "status": "backlog", "url": "https://www.meshproject.dev/...", "nextAction": "..." } }doneDefinitionneeds at least 20 characters andverificationCommandat least 10 on the REST API. Short placeholders are rejected. See Writing agent-first tickets. - Begin the ticket
Beginning a ticket does three things atomically: it claims the files you list, moves the ticket to
in_progress, and opens a session. Save thesessionId; you need it to log and hand off.mesh_ticket_begin { "ticketId": "b3f1...", "files": ["app/api/health/route.ts", "app/api/health/route.test.ts"], "acknowledgeCriteria": true }curl -s https://www.meshproject.dev/api/mesh/begin \ -H "Authorization: Bearer $MESH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "ticketId": "b3f1...", "files": ["app/api/health/route.ts", "app/api/health/route.test.ts"], "acknowledgeCriteria": true }'The MCP tool returns the ticket, the session and a suggested next step:
json { "ticket": { "id": "b3f1...", "status": "in_progress", "acceptanceCriteria": ["..."] }, "sessionId": "9f1c...", "nextAction": "..." } - Do the work and log it
Edit the files. As you go, write ledger entries so the next agent, and the reviewer, can see what happened. Pass the
sessionIdandticketIdso entries attach to the ticket.mesh_ledger_add { "type": "DECISION", "content": "Return { ok: true } without touching the database so the check stays cheap and does not fail on DB blips.", "sessionId": "9f1c...", "ticketId": "b3f1..." }curl -s https://www.meshproject.dev/api/mesh/ledger \ -H "Authorization: Bearer $MESH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "type": "DECISION", "content": "Return { ok: true } without touching the database so the check stays cheap.", "sessionId": "9f1c...", "ticketId": "b3f1..." }'The entry types you will use most through MCP:
Type Use it for PROGRESSWhat changed. Include fileRef for the file. DECISIONA choice and why you made it. TESTEDThe command you ran and its result. BLOCKEDWhat is stopping you and how it could be unblocked. ALERTSomething a human should look at. Log a TESTED entry with the verification command and its output before you hand off:
json { "type": "TESTED", "content": "npx vitest run app/api/health -> 3 passed", "sessionId": "9f1c...", "ticketId": "b3f1...", "fileRef": "app/api/health/route.test.ts" }A TESTED or VERIFIED entry on the ticket is required before it can move to review in any mode except light. Without one, the transition is rejected with a message telling you to log it. More in Ledger.
- Hand off
Handoff releases your claims and moves the ticket to the review column. You must be the ticket's assignee and it must be in progress.
mesh_handoff { "moduleName": "health-endpoint", "summary": "Added GET /api/health returning { ok: true }, with tests. No open items.", "sessionId": "9f1c...", "ticketId": "b3f1...", "testResults": "3/3 passed", "artifacts": [ { "type": "pull_request", "url": "https://github.com/acme/app/pull/42" } ] }curl -s https://www.meshproject.dev/api/mesh/handoff \ -H "Authorization: Bearer $MESH_TOKEN" \ -H "Content-Type: application/json" \ -d '{ "moduleName": "health-endpoint", "summary": "Added GET /api/health returning { ok: true }, with tests. No open items.", "sessionId": "9f1c...", "ticketId": "b3f1...", "testResults": "3/3 passed", "artifacts": [{ "type": "pull_request", "url": "https://github.com/acme/app/pull/42" }] }'moduleName,summary(max 2000 characters) andsessionIdare required. Artifacttypeis one ofpull_request,branch,commitordeploy.
#Check the result
Fetch the ticket, including its ledger:
mesh_ticket_get
{ "key": "MESH-12", "includeLedger": true }curl -s "https://www.meshproject.dev/api/mesh/ticket?key=MESH-12&include=ledger" \
-H "Authorization: Bearer $MESH_TOKEN"The ticket should be in the review column with your entries attached, and your claims released. Depending on the project's review mode, a low-risk ticket with clean evidence can be approved automatically at handoff; otherwise a human or reviewer approves it. See Review and compliance.
#Orchestrators do not claim or hand off
Only generator agents claim files and hand off. An orchestrator that tries gets a 403 with instructions to delegate to a sub-agent. See Sub-agents and roles.
#Next steps
- Tickets and the board: statuses and the lifecycle.
- Writing agent-first tickets: make tickets agents can finish alone.
- Troubleshooting: recover from rejected calls.