# TrucoPilot Tickets — MCP API Documentation

> **Base URL:** `https://jas15.com/api/mcp/v1`
> **Auth:** Bearer token in `Authorization` header (project-scoped, hashed at rest, revocable). Generate in **Settings > MCP Connection** in the TrucoPilot web UI.
> **Protocol:** MCP (Model Context Protocol) Streamable HTTP at `/mcp`. Every tool is also a REST endpoint (see table below).

## Quick Start

```bash
claude mcp add --transport http trucopilot-tickets \
  https://jas15.com/api/mcp/v1/mcp \
  --header "Authorization: Bearer YOUR_TOKEN_HERE"
```

Or add the same server manually under `mcpServers` in `~/.claude.json` (`"type": "http"`, the URL above, and the `Authorization` header). Then tell your AI: "Create a ticket for implementing login", "Move ticket 5 to In Process", "What's the project status?".

## Rules for LLMs / AI Agents

**You MUST follow these rules when connected to a TrucoPilot project:**

1. **First call:** always `get_project_status` — full board state (all boards, columns, tickets), documents, stats. **Use actual column names from the response; never guess them** (`list_columns` also works).
2. **Every feature is an Epic with sub-tickets.** Search for a related Epic first (`list_tickets` / `search`). If found, add a sub-ticket with `create_sub_ticket`; if not, `create_ticket` with `ticket_type: "epic"`, then sub-tickets under it. Never create standalone tickets for feature work.
3. **Epics auto-advance — only move sub-tickets.** All sub-tickets in the done column (`is_done_column: true`) → Epic auto-moves to done. Any sub-ticket in a middle column → Epic auto-moves to in-progress. All in first column → Epic stays put.
4. **Create tickets directly in the right column** via `column_name` (e.g. straight into the active column if you're starting now) — saves a `move_ticket` call.
5. **Comment after every action.** `add_comment` is REQUIRED after any update, move, or completed work — include summary, files changed, functions/classes modified. This is the audit trail.
6. **Complete sub-tickets** by moving them to the done column with a final summary comment. Last open sub-ticket done → Epic auto-completes.
7. **Bug reports: reopen, don't duplicate.** Search for the completed sub-ticket that implemented the feature; `move_ticket` it back to the active column, comment the bug, fix, complete again. Only create a new bug ticket if nothing related exists.
8. **You own the project's Design map.** You know the code; JAS only knows the tickets. Keep the map true to the code: when you add or change a page, service, background job or loop, data store or outside system — or how they connect — update it with `designer_define` in the same task, set each node's `stack`, and put each epic on the node it builds (`tickets`). See *Design map* below.

**Typical new-feature flow:** `get_project_status` → `create_ticket` (epic, in active column) → `create_sub_ticket`(s) → work + `add_comment` → `designer_define` (the parts you touched, with the epic in `tickets`) → `move_ticket` each sub-ticket to done (Epic auto-completes).

## Bootstrapping a Project from Git History

When connecting to an existing codebase for the first time, recreate the work already done so the board has history:

1. `get_project_status` to discover columns.
2. Analyze `git log --oneline --since="6 months ago"`; group commits into logical features (auth, API, UI…). One sub-ticket per meaningful piece, not per commit; skip infra/config noise.
3. For each major feature: `create_ticket` with `ticket_type: "epic"`, a description of what it does and key files, `created_at` = earliest related commit date (ISO 8601, e.g. `"2025-03-15T10:00:00"`), and `column_name` = done column if complete.
4. `create_sub_ticket` for each piece of work under its Epic (same fields; `parent_ticket_id` = the Epic).
5. `add_comment` on completed tickets summarizing what was built, files involved, current state.

Tip: `git log --format="%H %ai %s" --diff-filter=A -- "*.py"` shows when files were first added.

6. **Draw the Design map from the source code** (see *Design map* below): one `designer_define` call describing every
   screen, service, background job, data store and outside system with its stack and connections, the epics from
   step 3 on the nodes they built. Then `designer_render` to look at it and fix what reads wrong.

## MCP Tools (24 total)

Ticket IDs accept the full key, number, or UUID (`"PROJ-5"`, `"5"`). Bold params are required; all others optional.

| Tool | Params | REST | Purpose |
|------|--------|------|---------|
| `get_project_status` | — | `GET /status` | **CALL FIRST, every session/task.** Compact snapshot: project info, stats, all boards/columns (each with `name`, `is_done_column`, `ticket_count`, ticket index), 5 most-recent tickets (metadata only), documents (metadata only, except README content clipped to 3000 chars when Auto-Summary is on), labels. |
| `get_all_tickets` | — | `GET /all-tickets` | Compact index of ALL tickets (key, title, type, column, parent) with truncated AI summaries + documents clipped to 3000 chars. No descriptions/comments — use `get_ticket` for full content. |
| `list_columns` | — | `GET /columns` | All columns with `name`, `is_done_column`, `board_name`, ticket count. Check before creating/moving. |
| `create_ticket` | **title**, description, column_name, priority, ticket_type, created_at | `POST /tickets` | New ticket. `ticket_type`: `task` (default), `bug`, `story`, `epic`. |
| `create_sub_ticket` | **parent_ticket_id**, **title**, description, priority, column_name, created_at | `POST /tickets/{id}/sub-ticket` | Sub-ticket under a parent; parent auto-promotes to Epic. Priority defaults to parent's. |
| `convert_to_sub_ticket` | **ticket_id**, **epic_id** | `POST /tickets/{id}/convert-to-sub-ticket` | Re-parent a standalone ticket under an epic (epic auto-promoted). |
| `get_ticket` | **ticket_id** | `GET /tickets/{id}` | Full details incl. comments, activity, AI summary. |
| `list_tickets` | column_name, status, priority, search, limit | `GET /tickets` | Filter tickets. `status`: `open`/`completed`; `search` matches title+description. |
| `update_ticket` | **ticket_id**, title, description, priority, ticket_type, created_at | `PUT /tickets/{id}` | Update properties. **MUST `add_comment` after.** |
| `move_ticket` | **ticket_id**, **column_name** | `POST /tickets/{id}/move` | Move between columns (done = column with `is_done_column: true`). **MUST `add_comment` after.** |
| `add_comment` | **ticket_id**, **content** | `POST /tickets/{id}/comment` | Markdown comment. Required audit trail: summary, files changed, functions/classes, notes. |
| `delete_ticket` | **ticket_id** | `DELETE /tickets/{id}` | Delete permanently. |
| `search` | **query**, scope | `GET /search?q=` | Search tickets + documents. `scope`: `all` (default), `tickets`, `documents`. |
| `list_documents` | doc_type | `GET /documents` | List wiki/docs pages. `doc_type`: `readme`, `claude_md`, `wiki`, `changelog`, `custom`. |
| `get_document` | **doc_id** | `GET /documents/{slug}` | Get a document by slug or ID (e.g. `"readme"`). |
| `create_document` | **title**, content, slug, doc_type | `POST /documents` | New wiki page. |
| `update_document` | **doc_id**, title, content | `PUT /documents/{slug}` | Update a document. |
| `list_labels` | — | `GET /labels` | All project labels. |
| `list_members` | — | `GET /members` | Org members for assignment. |

Common fields: `priority` ∈ `lowest`/`low`/`medium` (default)/`high`/`highest`; `column_name` is case-insensitive and defaults to the first column; `created_at` is an ISO 8601 datetime for backdating historical imports (defaults to now). Descriptions and comments are markdown.

**MCP call example** (same shape for every tool):

```json
{ "name": "create_ticket", "arguments": { "title": "Implement OAuth login", "ticket_type": "epic", "column_name": "In Process", "created_at": "2025-06-15T10:30:00" } }
```

Also available: `GET /health` (health check), `DELETE /documents/{slug}`.

## Design map — drawn by you, from the code

Every project has a **Design**: one map a project manager or a boss reads **left to right** — what people use on the
left, the backend in the middle with its jobs & loops under it, then data, then outside systems — and **top to
bottom** for more of it. Every card shows what it is built with (its **stack**) and how far its tickets are
(**done/total**). You draw it, because you know how the code works; JAS only keeps the ticket progress current and
places new tickets on the cards you made.

| Kind | Lane | What it is | Code |
|------|------|-----------|------|
| `page` | Interface | A screen or page people use (a route, a view, a CLI command people run) | `P-n` |
| `service` | Backend | An API, server or module that answers requests | `S-n` |
| `worker` | Backend, under the services | A background job, loop, scheduler, cron or queue consumer | `W-n` |
| `datastore` | Data | A database, table group, cache, queue or file store | `D-n` |
| `external` | Outside | A third-party system (payments, email, auth, AI provider) | `X-n` |
| `area` | — | A band grouping one part of the product (e.g. "Checkout", "Admin") | `A-n` |
| `note` | — | A sticky note | `N-n` |

**Sections** are a card's parts — a page's features, a service's endpoints, a store's tables. **Connections** are
`navigates` (page → page), `calls` (→ service / worker / outside), `data` (reads or writes a data store) and `depends`.

### Build or refresh it: `designer_define`

Describe the system; the server matches what exists (by code, else by title), creates what is new, adds sections by
title, makes connections and ticket links once, and lays the map out in lanes. Calling it again with the same
description changes nothing, so send the whole picture — or only the part you touched.

```json
{ "name": "designer_define", "arguments": {
  "areas": ["Storefront", "Back office"],
  "nodes": [
    {"kind": "page", "title": "Checkout", "area": "Storefront", "route": "/checkout",
     "stack": ["Next.js", "TypeScript", "Stripe.js"], "sections": ["Shipping", "Payment", "Review"], "tickets": ["SHOP-12"]},
    {"kind": "service", "title": "Orders API", "stack": ["FastAPI", "Python"], "sections": ["POST /orders", "POST /refunds"]},
    {"kind": "worker", "title": "Receipt mailer", "stack": ["Celery", "Redis"], "intro": "Emails a receipt after each order"},
    {"kind": "datastore", "title": "MariaDB", "stack": ["MariaDB 11"], "sections": ["orders", "users"]},
    {"kind": "external", "title": "Stripe", "stack": ["REST"]}
  ],
  "connections": [
    {"from": "Checkout > Payment", "to": "Orders API", "label": "Place order"},
    {"from": "Orders API", "to": "MariaDB"},
    {"from": "Orders API", "to": "Stripe", "label": "Charge"},
    {"from": "Orders API", "to": "Receipt mailer", "kind": "depends", "label": "Queue"},
    {"from": "Receipt mailer", "to": "MariaDB"}
  ] } }
```

- `stack`: languages, frameworks and key libraries — short words (`"Next.js"`, `"Go"`, `"PostgreSQL 16"`), at most 8.
- Connection ends: a title, a code (`P-3`), or a section as `"Title > Section"` or `P-3.2`. `kind` is inferred when
  you leave it out.
- `layout: "keep"` places only new cards and leaves people's arrangement alone; `remove_missing: true` also removes
  cards an agent made earlier that the description no longer lists.
- People's edits are theirs; every change is undoable in the Design's Activity.

**When to update it:** after you add or change a screen, endpoint, job, table or integration, and when a ticket's epic
belongs to a card that doesn't have it yet. Check the picture with `designer_render` (`scope=A-2` or `scope=P-5` to zoom).

## Design tools (5)

The Design is addressed by short codes: page `P-3`, service `S-1`, job `W-2`, data store `D-1`, outside system `X-1`,
section `P-3.2`, connection `E-7`, area `A-1`, ticket `KEY-12`.

| Tool | Use it to |
|------|-----------|
| `designer_get` | Read the design. Default: a compact outline (one line per card with its stack and done/total). `view=node code=P-3` for one card in Markdown (`format=json` for short-key JSON); `view=search q=…`; `view=changes since_version=N`; `view=history` for runs; `view=help` for the full op grammar. Pass `since_version` to get `unchanged v=N` when nothing moved. |
| `designer_render` | A PNG of the map as people see it — `scope=all` (default), an area (`A-2`) or a card with its neighbours (`P-5`). `target=ui_preview scope=P-5` shows a page's generated UI. |
| `designer_define` | Build or refresh the map from a description of the system (above) — the main tool for coding agents. |
| `designer_apply` | Fine-grained ops (atomic; undoable as one run): `add_node`, `update_node {node, stack, kind, …}`, `connect`, `link_ticket`, `auto_layout`… Example: `[{"op":"add_node","ref":"$r","kind":"page","title":"Reset password","stack":["Next.js"],"sections":[{"ref":"f","title":"New password form"}]},{"op":"connect","from":"P-1.2","to":"$r","kind":"navigates","label":"Email link"},{"op":"link_ticket","ticket":"WEB-57","target":"$r.f"}]`. Send `base_version` to fail on conflicts instead of overwriting. |
| `designer_generate` | Ask JAS's design AI (for projects without a coding agent): `refresh`, `rebuild` (needs `confirm=true`), `bootstrap`, `ui node=P-3` (a UI preview), `place ticket=KEY-12`. Optional `wait` (≤60 s). |

Ticket tools also take an optional `designer` target (`"designer": "P-3.2"`) to place a ticket on a card as you create it.

**Token-saving tips:** start with `designer_get` (a few hundred tokens), zoom with `designer_render scope=…` at
`width≤1280` (~1.5k tokens), fetch one card with `view=node`, and poll with `since_version`. The REST mirror lives at
`/api/mcp/v1/designer` (`GET` text, `GET /render.png|svg`, `POST /define`, `POST /apply`, `POST /generate`) with the
same Bearer token.
