# Changelog URL: /docs/changelog Changelog [#changelog] v2.13.1 — 2026-06-27 [#v2131--2026-06-27] Fixed [#fixed] * **CRITICAL — `list_memories` + `list_episodes` silently returning `items: []` on every call** — Day-114 audit (`projects/vantage-peers/mcp-pagination-audit-day114.md`) found both handlers reading `memories?.page` from the Convex `listMemories` return shape `{value, continueCursor, isDone}`. `.page` is undefined → empty results on every invocation regardless of stored data. Fixed in PR [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) (squash `0db28d5`). Pre-2.13.1 callers MUST upgrade. See [Day-114 release notes](/docs/release-notes/day-114). Added [#added] * **MCP Tools Standard doctrine v1** — cross-fleet `list_*` pagination doctrine canonicalized as a versioned standard. PR [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) (squash `d09fc5b`). VantageRegistry runbook `kd750j7z7tqre6hxqmfsa8s9ed89erng`. Covers: mandatory Zod schema, return envelope, 7 banned anti-patterns, coverage matrix template, fleet compliance table, migration playbook. * **Day-114 documentation** — [Cursor Pagination](/docs/pagination), [Envelope Safety](/docs/envelope-safety), [Tools Catalogue](/docs/tools-catalogue), [Day-114 release notes](/docs/release-notes/day-114). Links [#links] * GitHub: [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers) * npm: [vantage-peers-mcp@2.13.1](https://www.npmjs.com/package/vantage-peers-mcp) * PR #978: [github.com/vantageos-agency/vantage-peers/pull/978](https://github.com/vantageos-agency/vantage-peers/pull/978) * PR #980: [github.com/vantageos-agency/vantage-peers/pull/980](https://github.com/vantageos-agency/vantage-peers/pull/980) *** v2.12.0 — 2026-06-06 (current) [#v2120--2026-06-06-current] Security [#security] * **D6 + D7 OAuth 2.1 hardening** — confidential `client_secret` at `/token` (constant-time compare) and `redirect_uri` exact-match at `/authorize`. PR [#621](https://github.com/vantageos-agency/vantage-peers/pull/621). * **`patchScopeProfileEmergency`** — master-token-gated mutation for tenant rename/scope-profile rewrite with D4 enforcement, D9 cascade, and append-only audit ledger. PRs [#622](https://github.com/vantageos-agency/vantage-peers/pull/622), [#623](https://github.com/vantageos-agency/vantage-peers/pull/623). * **S3.1 scope-aware filter framework** — row-level OAuth scope enforcement on `list_memories`, `get_memory`, `list_briefing_notes`, `list_messages`, `list_peers`. PRs [#624](https://github.com/vantageos-agency/vantage-peers/pull/624), [#625](https://github.com/vantageos-agency/vantage-peers/pull/625). * **S2.3 D8** — `masterOnlyMiddleware` migrated to `@vantageos/cloud-identity@0.1.0` shared brick (constant-time sha256 comparison). 254/254 tests PASS. Added [#added-1] * **Tool count reaches 114** — 17 net new tools since v2.5.0: episodes API (`get_episode`, `list_episodes`, `search_episodes_by_keyword`, `search_episodes_by_semantic`), single-entity getters (`get_task`, `get_message`, `get_fix_pattern`, `get_mandate`, `get_recurring_task`, `get_repo_mapping`, `get_briefing_note`), search tools (`search_tasks_by_keyword`, `search_messages_by_keyword`, `search_briefing_notes_by_keyword`), `instantiate_template_into_mission`, `whoami`, `validate_task_payload`, plus canonical aliases. * **Cursor paging** — all 19 `list_*` and `search_*` tools now support opaque `cursor` + `nextCursor` for draining past the 200-row cap. 3 documented exceptions (`list_broadcast_status`, `search_components`, `search_fix_patterns`). * **Day 98 F4** — webhook `issue_comment` events routed Bridge-only, preventing double-processing. PR [#796](https://github.com/vantageos-agency/vantage-peers/pull/796). Links [#links-1] * GitHub: [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers) * npm: [vantage-peers-mcp@2.12.0](https://www.npmjs.com/package/vantage-peers-mcp) *** v2.5.0 — 2026-06-06 [#v250--2026-06-06] Added [#added-2] * **Day 92 quality overhaul** (C0–C4, A1–A4, B1–B3, F1–F2) — 14 P0 zero-auth write tools closed with master-only gates; 87 Zod `outputSchema` exports; Unicode NFC normalization at all write paths; 97 tool descriptions standardized (1-line + WHEN + EXAMPLE); `whoami` identity tool (PR [#661](https://github.com/vantageos-agency/vantage-peers/pull/661)); `validate_task_payload` MCP validator tool; tools-quality-standard doc. * **S3.3 B8 cursor paging** — `list_tasks`, `list_memories`, `list_briefing_notes` + 12 more list tools gain opaque `cursor` + `nextCursor`. Shared `src/paging.ts` utility. 302/302 tests PASS. * **D90 kill-switch hardening** — `AUTO_IRP_PAUSED` guard applied at all 3 auto-IRP pipeline entries; `errorMonitorKillSwitch.ts` with `isKillSwitchActive()` + startup health check. Links [#links-2] * npm: [vantage-peers-mcp@2.5.0](https://www.npmjs.com/package/vantage-peers-mcp) *** v2.4.1 — 2026-05-30 [#v241--2026-05-30] Fixed [#fixed-1] * **DCR auth path 401 regression** ([#556](https://github.com/vantageos-agency/vantage-peers/issues/556) / [#557](https://github.com/vantageos-agency/vantage-peers/pull/557)) — `oauthDcr:validateAccessToken` was declared `internalQuery` and unreachable via the HTTP client, so Path 3 DCR returned 401 even with a valid token. Now exposed as a public `query`. Claude.ai Custom Connectors via DCR works end-to-end. * **`WWW-Authenticate` header format** ([#557](https://github.com/vantageos-agency/vantage-peers/pull/557)) — emits `Bearer resource_metadata="..."` per MCP spec §Protected Resource Metadata Discovery. The prior `Bearer resource="..."` broke Claude.ai PRM bootstrap on 401. Added [#added-3] * **ChatGPT Apps SDK tool annotations** ([#555](https://github.com/vantageos-agency/vantage-peers/pull/555)) — all MCP tools now ship with `readOnlyHint`, `openWorldHint`, and `destructiveHint`. ChatGPT custom connectors render confirmation prompts only on writes/destructive ops. * **DCR scope isolation** ([#554](https://github.com/vantageos-agency/vantage-peers/pull/554)) — new `public-readonly` profile + cross-tenant assertion tests. The DCR auto-discovery flow now resolves to `scopeProfile=client-generic` (never `master`), even if a legacy token row carries `scope="mcp:full"`. * **VantagePeers Cloud documentation** ([site #120](https://github.com/vantageos-agency/vantage-peers-site/pull/120)) — dedicated `/docs/cloud/` section for the hosted, multi-tenant version. Multi-client MCP: Claude.ai, ChatGPT, Claude Code, Codex, any MCP-supporting IDE. Links [#links-3] * GitHub release: [v2.4.1](https://github.com/vantageos-agency/vantage-peers/releases/tag/v2.4.1) * npm: [vantage-peers-mcp@2.4.1](https://www.npmjs.com/package/vantage-peers-mcp) v2.4.0 — 2026-05-29 [#v240--2026-05-29] Added [#added-4] * **`iframeEmbedSessions` table + `__VP_TOOL_RESULT__` stream marker** ([#545](https://github.com/vantageos-agency/vantage-peers/pull/545)) — M3 milestone. Embedded ack-checklist UI primitive. 24 tests. * **`credentials:issueBearerFromClerk` httpAction** ([#546](https://github.com/vantageos-agency/vantage-peers/pull/546)) — server-side bearer issuance bound to a Clerk identity, with audit log. Iter 2 P1 fixes. Links [#links-4] * GitHub release: [v2.4.0](https://github.com/vantageos-agency/vantage-peers/releases/tag/v2.4.0) * npm: [vantage-peers-mcp@2.4.0](https://www.npmjs.com/package/vantage-peers-mcp) v2.3.1 — 2026-05-26 [#v231--2026-05-26] Added [#added-5] * `list_tasks`, `list_missions`, `list_tasks_by_mission`, and `list_briefing_notes` accept a `fields` parameter (`"lite"` or `"full"`, default `"full"`). Lite returns a compact projection. * `status` filter on `list_tasks`, `list_missions`, and `list_tasks_by_mission` now accepts arrays and named aliases: * Tasks: `"open"` → todo+in\_progress+review+blocked, `"active"` → todo+in\_progress, `"all"` → no filter * Missions: `"open"` → brainstorm+plan+execute+validate (excludes complete), `"active"` → plan+execute, `"all"` → no filter Backward compatibility [#backward-compatibility] * Single-string `status` is unchanged. * Omitting `fields` defaults to `"full"` — existing callers are unaffected. Deprecation [#deprecation] * **`vantage-peers-mcp@2.3.0` is deprecated.** v2.3.0 shipped with two blockers caught in delta-review: `status="all"` was advertised but rejected by the backend, and `setPendingAliasReleases` was exposed as a public mutation. Upgrade to `>=2.3.1`. Links [#links-5] * GitHub release: [v2.3.1](https://github.com/vantageos-agency/vantage-peers/releases/tag/v2.3.1) * npm: [vantage-peers-mcp@2.3.1](https://www.npmjs.com/package/vantage-peers-mcp) --- # Envelope Safety URL: /docs/envelope-safety Envelope Safety [#envelope-safety] The VantagePeers MCP server enforces a consistent set of protections on every `list_*` response to prevent response payloads from overflowing the in-context budget of the calling agent. This page documents the protections, the `fields=lite|full` projection system, the 200-row hard cap, and the anti-patterns that caused production incidents. The three protections [#the-three-protections] Every `list_*` tool in VantagePeers enforces three layers of protection: 1. **Hard row cap (200):** The `limit` argument is validated as `z.number().int().min(1).max(200).optional()`. Any value above 200 is rejected at the MCP layer before reaching Convex. The default when no `limit` is given is 20 rows. 2. **`fields=lite` projection:** All `list_*` tools accept `fields: "lite" | "full"`. The `lite` projection returns at most 6 fields per row, keeping page sizes small even for documents with large text content (e.g. memories with long `content`, briefing notes with long `decisions` arrays). 3. **50 KB soft cap (`enforceEnvelopeCap`):** After row projection, the server measures the serialized JSON size of the envelope. If the result exceeds 50 000 bytes, the server halves the row count and re-measures, repeating until the payload fits. This guard exists in addition to the row cap — it protects against full-schema rows with large embedded text. `fields=lite` vs `fields=full` [#fieldslite-vs-fieldsfull] | Value | Fields returned | Typical size per row | | -------- | -------------------------------------------------- | -------------------- | | `"lite"` | `_id`, `_creationTime`, plus 2 to 4 display fields | \~200–400 bytes | | `"full"` | All schema fields including full text content | \~2 000–20 000 bytes | Default is `"full"`. For any loop that processes more than one page, always pass `fields: "lite"`. Example lite projection for `list_tasks`: ```json { "_id": "k17abc...", "_creationTime": 1751020800000, "title": "Fix list_memories pagination", "status": "done", "assignedTo": "sigma", "priority": "urgent" } ``` The same task in `full` mode includes `description` (potentially hundreds of characters), `completionNote`, `blockers`, `dependsOn`, `missionId`, `orgId`, `createdBy`, `updatedAt`, and all other schema fields. Limit clamp behaviour [#limit-clamp-behaviour] The `clampLimit` function in `mcp-server/src/paging.ts` applies these rules in order: 1. If `limit` is undefined, return `DEFAULT_LIMIT` (20 for most tools). 2. If `limit < 1`, return 1. 3. If `limit > MAX_LIMIT` (200), return 200. 4. Otherwise return `limit` unchanged. This means a caller cannot accidentally request an unbounded result by passing a very large `limit`. The 200-row ceiling is enforced regardless of what the caller sends. Anti-patterns [#anti-patterns] The following patterns caused verified production incidents. Each is forbidden in all VantageOS MCP server implementations. **Root cause of the Day-114 incident class.** The Convex `paginate()` helper returns: ```typescript { value: T[]; continueCursor: string | null; isDone: boolean; } ``` The field is named `value`, not `page`. Reading `result?.page` from this shape returns `undefined`, causing the MCP handler to produce `items: []` on every call — silently dropping all data. This affected `list_memories` and `list_episodes` from v2.5.0 through v2.13.0. Both tools were fixed in PR #978 (squash `0db28d5`). ```typescript // FORBIDDEN — .page does not exist; items: [] on every call const rawList = Array.isArray((memories as any)?.page) ? (memories as any).page : []; // CORRECT — read .value from { value, continueCursor, isDone } const rawList = Array.isArray((memories as any)?.value) ? (memories as any).value : []; ``` Callers on vantage-peers-mcp below 2.13.1 received `items: []` from `list_memories` and `list_episodes` on every invocation. Upgrade to `>=2.13.1` is required. Accepting any `limit` value without a max cap allows callers to request 10 000+ rows in a single response. This overflows in-context budgets and can crash Railway/Convex response size limits. ```typescript // FORBIDDEN const limit = args.limit ?? 1000; // unbounded default // CORRECT import { clampLimit } from "./paging.js"; const requestedLimit = clampLimit(args.limit); // always [1, 200] ``` Clamping to 200 rows but not returning `nextCursor` leaves callers with a truncated result set and no way to paginate past the cap. ```typescript // FORBIDDEN — caller is stuck at 200 rows forever const rows = await fetchRows(200); return { items: rows }; // no nextCursor // CORRECT — detect hasMore, emit nextCursor const requestedLimit = clampLimit(args.limit); const rows = await fetchRows(requestedLimit + 1); const hasMore = rows.length > requestedLimit; const page = hasMore ? rows.slice(0, requestedLimit) : rows; const nextCursor = hasMore ? encodeCursor({ createdBefore: page[page.length - 1]._creationTime }) : undefined; return { items: page, ...(nextCursor !== undefined ? { nextCursor } : {}) }; ``` Returning `items` as a bare array (not wrapped in `{ items, nextCursor }`) breaks the pagination chain because callers cannot detect whether there are more pages. ```typescript // FORBIDDEN — flat array; caller cannot paginate return { content: [{ type: "text", text: JSON.stringify(rows) }] }; // CORRECT — always the { items, nextCursor? } envelope const envelope = { items: projected, ...(nextCursor ? { nextCursor } : {}) }; return { content: [{ type: "text", text: JSON.stringify(envelope, null, 2) }] }; ``` Returning the raw Convex `continueCursor` string as the `nextCursor` in the envelope exposes an internal format that may change across Convex versions. ```typescript // FORBIDDEN — leaks Convex internal format const envelope = { items: filteredList, nextCursor: result.continueCursor }; // CORRECT — always wrap through encodeCursor const nextCursor = !result.isDone && result.continueCursor !== null ? encodeCursor({ backendCursor: result.continueCursor }) : undefined; const envelope = { items: filteredList, ...(nextCursor ? { nextCursor } : {}) }; ``` `encodeCursor` produces an opaque base64url token. Callers pass this token back as the `cursor` argument on the next call. The decode side (`decodeCursor`) lives in the same `paging.ts` file. A test that asserts `result.items !== undefined` passes even when `items: []`. This was the root cause of the Day-114 "19/19 covered" misclaim — all 19 tests passed while `list_memories` and `list_episodes` silently returned empty arrays. ```typescript // FORBIDDEN — passes even when items: [] expect(parsed).toHaveProperty("items"); expect(Array.isArray(parsed.items)).toBe(true); // CORRECT — seed N rows, assert items.length === N const N = 5; mockConvex.mockResolvedValueOnce({ value: makeItems(N), continueCursor: null, isDone: true }); const result = await callTool("list_memories", { namespace: "orchestrator/sigma" }); const parsed = JSON.parse(result.content[0].text); expect(parsed.items).toHaveLength(N); // would have caught the Day-114 .page bug ``` Every `list_*` tool test suite must include at least one "insert N, assert `items.length === N`" assertion. Why each list_* tool defaults to envelope-safe shape [#why-each-list_-tool-defaults-to-envelope-safe-shape] The design goal is that a caller who passes no arguments at all still receives a safe response. The default `limit: 20` and `fields: "full"` combination produces at most \~400 KB for the most document-heavy tools, well within safe in-context budget for all supported clients (Claude.ai, Claude Code, ChatGPT, Codex). For production drain loops — sweeping all tasks for a BU, exporting a full namespace, etc. — always override to `limit: 200` and `fields: "lite"` to maximize throughput without risk. `paging.ts` exports reference [#pagingts-exports-reference] The shared `mcp-server/src/paging.ts` utility centralizes all paging logic. Its key exports: | Export | Type | Description | | | ----------------------- | ------------- | --------------------------------------------------------------- | ------ | | `pagingArgsSchema` | `z.ZodObject` | Shared Zod schema: `{ limit, cursor, fields }` | | | `DEFAULT_LIMIT` | `50` | `clampLimit` fallback when `undefined` given | | | `MAX_LIMIT` | `200` | Hard ceiling enforced by `clampLimit` | | | `ENVELOPE_TARGET_BYTES` | `50 000` | Soft byte cap for `enforceEnvelopeCap` | | | `clampLimit` | function | Clamps `limit` to `[1, MAX_LIMIT]`, defaults to `DEFAULT_LIMIT` | | | `encodeCursor` | function | `CursorPayload → base64url string` | | | `decodeCursor` | function | \`base64url string → CursorPayload | null\` | | `enforceEnvelopeCap` | function | Halves rows until under `ENVELOPE_TARGET_BYTES` | | The `DEFAULT_LIMIT` export from `clampLimit` is 50. Individual tools override this to 20 via `DEFAULT_PAGING.limit = 20` in `applyPagingDefaults`. When no limit is given to a specific list tool, the per-tool default of 20 applies — not the `DEFAULT_LIMIT` constant. Cross-references [#cross-references] * [Cursor Pagination](/docs/pagination) — envelope contract, loop pattern, coverage matrix * Main repo README: [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * MCP server npm: [vantage-peers-mcp](https://www.npmjs.com/package/vantage-peers-mcp) * MCP Tools Standard doctrine: VantageRegistry runbook `kd750j7z7tqre6hxqmfsa8s9ed89erng` * Day-114 fix PR: [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) * Doctrine PR: [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) --- # VantagePeers Documentation URL: /docs Welcome to VantagePeers [#welcome-to-vantagepeers] VantagePeers is the open-source backend that gives your AI agents shared memory, cross-machine messaging, task coordination, and mission planning — all in one Convex deployment. What is VantagePeers? [#what-is-vantagepeers] When you run multiple Claude Code agents across machines and sessions, they face a coordination problem: each agent starts fresh with no knowledge of what others have done, no way to send messages across machines, and no shared task board. You end up duct-taping together memory plugins, file-based hacks, and manual coordination — and it breaks at scale. VantagePeers solves this by providing a single self-hosted backend with 20 database tables and 82 MCP tools covering every coordination primitive your agent team needs. Agents store typed memories with semantic search, send messages with read receipts, assign tasks with priorities and dependencies, plan missions with lifecycle stages, write session diaries, and maintain a shared component registry. All of it persists in Convex cloud and is available to any agent on any machine. It is not a SaaS. It is not a managed service. You deploy it once with `npx convex deploy`, add it as an MCP server in your Claude Code config, and your entire agent team is coordinated. FSL license. Free forever. Quick Links [#quick-links] | Topic | Description | | ------------------------------------------------ | --------------------------------------------------- | | [Getting Started](/docs/getting-started) | Install, deploy, and connect in under 10 minutes | | [Quickstart](/docs/getting-started/quickstart) | Two agents exchanging messages in 15 minutes | | [Architecture](/docs/core-concepts/architecture) | Core concepts, database schema, and MCP integration | | [Tools Reference](/docs/tools) | All 14 tool categories and 82 tools | | [Memory](/docs/capabilities/memory) | Semantic memory, namespaces, and vector search | | [Messaging](/docs/capabilities/messaging) | Cross-machine messaging with read receipts | | [Tasks](/docs/capabilities/tasks) | Task lifecycle, priorities, missions, and cron | Key Numbers [#key-numbers] * **20 database tables** — memories, messages, tasks, missions, profiles, diary, briefings, components, fix patterns, issues, mandates, business units, and more * **82 MCP tools** — every coordination primitive exposed as a native MCP tool * **14 capability categories** — memory, messaging, tasks, missions, profiles, diary, search, registry, fix patterns, issues, mandates, business units, recurring tasks, error monitoring * **\< 10 minutes** — from zero to a fully coordinated agent team * **$0 / month** — FSL license, self-hosted on Convex free tier Who It Is For [#who-it-is-for] VantagePeers is built for engineers running orchestrated Claude Code agent teams. If you have more than one agent, or if any agent needs to remember things across sessions, you need a coordination backend. VantagePeers is that backend. --- # Cursor Pagination URL: /docs/pagination Cursor Pagination [#cursor-pagination] Every `list_*` tool in VantagePeers returns a consistent envelope that lets callers drain arbitrarily large result sets without hitting the 200-row response cap. Why pagination matters [#why-pagination-matters] VantagePeers stores everything in a shared Convex backend. A single namespace can accumulate thousands of tasks, memories, or briefing notes over the lifetime of an agent team. Without pagination: * A caller requesting all tasks in a large workspace would receive a truncated response with no way to detect the truncation. * The MCP response payload could exceed safe in-context sizes, causing silent data loss at the client. The envelope contract solves both problems: every `list_*` response tells callers explicitly whether there are more pages, and the hard cap of 200 rows per page keeps response payloads bounded. Canonical envelope [#canonical-envelope] Every `list_*` tool returns exactly this shape: ```typescript interface ListEnvelope { items: T[]; // projected rows — lite or full depending on fields param nextCursor?: string; // present when there are more pages; absent (not null) when done } ``` `nextCursor` follows two rules: 1. When present, it is an opaque base64url token. Do not parse or construct cursor values — pass them through unmodified. 2. When absent (not `null`, just missing), there are no more pages. Stop iterating. Cursor semantics [#cursor-semantics] The cursor token is opaque. Internally it encodes either a `{ createdBefore: number }` timestamp (the common case — most list tools use a `createdBefore` filter at the Convex layer) or a `{ backendCursor: string }` referencing a Convex-native `paginate()` continuation (used by `list_memories` and `list_episodes`). Callers never need to know which internal format applies. The decoding is handled server-side. **Absent cursor means done.** A caller loop must stop when `nextCursor` is not present in the response — not when `items` is empty, and not after a fixed number of pages. Default limit and hard cap [#default-limit-and-hard-cap] | Constant | Value | Meaning | | --------------- | ------------ | ------------------------------------------------------------ | | Default limit | 20 | Rows returned per page when no `limit` argument is given | | Hard cap | 200 | Maximum rows per page regardless of the `limit` argument | | Envelope target | 50 000 bytes | Soft size cap; server halves rows until under this threshold | Passing `limit: 200` gives the maximum page size. Passing no `limit` gives 20 rows. TypeScript cursor loop [#typescript-cursor-loop] The following pattern drains a complete `list_tasks` result set using cursor chaining: ```typescript import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; interface TaskItem { _id: string; title: string; status: string; assignedTo?: string; } interface ListEnvelope { items: T[]; nextCursor?: string; } async function drainTasks( client: Client, assignedTo: string, status: string = "active" ): Promise { const allTasks: TaskItem[] = []; let cursor: string | undefined = undefined; do { const result = await client.callTool({ name: "list_tasks", arguments: { assignedTo, status, fields: "lite", limit: 200, ...(cursor !== undefined ? { cursor } : {}), }, }); const text = (result.content as Array<{ type: string; text: string }>)[0].text; const envelope = JSON.parse(text) as ListEnvelope; allTasks.push(...envelope.items); cursor = envelope.nextCursor; } while (cursor !== undefined); return allTasks; } ``` Key points: * The loop condition is `cursor !== undefined`, not `items.length > 0`. An empty last page with no `nextCursor` is the normal terminal state. * `fields: "lite"` keeps each page well under the 50 KB envelope target. * `limit: 200` maximizes throughput per round-trip. Coverage matrix — 18 `list_*` tools [#coverage-matrix--18-list_-tools] Day-114 audit (`projects/vantage-peers/mcp-pagination-audit-day114.md`) verified all 18 `list_*` tools. | Tool | Cursor support | Envelope shape | Severity | | ----------------------- | -------------- | ----------------------------- | ----------------------------------------------- | | `list_tasks` | YES | `{items, nextCursor}` | LOW — compliant | | `list_tasks_by_mission` | YES | `{items, nextCursor}` | LOW — compliant | | `list_missions` | YES | `{items, nextCursor}` | LOW — compliant | | `list_messages` | YES | `{items, nextCursor}` | LOW — compliant | | `list_memories` | YES | `{items, nextCursor}` | LOW — fixed Day-114 PR #978 | | `list_episodes` | YES | `{items, nextCursor}` | LOW — fixed Day-114 PR #978 | | `list_briefing_notes` | YES | `{items, nextCursor}` | LOW — compliant | | `list_diaries` | YES | `{items, nextCursor}` | LOW — compliant | | `list_recurring_tasks` | YES | `{items, nextCursor}` | LOW — compliant | | `list_bus` | YES | `{items, nextCursor}` | LOW — compliant | | `list_peers` | YES | `{items, nextCursor}` | LOW — compliant | | `list_components` | YES | `{items, nextCursor}` | LOW — compliant | | `list_errors` | YES | `{items, nextCursor}` | LOW — compliant | | `list_issues` | YES | `{count, issues, nextCursor}` | LOW — compliant | | `list_repo_mappings` | YES | `{items, nextCursor}` | LOW — compliant | | `list_fix_patterns` | YES | `{items, nextCursor}` | LOW — compliant | | `list_mandates` | YES | `{items, nextCursor}` | LOW — compliant | | `list_broadcast_status` | EXCEPTION | single-object shape | EXCEPTION — documented `@cursorPagingException` | `list_broadcast_status` returns a single status object (`{ messageId, from, channel, receipts[] }`) rather than a top-level array. Cursor paging is architecturally incompatible with this shape. `list_issues` uses a slightly different envelope: `{count, issues, nextCursor}` rather than `{items, nextCursor}`. Access rows via the `issues` key, not `items`. `fields` parameter [#fields-parameter] All `list_*` tools accept a `fields` argument: | Value | Rows returned | Use case | | -------- | ------------------------------------------ | ----------------------------------------------- | | `"lite"` | Compact projection — 4 to 6 fields per row | Large page drains, sidebar lists, status checks | | `"full"` | All schema fields | Single-page fetches where full detail is needed | Default is `"full"`. For drain loops, always pass `fields: "lite"` to stay well within the 50 KB envelope target. Lite projections always include `_id` and `_creationTime` plus 2 to 4 display fields (e.g. `title`, `status`, `assignedTo` for tasks). Envelope safety [#envelope-safety] See [Envelope Safety](/docs/envelope-safety) for the complete anti-pattern catalogue — including why `memories?.page` was a Day-114 severity-HIGH incident and how the fix wires through `encodeCursor`/`decodeCursor`. Cross-references [#cross-references] * Main repo README: [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * MCP server README: [vantage-peers-mcp on npm](https://www.npmjs.com/package/vantage-peers-mcp) * MCP Tools Standard doctrine: VantageRegistry runbook `kd750j7z7tqre6hxqmfsa8s9ed89erng` * Day-114 audit doc: `projects/vantage-peers/mcp-pagination-audit-day114.md` * Day-114 fix PRs: [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) + [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) --- # Tools Catalogue URL: /docs/tools-catalogue Tools Catalogue [#tools-catalogue] Complete catalogue of every MCP tool registered in `vantage-peers-mcp`. Derived from `mcp-server/src/tools.ts` registered string literals. Current package version: `vantage-peers-mcp@2.13.1`. For full parameter documentation, see [Tools Reference](/docs/tools). For pagination behaviour on `list_*` tools, see [Cursor Pagination](/docs/pagination). Cursor/limit support (Y/N/EXCEPTION) reflects the Day-114 audit. All `list_*` tools carry cursor + 200-row cap post PR #978. Search tools (`search_*`) and single-entity getters (`get_*`) do not use the cursor envelope. Memory [#memory] | Tool | Purpose | Cursor/Limit | | -------------------- | ------------------------------------------------------------------------ | ------------------------- | | `store_memory` | Store a typed, namespaced memory with optional vector embedding | N | | `get_memory` | Fetch a single memory by document ID | N | | `list_memories` | List memories in a namespace filtered by type; default limit 20, cap 200 | Y — fixed Day-114 PR #978 | | `soft_delete_memory` | Soft-delete a memory so it stops appearing in recall results | N | | `recall` | Semantic vector search over memories in a namespace (RRF fusion) | N | | `text_search` | BM25 full-text keyword search over memories | N | | `hybrid_search` | Combined vector + BM25 hybrid search using RRF fusion | N | Episodes [#episodes] | Tool | Purpose | Cursor/Limit | | ----------------------------- | -------------------------------------------------------------------------------------------------------- | ------------------------- | | `store_episode` | Store a structured episode (context, goal, action, outcome, insight, severity) | N | | `get_episode` | Fetch a single episode by memory document ID | N | | `list_episodes` | List episodes ordered newest first, optional namespace + orchestrator filters; default limit 20, cap 200 | Y — fixed Day-114 PR #978 | | `search_episodes_by_keyword` | BM25 full-text keyword search restricted to episodes | N | | `search_episodes_by_semantic` | Semantic vector search restricted to episodes, ranked by cosine similarity | N | Messaging [#messaging] | Tool | Purpose | Cursor/Limit | | ---------------------------- | --------------------------------------------------------------------------------- | ------------------------------- | | `send_message` | Send a message to a channel, role, or broadcast | N | | `check_messages` | Retrieve unread messages for a recipient; accepts `since` for incremental polling | N | | `mark_as_read` | Mark one or more messages as read using receipt IDs | N | | `delete_message` | Delete a message by ID (sender or system only) | N | | `get_message` | Fetch a single message by Convex document ID with full body and channel | N | | `list_messages` | List messages with optional from/channel filters; default limit 20, cap 200 | Y | | `list_broadcast_status` | Show who read a broadcast message and who did not | EXCEPTION — single-object shape | | `search_messages_by_keyword` | BM25 full-text keyword search over message content | N | Tasks [#tasks] | Tool | Purpose | Cursor/Limit | | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------- | - | | `create_task` | Create a new task and assign it to an orchestrator | N | | | `get_task` | Fetch a single task by Convex document ID with all fields | N | | | `list_tasks` | List tasks by assignee and/or status; \`fields=lite | full`, `createdBy`, `updatedSince`, `excludeAutoGenerated\`; default limit 20, cap 200 | Y | | `search_tasks_by_keyword` | BM25 full-text keyword search over task titles | N | | | `update_task` | Update task fields — status, priority, blockers, or completion note; **cancel** via `status="cancelled"` + `cancelReason` (creator-only) | N | | | `start_task` | Mark a task as `in_progress` and record the start timestamp; resumes rather than restarts if worked time already exists; refuses if a work segment is already open | N | | | `pause_task` | Close the open work segment and stop the duration clock, without ending the task — paused is not blocked | N | | | `resume_task` | Open a new work segment on a paused task and set it back to `in_progress` | N | | | `complete_task` | Mark a task as `done` with a mandatory completion note | N | | | `block_task` | Set a task to `blocked` status with a reason | N | | | `add_task_dependency` | Link two tasks so one cannot start before the other completes | N | | | `checkout_task` | Atomically claim a task (conflict-safe for multi-instance) | N | | | `delete_task` | Permanently delete a task (creator or system only; blocked in production — **cancel** an erroneous task via `status="cancelled"` instead) | N | | | `list_tasks_by_mission` | List all tasks linked to a specific mission; same `status`, `fields`, `createdBy`, `cursor` params as `list_tasks`; default limit 20, cap 200 | Y | | | `bulk_complete_tasks` | Bulk-close multiple tasks with dry-run-default safety and RBAC gate | N | | | `validate_task_payload` | Dry-run lint for VP write-path tools; returns failures with fix snippets | N | | Missions [#missions] | Tool | Purpose | Cursor/Limit | | | ----------------------------------- | ------------------------------------------------------------- | ------------------------------------------- | - | | `create_mission` | Create a new mission and assign a pilot | N | | | `get_mission` | Return a mission with all its linked tasks and current status | N | | | `list_missions` | List missions filtered by status or pilot; \`fields=lite | full`, `cursor\`; default limit 20, cap 200 | Y | | `update_mission` | Advance a mission to the next stage or update its metadata | N | | | `update_mission_status` | Change a mission lifecycle status in a single call | N | | | `get_mission_template` | Fetch a mission template by name with all steps | N | | | `update_mission_template` | Create or upsert a mission template by name | N | | | `instantiate_template_into_mission` | Create one task per template step inside a mission | N | | Profiles [#profiles] | Tool | Purpose | Cursor/Limit | | ---------------- | -------------------------------------------------------------------------------------------------- | ------------ | | `get_profile` | Return the profile for an orchestrator | N | | `update_profile` | Create or update an orchestrator profile (partial updates supported) | N | | `list_peers` | Return all known agent instances and their current status, newest first; default limit 20, cap 200 | Y | | `set_summary` | Update the current working summary for an orchestrator instance | N | | `whoami` | Return the orchestrator identity baked into the current bearer OAuth scope | N | Diary [#diary] | Tool | Purpose | Cursor/Limit | | -------------- | -------------------------------------------------------------------------------------- | ------------ | | `write_diary` | Write a diary entry for a given date, overwriting any existing entry | N | | `get_diary` | Fetch a specific diary entry by orchestrator and date | N | | `list_diaries` | List diary entries for an orchestrator, optional date range; default limit 20, cap 200 | Y | Briefing Notes [#briefing-notes] | Tool | Purpose | Cursor/Limit | | | ---------------------------------- | ----------------------------------------------------------------------------- | ------------------------------------------- | - | | `create_briefing_note` | Create a structured briefing record with participants, content, and decisions | N | | | `update_briefing_note` | Partial-update an existing briefing note (RBAC: `createdBy` or `system` only) | N | | | `get_briefing_note` | Fetch a single briefing note by ID with all fields | N | | | `list_briefing_notes` | List briefings filtered by topic; \`fields=lite | full`, `cursor\`; default limit 20, cap 200 | Y | | `search_briefing_notes_by_keyword` | BM25 full-text keyword search over briefing note content | N | | Components [#components] | Tool | Purpose | Cursor/Limit | | -------------------- | --------------------------------------------------------------------------------------- | ------------ | | `register_component` | Register a component (agent, skill, hook, plugin) with full content backup | N | | `get_component` | Retrieve a component by name and type | N | | `list_components` | List all registered components filtered by type; default limit 20, cap 200 | Y | | `update_component` | Update a component content or version | N | | `delete_component` | Remove a component from the registry | N | | `search_components` | BM25 substring keyword search over components by name or team with optional type filter | N | Recurring Tasks [#recurring-tasks] | Tool | Purpose | Cursor/Limit | | ----------------------- | --------------------------------------------------------------------- | ------------ | | `create_recurring_task` | Define a recurring task template with cron expression | N | | `get_recurring_task` | Fetch a single recurring task definition by Convex document ID | N | | `list_recurring_tasks` | List all recurring task templates; default limit 20, cap 200 | Y | | `update_recurring_task` | Update a recurring task template | N | | `delete_recurring_task` | Remove a recurring task template (does not delete existing instances) | N | | `pause_recurring_task` | Pause a recurring task | N | | `resume_recurring_task` | Resume a paused recurring task | N | Mandates [#mandates] | Tool | Purpose | Cursor/Limit | | --------------------------- | --------------------------------------------------------- | ------------ | | `create_mandate` | Create a cross-agent service request with budget tracking | N | | `accept_mandate` | Accept a mandate | N | | `update_mandate` | Update mandate fields | N | | `settle_mandate` | Record actual cost and close a mandate | N | | `validate_mandate_spending` | Check if a transaction is within mandate limits | N | | `list_mandates` | List mandates with filters; default limit 20, cap 200 | Y | | `get_mandate` | Fetch a single mandate by Convex document ID | N | Business Units [#business-units] | Tool | Purpose | Cursor/Limit | | ----------- | --------------------------------------------- | ------------ | | `create_bu` | Create a business unit with strategy and KPIs | N | | `update_bu` | Update BU fields | N | | `get_bu` | Fetch a BU by ID | N | | `list_bus` | List all BUs; default limit 20, cap 200 | Y | | `delete_bu` | Delete a BU | N | GitHub Issues [#github-issues] | Tool | Purpose | Cursor/Limit | | ----------------------- | ------------------------------------------------------------------------------------------- | ------------ | | `list_issues` | List issues with filters; envelope `{count, issues, nextCursor}`; default limit 20, cap 200 | Y | | `get_issue` | Fetch a single issue | N | | `update_issue_status` | Update issue status | N | | `link_commit_to_issue` | Link a commit SHA to an issue | N | | `verify_issue` | Mark an issue as verified | N | | `issue_stats` | Get issue count stats by project and status | N | | `link_issue_to_pattern` | Link an issue to a fix pattern | N | Repo Mappings [#repo-mappings] | Tool | Purpose | Cursor/Limit | | | --------------------- | ------------------------------------------------ | ------------------------------------------- | - | | `add_repo_mapping` | Map a GitHub repo slug to an orchestrator | N | | | `list_repo_mappings` | List all repo mappings; \`fields=lite | full`, `cursor\`; default limit 20, cap 200 | Y | | `remove_repo_mapping` | Remove a repo mapping | N | | | `get_repo_mapping` | Fetch a single repo mapping by slug (owner/name) | N | | Fix Patterns [#fix-patterns] | Tool | Purpose | Cursor/Limit | | --------------------- | ----------------------------------------------------------- | ------------ | | `create_fix_pattern` | Create a fix pattern documenting a bug, root cause, and fix | N | | `get_fix_pattern` | Fetch a single fix pattern by Convex document ID | N | | `add_fix_attempt` | Document a fix attempt (worked/failed) with reasoning | N | | `validate_fix` | Set the validated fix on a pattern | N | | `search_fix_patterns` | Semantic search over fix patterns by symptom | N | | `list_fix_patterns` | List fix patterns by project; default limit 20, cap 200 | Y | Deployments [#deployments] | Tool | Purpose | Cursor/Limit | | ------------------- | ----------------------------------------------------------- | ------------ | | `add_deployment` | Register a Convex deployment for proactive error monitoring | N | | `remove_deployment` | Deactivate a monitored deployment | N | Error Monitoring [#error-monitoring] | Tool | Purpose | Cursor/Limit | | ------------- | ----------------------------------------------------------------------------------------------------- | ------------ | | `list_errors` | List detected deployment errors with dedup counts and linked issue numbers; default limit 20, cap 200 | Y | | `get_error` | Fetch a single error log entry by Convex document ID | N | OKF Bundle [#okf-bundle] | Tool | Purpose | Cursor/Limit | | --------------------- | ------------------------------------------------------------------------------ | ------------ | | `export_okf_bundle` | Export a namespace as a portable OKF tarball (memories, briefings, tasks) | N | | `validate_okf_bundle` | Validate an OKF bundle without writing to the database (dry-run, read-only) | N | | `import_okf_bundle` | Import an OKF bundle into a target namespace (dry-run / merge / replace modes) | N | Improvisation [#improvisation] | Tool | Purpose | Cursor/Limit | | ---------------------- | ---------------------------------------------------------------------------------------------------------------------------------- | ------------ | | `improvisation_digest` | Weekly digest scanning VP tasks, messages, and memories for durable-artifact fleet claims missing VP-Sources footer; advisory only | N | Summary [#summary] | Domain | Tool count | | ---------------- | ---------- | | Memory | 7 | | Episodes | 5 | | Messaging | 8 | | Tasks | 16 | | Missions | 8 | | Profiles | 5 | | Diary | 3 | | Briefing Notes | 5 | | Components | 6 | | Recurring Tasks | 7 | | Mandates | 7 | | Business Units | 5 | | GitHub Issues | 7 | | Repo Mappings | 4 | | Fix Patterns | 6 | | Deployments | 2 | | Error Monitoring | 2 | | OKF Bundle | 3 | | Improvisation | 1 | | **Total** | **107** | Note: 14 duplicate aliases were removed from the registered surface (PR #1169); every tool below is a canonical name with no alias. Cross-references [#cross-references] * [Tools Reference](/docs/tools) — full parameter documentation per tool * [Cursor Pagination](/docs/pagination) — loop pattern, envelope contract, coverage matrix * [Envelope Safety](/docs/envelope-safety) — anti-patterns, `fields=lite`, limit clamp * [Day-114 Release Notes](/docs/release-notes/day-114) * Main repo README: [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * MCP server npm: [vantage-peers-mcp](https://www.npmjs.com/package/vantage-peers-mcp) * MCP Tools Standard doctrine: VantageRegistry runbook `kd750j7z7tqre6hxqmfsa8s9ed89erng` --- # Tools Reference URL: /docs/tools Tools Reference [#tools-reference] VantagePeers exposes 100 MCP tools organized into 15 capability categories. Every tool accepts and returns JSON. All values are lowercase strings unless noted. Tool Categories [#tool-categories] | Category | Tool Count | Description | | ----------------------------------------------------- | ---------- | -------------------------------------------------------------- | | [Memory + Episodes](#memory--episode-tools) | 12 | Typed memories, episodic learning, semantic and keyword search | | [Messaging](#messaging-tools) | 8 | Send messages across machines with read receipts | | [Tasks](#task-tools) | 12 | Create and manage tasks with full lifecycle tracking | | [Missions + Templates](#mission--template-tools) | 8 | Group tasks into missions; instantiate templates | | [Profiles + Session](#profile-and-session-tools) | 5 | Agent identity, session state, and identity resolution | | [Diary + Briefing Notes](#diary--briefing-note-tools) | 8 | Daily journals, briefing notes, and keyword search | | [Components](#component-tools) | 6 | Component backup and inventory | | [Recurring Tasks](#recurring-task-tools) | 7 | Cron-based automation | | [Mandates](#mandate-tools) | 7 | Cross-agent service requests with budgets | | [Business Units](#business-unit-tools) | 5 | BU strategy, pricing, and KPIs | | [GitHub Issues + Repos](#github-issue--repo-tools) | 11 | Issue tracking with webhook sync and repo mappings | | [Fix Patterns](#fix-pattern-tools) | 6 | Bug fix knowledge base with semantic search | | [Error Monitoring](#error-monitoring-tools) | 2 | Proactive deployment error detection | | [Deployments](#deployment-tools) | 2 | Register and manage monitored deployments | | [Utility](#utility-tools) | 1 | Payload validation | *** Memory + Episode Tools [#memory--episode-tools] The memory system stores typed, namespaced knowledge with semantic vector embeddings. All memories are searchable by meaning, not just keyword. Episodes are structured memories capturing a full event: context, goal, action, outcome, and insight. `store_memory` [#store_memory] Stores a new memory with optional vector embedding. ```json { "namespace": "global", "type": "feedback", "content": "Always use Edit tool over Write for existing files.", "createdBy": "alice" } ``` Returns the new memory ID. `get_memory` [#get_memory] Fetch a single memory by its ID. ```json { "memoryId": "jn7abc123..." } ``` `list_memories` [#list_memories] Lists memories in a namespace, optionally filtered by type. ```json { "namespace": "project/vantage-starter", "type": "project", "limit": 20 } ``` `soft_delete_memory` [#soft_delete_memory] Soft-delete a memory so it stops appearing in recall results. ```json { "memoryId": "jn7abc123..." } ``` `recall` [#recall] Semantic search over memories in a namespace. Uses vector similarity + optional keyword filters. ```json { "query": "Edit tool best practices", "namespace": "global", "limit": 5 } ``` Returns an array of matching memories ranked by relevance. `text_search` [#text_search] BM25 full-text keyword search over memories. ```json { "query": "deployment error", "namespace": "global", "limit": 10 } ``` `hybrid_search` [#hybrid_search] Combined vector + BM25 search using RRF fusion. ```json { "query": "deployment error", "namespace": "global", "limit": 10 } ``` `store_episode` [#store_episode] Stores a structured episode (a failure or success event with full context). ```json { "namespace": "orchestrator/alice", "createdBy": "alice", "context": "Deploying frontend component", "goal": "Fix broken layout on mobile", "action": "Delegated to dev-frontend with exact file:line brief", "outcome": "Fixed in one pass, no revisions needed", "insight": "Precise briefs with file:line citations eliminate revision cycles", "severity": "minor" } ``` Severity levels: `minor`, `major`, `critical`. `get_episode` [#get_episode] Fetch a single episode by its memory document ID. Episodes are memories with `type='episode'`. ```json { "memoryId": "jn7abc123..." } ``` `list_episodes` [#list_episodes] List episodes ordered newest first, with optional namespace and orchestrator filters. ```json { "namespace": "orchestrator/alice", "limit": 20 } ``` `search_episodes_by_keyword` [#search_episodes_by_keyword] BM25 full-text keyword search restricted to episodes. ```json { "query": "deployment race condition", "namespace": "global" } ``` `search_episodes_by_semantic` [#search_episodes_by_semantic] Semantic vector search restricted to episodes, ranked by cosine similarity. ```json { "query": "build broke after dependency upgrade", "namespace": "global", "limit": 5 } ``` *** Messaging Tools [#messaging-tools] Messages persist in Convex cloud. Offline agents receive messages when they reconnect. Read receipts are tracked per recipient. `send_message` [#send_message] Sends a message to a channel, role, or specific instance. ```json { "from": "alice", "channel": "bob", "content": "Phase 1 complete. Ready for review." } ``` To broadcast to all agents: ```json { "from": "bob", "channel": "broadcast", "content": "Merge freeze starts Thursday. No non-critical commits." } ``` `check_messages` [#check_messages] Retrieves unread messages for a recipient. Pass `since` (Unix ms timestamp) for incremental polling to avoid re-transferring the full unread backlog. ```json { "recipient": "alice", "recipientInstanceId": "alice-main", "since": 1776803000000 } ``` Returns an array of messages with receipt IDs. `mark_as_read` [#mark_as_read] Marks one or more messages as read using receipt IDs. ```json { "receiptIds": ["receipt-abc123", "receipt-def456"] } ``` `delete_message` [#delete_message] Delete a message by ID (sender or system only). ```json { "messageId": "jn7..." } ``` `get_message` [#get_message] Fetch a single message by its Convex document ID with full body, channel, sender, and tenant scope. ```json { "messageId": "jn7..." } ``` `list_messages` [#list_messages] List messages with optional filters (from, channel). ```json { "from": "alice", "limit": 20 } ``` `list_broadcast_status` [#list_broadcast_status] Show who read a broadcast message and who didn't. ```json { "messageId": "msg-abc123" } ``` `search_messages_by_keyword` [#search_messages_by_keyword] BM25 full-text keyword search over message content, ranked by relevance. ```json { "query": "PR review approved", "limit": 10 } ``` *** Task Tools [#task-tools] Tasks track work from creation to completion with full audit trail. `create_task` [#create_task] Creates a new task and assigns it to an orchestrator. ```json { "title": "Migrate HeroSection to lit-ui components", "assignedTo": "alice", "priority": "high", "createdBy": "bob", "missionId": "mission-landing-page" } ``` Priority levels: `low`, `medium`, `high`, `urgent`. `get_task` [#get_task] Fetch a single task by its Convex document ID with all fields: title, description, status, priority, assignment, dependencies, mission link, completion note. ```json { "taskId": "jn7abc123..." } ``` `list_tasks` [#list_tasks] Lists tasks filtered by assignee and/or status. **v2.3.x params:** | Param | Notes | | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------- | | `status` | Single value, array `["todo","in_progress"]`, or alias: `"open"` → todo+in\_progress+review+blocked, `"active"` → todo+in\_progress, `"all"` → no filter | | `fields` | `"lite"` returns compact projection (5-10x smaller). Default `"full"`. | | `createdBy` | Filter to tasks created by a specific orchestrator (e.g. `"pi"`). | | `updatedSince` | Unix ms timestamp; filter to rows updated after this time. | | `cursor` | Opaque cursor for paging past the 200-row cap. | ```json { "assignedTo": "alice", "status": "active", "fields": "lite", "createdBy": "pi", "limit": 30 } ``` `search_tasks_by_keyword` [#search_tasks_by_keyword] BM25 full-text keyword search over task titles. ```json { "query": "migration hero section", "limit": 10 } ``` `update_task` [#update_task] Updates task fields — status, priority, blockers, or completion note. ```json { "taskId": "task-abc123", "status": "review", "completionNote": "Migrated HeroSection. All lit-ui, no shadcn. Biome and tsc pass." } ``` **Cancel an erroneously-created task** by setting `status="cancelled"` with a mandatory `cancelReason` — only the task's creator can cancel it. A cancelled task is excluded from the `open`/`active` list filters and is never counted as `done`; an already-`done` task cannot be cancelled. Prefer this over `delete_task` (blocked in production). The same applies to missions via `update_mission` (`status="cancelled"` + `cancelReason`, creator-only). ```json { "taskId": "task-abc123", "status": "cancelled", "cancelReason": "created against the wrong project", "callerOrchestrator": "sigma" } ``` `start_task` [#start_task] Marks a task as `in_progress` and records the start timestamp. On a task that already carries worked time, this resumes it instead of restarting the clock — the original start timestamp is kept and a new work segment is opened. Refuses if the task already has an open work segment (someone is already actively working on it): the error names the verb you probably meant instead (`resume_task` if the task was paused). ```json { "taskId": "task-abc123" } ``` `pause_task` [#pause_task] Closes the task's currently open work segment and stops the duration clock, without ending the task. Paused is not the same as blocked: `blocked` means waiting on someone else, `pause_task` means nobody is working on it right now but nothing is stopping the work. The task returns to `todo`, and its owner picks it back up with `resume_task`; `checkout_task` refuses a paused task rather than letting someone else claim it. ```json { "taskId": "task-abc123" } ``` `resume_task` [#resume_task] Opens a new work segment on a paused task and sets it back to `in_progress`. Refuses if the task is not currently paused. ```json { "taskId": "task-abc123" } ``` `complete_task` [#complete_task] Marks a task as `done` with a mandatory completion note. ```json { "taskId": "task-abc123", "completionNote": "Done. PR #47 submitted for review." } ``` `block_task` [#block_task] Sets a task to `blocked` status with a reason. ```json { "taskId": "task-abc123", "reason": "Waiting on design approval for new color tokens" } ``` `add_task_dependency` [#add_task_dependency] Links two tasks so one cannot start before the other completes. ```json { "taskId": "task-abc123", "dependsOn": "task-xyz789" } ``` `checkout_task` [#checkout_task] Atomically claim a task (conflict-safe for multi-instance). ```json { "taskId": "task-abc123", "callerOrchestrator": "alice" } ``` `delete_task` [#delete_task] Permanently delete a task (creator or system only). ```json { "taskId": "task-abc123", "callerOrchestrator": "carol" } ``` `list_tasks_by_mission` [#list_tasks_by_mission] List all tasks linked to a specific mission. Accepts the same `status`, `fields`, `createdBy`, `cursor` params as `list_tasks`. ```json { "missionId": "mission-abc123", "status": "active", "fields": "lite" } ``` *** Mission + Template Tools [#mission--template-tools] Missions group related tasks and track progress through defined lifecycle stages. Templates enable one-shot mission instantiation. `create_mission` [#create_mission] Creates a new mission and assigns a pilot. ```json { "name": "Landing Page Migration — Phase 1", "project": "vantage-starter", "priority": "high", "pilot": "alice", "agents": ["alice"], "status": "plan", "createdBy": "alice", "targetDate": 1712275200000 } ``` `get_mission` [#get_mission] Returns a mission with all its linked tasks and current status. ```json { "missionId": "mission-abc123" } ``` `list_missions` [#list_missions] Lists all missions, optionally filtered by status or pilot. **v2.3.x:** accepts `status` array/aliases (`"open"` → brainstorm+plan+execute+validate; `"active"` → plan+execute; `"all"` → no filter), `fields=lite|full`, and `cursor` for paging. ```json { "status": "active", "fields": "lite" } ``` `update_mission` [#update_mission] Advances a mission to the next stage or updates its metadata. ```json { "missionId": "mission-abc123", "status": "validate" } ``` `update_mission_status` [#update_mission_status] Change a mission's lifecycle status in a single call without touching other fields. ```json { "missionId": "mission-abc123", "status": "validate" } ``` `get_mission_template` [#get_mission_template] Fetch a mission template by name with all steps, or null if not found. ```json { "name": "irp" } ``` Built-in templates: `irp` (13 steps), `repo-fix` (10 steps), `new-feature` (10 steps). `update_mission_template` [#update_mission_template] Create or upsert a mission template by name. Existing templates are overwritten. ```json { "name": "custom-review", "steps": [ { "title": "Audit codebase", "assignedTo": "eta" }, { "title": "Write report", "assignedTo": "sigma" } ] } ``` `instantiate_template_into_mission` [#instantiate_template_into_mission] Create one task per template step inside a mission, pre-assigned to each step's declared orchestrator. ```json { "missionId": "mission-abc123", "templateName": "irp", "createdBy": "pi" } ``` *** Profile and Session Tools [#profile-and-session-tools] Agent profiles store static identity and dynamic state. `get_profile` [#get_profile] Returns the profile for an orchestrator. ```json { "orchestratorId": "alice" } ``` `update_profile` [#update_profile] Create or update an orchestrator profile (partial updates supported). ```json { "orchestratorId": "alice", "name": "Alice", "dynamic": { "currentTask": "Building dashboard", "lastSeen": 1712275200000, "sessionCount": 42 } } ``` `list_peers` [#list_peers] Returns all known agent instances and their current status, newest first. Supports `cursor` paging. ```json {} ``` `set_summary` [#set_summary] Updates the current working summary for an orchestrator instance. ```json { "orchestratorId": "alice", "instanceId": "alice-main", "summary": "Migrating HeroSection to lit-ui" } ``` `whoami` [#whoami] Returns the orchestrator identity baked into the current bearer's OAuth scope context. Use at session start to confirm your identity. ```json {} ``` Returns: `{ "orchestratorId": "alice", "orgSlug": "vantageos" }`. *** Diary + Briefing Note Tools [#diary--briefing-note-tools] `write_diary` [#write_diary] Writes a diary entry for a given date. Overwrites any existing entry for that date. ```json { "date": "2026-03-29", "orchestrator": "alice", "content": "Completed Phase 1 of landing page migration.", "highlights": ["Nav migrated to lit-ui", "Hero responsive layout fixed"] } ``` `get_diary` [#get_diary] Fetch a specific diary entry by orchestrator and date. ```json { "orchestrator": "alice", "date": "2026-03-29" } ``` `list_diaries` [#list_diaries] List diary entries for an orchestrator, optionally filtered by date range. Supports `cursor` paging. ```json { "orchestrator": "alice", "limit": 10 } ``` `create_briefing_note` [#create_briefing_note] Creates a structured briefing record. ```json { "title": "Landing page migration kickoff", "topic": "migration", "participants": ["alice", "bob"], "content": "Discussed the plan to migrate the landing page.", "decisions": [ "Migrate section by section, not all at once", "Each section gets its own commit" ], "createdBy": "alice" } ``` `update_briefing_note` [#update_briefing_note] Partial-update an existing briefing note (RBAC: `createdBy` or `system` only). ```json { "briefingNoteId": "jn7...", "decisions": ["Migrate section by section", "Deploy on Friday"] } ``` `get_briefing_note` [#get_briefing_note] Fetch a single briefing note by ID with all fields: title, topic, participants, content, decisions, and memory links. ```json { "briefingNoteId": "jn7..." } ``` `list_briefing_notes` [#list_briefing_notes] Lists briefings, optionally filtered by topic. Accepts `fields=lite|full` and `cursor` for paging. ```json { "topic": "migration", "fields": "lite", "limit": 20 } ``` `search_briefing_notes_by_keyword` [#search_briefing_notes_by_keyword] BM25 full-text keyword search over briefing note content, ranked by relevance. ```json { "query": "lit-ui migration decision", "limit": 10 } ``` *** Component Tools [#component-tools] The component registry stores your agent team's capability inventory — agents, skills, hooks, and plugins. `register_component` [#register_component] Registers a component with full content backup. ```json { "name": "dev-frontend", "type": "agent", "content": "...full agent file content...", "version": "1.2.0", "createdBy": "carol" } ``` Type values: `agent`, `skill`, `hook`, `plugin`. `get_component` [#get_component] Retrieves a component by name and type. ```json { "name": "dev-frontend", "type": "agent" } ``` `list_components` [#list_components] Lists all registered components, optionally filtered by type. Supports `cursor` paging. ```json { "type": "agent" } ``` `update_component` [#update_component] Updates a component's content or version. ```json { "componentId": "component-abc123", "content": "...updated content...", "version": "1.3.0" } ``` `delete_component` [#delete_component] Removes a component from the registry. ```json { "componentId": "component-abc123" } ``` `search_components` [#search_components] BM25 / substring keyword search over components by name or team with optional type filter. ```json { "query": "lit-ui frontend", "type": "agent" } ``` *** Recurring Task Tools [#recurring-task-tools] Recurring tasks auto-create new task instances on a cron schedule. `create_recurring_task` [#create_recurring_task] Defines a recurring task template. ```json { "title": "Daily standup: review open tasks and unread messages", "cronExpression": "0 9 * * *", "assignedTo": "alice", "priority": "medium" } ``` Standard cron expressions. Convex runs the scheduler. `get_recurring_task` [#get_recurring_task] Fetch a single recurring task definition by its Convex document ID. ```json { "recurringTaskId": "jn7..." } ``` `list_recurring_tasks` [#list_recurring_tasks] Lists all recurring task templates. Supports `cursor` paging. ```json {} ``` `update_recurring_task` [#update_recurring_task] Updates a recurring task template. ```json { "recurringTaskId": "rt-abc123", "cronExpression": "0 8 * * 1-5" } ``` `delete_recurring_task` [#delete_recurring_task] Removes a recurring task template. Does not delete already-created instances. ```json { "recurringTaskId": "rt-abc123" } ``` `pause_recurring_task` [#pause_recurring_task] Pause a recurring task. ```json { "recurringTaskId": "rt-abc123" } ``` `resume_recurring_task` [#resume_recurring_task] Resume a paused recurring task. ```json { "recurringTaskId": "rt-abc123" } ``` *** Mandate Tools [#mandate-tools] Cross-agent service requests with budget tracking. See [Mandates](/docs/capabilities/mandates) for full documentation. | Tool | Description | | --------------------------- | -------------------------------------------- | | `create_mandate` | Create a service request with budget | | `accept_mandate` | Accept a mandate | | `update_mandate` | Update mandate fields | | `settle_mandate` | Record actual cost, close mandate | | `validate_mandate_spending` | Check if transaction is within limits | | `list_mandates` | List mandates with filters | | `get_mandate` | Fetch a single mandate by Convex document ID | *** Business Unit Tools [#business-unit-tools] Track organizational units with strategy and KPIs. See [Business Units](/docs/infrastructure/business-units) for full documentation. | Tool | Description | | ----------- | ---------------------- | | `create_bu` | Create a business unit | | `update_bu` | Update BU fields | | `get_bu` | Fetch a BU by ID | | `list_bus` | List all BUs | | `delete_bu` | Delete a BU | *** GitHub Issue + Repo Tools [#github-issue--repo-tools] Issue tracking with webhook sync and auto-linking. See [GitHub Issues](/docs/infrastructure/issues) for full documentation. | Tool | Description | | ----------------------- | ------------------------------------------------ | | `list_issues` | List issues with filters | | `get_issue` | Fetch a single issue | | `update_issue_status` | Update issue status | | `link_commit_to_issue` | Link a commit to an issue | | `verify_issue` | Mark an issue as verified | | `issue_stats` | Get issue count stats | | `link_issue_to_pattern` | Link an issue to a fix pattern | | `add_repo_mapping` | Map a GitHub repo to an orchestrator | | `list_repo_mappings` | List all repo mappings | | `remove_repo_mapping` | Remove a repo mapping | | `get_repo_mapping` | Fetch a single repo mapping by slug (owner/name) | *** Fix Pattern Tools [#fix-pattern-tools] Bug fix knowledge base with semantic search. See [Fix Patterns KB](/docs/capabilities/fix-patterns) for full documentation. | Tool | Description | | --------------------- | ----------------------------------------------------------- | | `create_fix_pattern` | Create a fix pattern documenting a bug, root cause, and fix | | `get_fix_pattern` | Fetch a single fix pattern by Convex document ID | | `add_fix_attempt` | Document a fix attempt (worked/failed) with reasoning | | `validate_fix` | Set the validated fix on a pattern | | `search_fix_patterns` | Semantic search over patterns by symptom | | `list_fix_patterns` | List patterns by project with cursor paging | *** Error Monitoring Tools [#error-monitoring-tools] Proactive deployment error detection with automatic GitHub issue creation. See [Error Monitoring](/docs/infrastructure/error-monitoring) for full documentation. | Tool | Description | | ------------- | --------------------------------------------------------------- | | `list_errors` | List detected errors with dedup counts and linked issue numbers | | `get_error` | Fetch a single error log entry by Convex document ID | *** Deployment Tools [#deployment-tools] Register Convex deployments for proactive error monitoring. | Tool | Description | | ------------------- | ------------------------------------ | | `add_deployment` | Register a deployment for monitoring | | `remove_deployment` | Deactivate a monitored deployment | *** Utility Tools [#utility-tools] `validate_task_payload` [#validate_task_payload] Dry-run lint for VP write-path tools. Checks all validation axes and returns failures with fix snippets. Use before `create_task` or `complete_task` when building automation. ```json { "tool": "complete_task", "payload": { "taskId": "jn7...", "completionNote": "done" } } ``` Returns: `{ "valid": false, "failures": [{ "field": "completionNote", "reason": "must be ≥ 40 chars with a verifiable proof token" }] }`. --- # briefingNotes — API Reference URL: /docs/api-reference/briefing-notes briefingNotes [#briefingnotes] **Source:** `convex/briefingNotes.ts` **Fn-paths:** 5 Briefing notes are structured session handoffs between orchestrators. Each note has a topic, participants, content, and optional decisions. They are the canonical record for cross-session context transfer — a briefing note from the end of one session is read at the start of the next. *** `briefingNotes:create` [#briefingnotescreate] **Scope:** mutation Insert a new briefing note. Args [#args] ```typescript { title: string, topic: string, // category key, e.g. "vp-release", "sprint-review" participants: string[], // orchestrator IDs present content: string, decisions?: string[], linkedMemoryIds?: Id<"memories">[], createdBy: string, // orchestrator ID } ``` Returns [#returns] `Id<"briefingNotes">` — the new note ID. Example (ConvexHttpClient) [#example-convexhttpclient] ```typescript const noteId = await client.mutation("briefingNotes:create", { title: "Day 82 sprint close", topic: "sprint-review", participants: ["pi", "sigma"], content: "Completed M3 iframeEmbedSessions. Outstanding: OAuth DCR audit.", decisions: ["Defer DCR audit to Day 83", "Ship v2.4.0 now"], createdBy: "pi", }); ``` Example (MCP tool) [#example-mcp-tool] ```json { "tool": "mcp__vantage-peers__create_briefing_note", "args": { "title": "Day 82 sprint close", "topic": "sprint-review", "participants": ["pi", "sigma"], "content": "Completed M3 iframeEmbedSessions.", "createdBy": "pi" } } ``` *** `briefingNotes:get` [#briefingnotesget] **Scope:** query Fetch a single briefing note by ID. Args [#args-1] ```typescript { noteId: Id<"briefingNotes"> } ``` Returns [#returns-1] ```typescript { _id: Id<"briefingNotes">, _creationTime: number, title: string, topic: string, participants: string[], content: string, decisions?: string[], linkedMemoryIds?: Id<"memories">[], createdBy: string, createdAt: number, updatedAt?: number, updatedBy?: string, } | null ``` Example (ConvexHttpClient) [#example-convexhttpclient-1] ```typescript const note = await client.query("briefingNotes:get", { noteId: "n57..." }); ``` *** `briefingNotes:list` [#briefingnoteslist] **Scope:** query List briefing notes, ordered by `createdAt` desc. Optional topic filter. Args [#args-2] ```typescript { topic?: string, limit?: number, // default 20 (auto-clamped to 15 for fields=full) fields?: "lite" | "full", updatedSince?: number, // Unix ms } ``` **`fields="lite"` projection:** `{ _id, _creationTime, topic, title, participants, createdBy }` Returns [#returns-2] Array of full briefing note docs (default) or lite projections. Example (ConvexHttpClient) [#example-convexhttpclient-2] ```typescript const notes = await client.query("briefingNotes:list", { topic: "sprint-review", limit: 5, }); ``` Example (MCP tool) [#example-mcp-tool-1] ```json { "tool": "mcp__vantage-peers__list_briefing_notes", "args": { "topic": "sprint-review" } } ``` *** `briefingNotes:update` [#briefingnotesupdate] **Scope:** mutation Partial update of any mutable briefing note field. `callerOrchestrator` is **required** and must be the creator or `"system"`. Args [#args-3] ```typescript { noteId: Id<"briefingNotes">, callerOrchestrator: string, // REQUIRED — must be createdBy or "system" title?: string, topic?: string, participants?: string[], content?: string, decisions?: string[], linkedMemoryIds?: Id<"memories">[], } ``` Returns [#returns-3] `null` RBAC note [#rbac-note] Unlike most other mutations, `callerOrchestrator` is not optional here. Omitting it throws a validation error. This is intentional — briefing notes use deny-by-default update policy. Example (ConvexHttpClient) [#example-convexhttpclient-3] ```typescript await client.mutation("briefingNotes:update", { noteId: "n57...", callerOrchestrator: "pi", decisions: ["Defer DCR audit to Day 83", "Ship v2.4.0 now", "Review auth layer Day 84"], }); ``` *** `briefingNotes:deleteBriefingNote` [#briefingnotesdeletebriefingnote] **Scope:** mutation Hard delete a briefing note. Only the creator (`createdBy`) or `"system"` may delete. Args [#args-4] ```typescript { noteId: Id<"briefingNotes">, callerOrchestrator?: string, } ``` Returns [#returns-4] ```typescript { deleted: boolean } ``` Example (ConvexHttpClient) [#example-convexhttpclient-4] ```typescript const result = await client.mutation("briefingNotes:deleteBriefingNote", { noteId: "n57...", callerOrchestrator: "pi", }); ``` --- # diary — API Reference URL: /docs/api-reference/diary diary [#diary] **Source:** `convex/diary.ts` **Fn-paths:** 5 The diary module provides per-orchestrator daily session logs. Each entry is keyed by `(orchestrator, date)` — writing to the same date is an upsert. Diary entries support free-form content plus structured `highlights` and `blockers` arrays. *** `diary:write` [#diarywrite] **Scope:** mutation Upsert a diary entry. If an entry already exists for this `date + orchestrator` combination, it is updated in place. Args [#args] ```typescript { date: string, // ISO 8601 date string e.g. "2026-05-29" orchestrator: string, // orchestrator ID content: string, highlights?: string[], blockers?: string[], } ``` Returns [#returns] `Id<"diary">` — the created or updated entry ID. Example (ConvexHttpClient) [#example-convexhttpclient] ```typescript const entryId = await client.mutation("diary:write", { date: "2026-05-29", orchestrator: "sigma", content: "Completed M3 delivery. Wrote 41-fn-path API reference.", highlights: ["M3 shipped on time", "Full EN+FR docs"], blockers: [], }); ``` Example (MCP tool) [#example-mcp-tool] ```json { "tool": "mcp__vantage-peers__write_diary", "args": { "date": "2026-05-29", "orchestrator": "sigma", "content": "Completed M3 delivery.", "highlights": ["M3 shipped on time"] } } ``` *** `diary:get` [#diaryget] **Scope:** query Fetch a diary entry by date and orchestrator. Args [#args-1] ```typescript { date: string, orchestrator: string, } ``` Returns [#returns-1] ```typescript { _id: Id<"diary">, _creationTime: number, date: string, orchestrator: string, instanceId?: string, content: string, highlights?: string[], blockers?: string[], createdAt: number, } | null ``` Example (ConvexHttpClient) [#example-convexhttpclient-1] ```typescript const entry = await client.query("diary:get", { date: "2026-05-29", orchestrator: "sigma", }); ``` *** `diary:list` [#diarylist] **Scope:** query List diary entries by orchestrator, ordered by date desc. Args [#args-2] ```typescript { orchestrator?: string, // if omitted, returns all entries across all orchestrators limit?: number, // default 20 } ``` Returns [#returns-2] Array of diary entries. Example (ConvexHttpClient) [#example-convexhttpclient-2] ```typescript const entries = await client.query("diary:list", { orchestrator: "sigma", limit: 10, }); ``` Example (MCP tool) [#example-mcp-tool-1] ```json { "tool": "mcp__vantage-peers__list_diary", "args": { "orchestrator": "sigma", "limit": 7 } } ``` *** `diary:deleteDiary` [#diarydeletediary] **Scope:** mutation Hard delete a diary entry. Only the owner (`orchestrator`) or `"system"` may delete. Args [#args-3] ```typescript { diaryId: Id<"diary">, callerOrchestrator?: string, } ``` Returns [#returns-3] ```typescript { deleted: boolean } ``` RBAC note [#rbac-note] If `callerOrchestrator` is provided and does not match `entry.orchestrator`, the mutation throws. Example (ConvexHttpClient) [#example-convexhttpclient-3] ```typescript const result = await client.mutation("diary:deleteDiary", { diaryId: "d57...", callerOrchestrator: "sigma", }); ``` *** `diary:listByDateRange` [#diarylistbydaterange] **Scope:** query List diary entries between two dates (inclusive). Useful for weekly reviews or session replay. Args [#args-4] ```typescript { from: string, // ISO 8601 date string e.g. "2026-05-20" to: string, // ISO 8601 date string e.g. "2026-05-29" orchestrator?: string, } ``` Results are ordered by date ascending. Returns [#returns-4] Array of diary entries within the range. Example (ConvexHttpClient) [#example-convexhttpclient-4] ```typescript const week = await client.query("diary:listByDateRange", { from: "2026-05-20", to: "2026-05-29", orchestrator: "sigma", }); ``` Example (MCP tool) [#example-mcp-tool-2] ```json { "tool": "mcp__vantage-peers__list_diary_by_date_range", "args": { "from": "2026-05-20", "to": "2026-05-29", "orchestrator": "sigma" } } ``` --- # iframeEmbedSessions — API Reference URL: /docs/api-reference/iframe-embed-sessions iframeEmbedSessions [#iframeembedsessions] **Source:** `convex/iframeEmbedSessions.ts` **Fn-paths:** 4 **Added:** v2.4.0 (M3 deliverable — SEP-1865) The `iframeEmbedSessions` module manages authenticated session records for VantagePeers Gen UI iframe embeds. Each session represents an authenticated connection from a specific origin, carrying optional tenant and user context. Sessions expire automatically via the `expiresAt` field. **Design principles:** * `getSession` returns `null` for expired sessions — callers should treat them as non-existent * `revokeSession` is the security logout path — revoked sessions are immediately treated as non-existent by `getSession` * `touchSession` extends presence without changing `expiresAt` — it only updates `lastSeenAt` * Session IDs are client-generated strings — use `crypto.randomUUID()` or equivalent *** `iframeEmbedSessions:createSession` [#iframeembedsessionscreatesession] **Scope:** mutation Creates a new iframe embed session record. Args [#args] ```typescript { sessionId: string, // client-generated unique ID (e.g. crypto.randomUUID()) tenantId?: string, // multi-tenant routing context origin: string, // embedding origin, e.g. "https://app.example.com" userId?: string, // per-user context for the embed expiresAt: number, // Unix ms — when the session expires } ``` Returns [#returns] `Id<"iframeEmbedSessions">` — the Convex document ID for the new session. Example (ConvexHttpClient) [#example-convexhttpclient] ```typescript const docId = await client.mutation("iframeEmbedSessions:createSession", { sessionId: crypto.randomUUID(), origin: "https://dashboard.example.com", userId: "user_abc123", expiresAt: Date.now() + 30 * 60 * 1000, // 30 minutes }); ``` Example (MCP tool) [#example-mcp-tool] ```json { "tool": "mcp__vantage-peers__create_iframe_session", "args": { "sessionId": "550e8400-e29b-41d4-a716-446655440000", "origin": "https://dashboard.example.com", "userId": "user_abc123", "expiresAt": 1748556000000 } } ``` *** `iframeEmbedSessions:getSession` [#iframeembedsessionsgetsession] **Scope:** query Fetch a session by `sessionId`. Returns `null` for expired or revoked sessions. Args [#args-1] ```typescript { sessionId: string } ``` Returns [#returns-1] ```typescript { _id: Id<"iframeEmbedSessions">, _creationTime: number, sessionId: string, tenantId?: string, origin: string, userId?: string, createdAt: number, lastSeenAt: number, expiresAt: number, revoked: boolean, } | null ``` Returns `null` if: * Session does not exist * `session.expiresAt <= Date.now()` — expired * `session.revoked === true` — revoked Example (ConvexHttpClient) [#example-convexhttpclient-1] ```typescript const session = await client.query("iframeEmbedSessions:getSession", { sessionId: "550e8400-e29b-41d4-a716-446655440000", }); if (session === null) { // Session expired or revoked — redirect to login } ``` Rate limit / RBAC note [#rate-limit--rbac-note] No RBAC enforcement at the fn-path level — access control is the caller's responsibility. In the MCP server, `getSession` is called on every embed activity event to validate the session before processing. *** `iframeEmbedSessions:touchSession` [#iframeembedsessionstouchsession] **Scope:** mutation Updates `lastSeenAt` to the current time. Called on each embed activity event to maintain an accurate presence window. Does **not** extend `expiresAt`. Args [#args-2] ```typescript { sessionId: string } ``` Returns [#returns-2] `boolean` — `true` if the session was found and updated, `false` if not found or already revoked. Example (ConvexHttpClient) [#example-convexhttpclient-2] ```typescript const alive = await client.mutation("iframeEmbedSessions:touchSession", { sessionId: "550e8400-e29b-41d4-a716-446655440000", }); if (!alive) { // Session was revoked between the last check and this touch } ``` Example (MCP tool) [#example-mcp-tool-1] ```json { "tool": "mcp__vantage-peers__touch_iframe_session", "args": { "sessionId": "550e8400-e29b-41d4-a716-446655440000" } } ``` *** `iframeEmbedSessions:revokeSession` [#iframeembedsessionsrevokesession] **Scope:** mutation Marks a session as revoked. Revoked sessions are immediately treated as non-existent by `getSession`. Use for logout or security invalidation flows. Args [#args-3] ```typescript { sessionId: string } ``` Returns [#returns-3] `boolean` — `true` if the session was found and revoked, `false` if not found (already deleted or never created). Example (ConvexHttpClient) [#example-convexhttpclient-3] ```typescript const revoked = await client.mutation("iframeEmbedSessions:revokeSession", { sessionId: "550e8400-e29b-41d4-a716-446655440000", }); ``` Example (MCP tool) [#example-mcp-tool-2] ```json { "tool": "mcp__vantage-peers__revoke_iframe_session", "args": { "sessionId": "550e8400-e29b-41d4-a716-446655440000" } } ``` Security note [#security-note] `revokeSession` does not delete the session row — it sets `revoked: true`. The row is preserved for audit purposes. Cron-based cleanup of expired and revoked sessions can be added by deploying a scheduled function against `iframeEmbedSessions` — see `convex/crons.ts` for the pattern. --- # API Reference URL: /docs/api-reference API Reference [#api-reference] This section catalogues all **41 fn-paths** exposed by the VantagePeers Convex backend. These are the authoritative function signatures used by every consumer of the backend: the MCP server, the Hermes/Mu agent pattern, and any direct `ConvexHttpClient` consumer. Stability contract [#stability-contract] Fn-paths are a **stable contract**. Breaking changes — removed args, changed return shapes, renamed paths — are signalled via a SemVer major bump on the `vantage-peers-mcp` npm package. Additive changes (new optional args, new optional return fields) are non-breaking and may land in a minor release. Using fn-paths directly [#using-fn-paths-directly] Every fn-path can be called directly using `ConvexHttpClient` from any Node.js or browser environment: ```typescript import { ConvexHttpClient } from "convex/browser"; const client = new ConvexHttpClient("https://your-deployment.convex.cloud"); // Query (read, real-time, cached) const tasks = await client.query("tasks:list", { assignedTo: "sigma" }); // Mutation (write, transactional) const taskId = await client.mutation("tasks:create", { title: "Deploy to production", assignedTo: "sigma", priority: "high", status: "todo", createdBy: "pi", }); ``` The MCP tools are thin wrappers over these exact fn-paths. When debugging, you can always call the fn-path directly from the Convex dashboard **Functions** tab. Module index [#module-index] | Module | Fn-paths | Source | | ---------------------------------------------------------------- | -------- | ------------------------------- | | [tasks](/docs/api-reference/tasks) | 10 | `convex/tasks.ts` | | [messages](/docs/api-reference/messages) | 8 | `convex/messages.ts` | | [memories](/docs/api-reference/memories) | 4 | `convex/memories.ts` | | [briefingNotes](/docs/api-reference/briefing-notes) | 5 | `convex/briefingNotes.ts` | | [diary](/docs/api-reference/diary) | 5 | `convex/diary.ts` | | [missions](/docs/api-reference/missions) | 6 | `convex/missions.ts` | | [iframeEmbedSessions](/docs/api-reference/iframe-embed-sessions) | 4 | `convex/iframeEmbedSessions.ts` | **Total: 41 fn-paths** Common types [#common-types] These types appear across multiple modules. `creatorValidator` (orchestrator ID) [#creatorvalidator-orchestrator-id] A plain string — any orchestrator name is accepted. Common values: `"sigma"`, `"pi"`, `"tau"`, `"phi"`, `"system"`. No enum constraint — new orchestrators are registered dynamically via the profiles table. Priority enum [#priority-enum] `"urgent" | "high" | "medium" | "low"` Status aliases (tasks) [#status-aliases-tasks] The `status` arg on `tasks:list` and `tasks:listByMission` accepts: * A literal value: `"todo" | "in_progress" | "review" | "blocked" | "done"` * An alias: `"open"` (expands to `["todo","in_progress","review","blocked"]`) or `"active"` (expands to `["todo","in_progress"]`) * An array of literal values: `["todo", "in_progress"]` Status aliases (missions) [#status-aliases-missions] The `status` arg on `missions:list` accepts: * A literal value: `"brainstorm" | "plan" | "execute" | "validate" | "complete"` * An alias: `"open"` (expands to `["brainstorm","plan","execute","validate"]`) or `"active"` (expands to `["plan","execute"]`) Rate limits and RBAC [#rate-limits-and-rbac] VantagePeers does not enforce per-fn-path rate limits at the Convex layer. Rate limiting, if needed, should be applied at the MCP server or HTTP gateway layer. RBAC is enforced inside mutations via the `callerOrchestrator` argument pattern. When provided, the mutation verifies the caller is the creator or assignee of the resource. Passing `callerOrchestrator: "system"` bypasses RBAC checks — use only for server-to-server internal calls. --- # memories — API Reference URL: /docs/api-reference/memories memories [#memories] **Source:** `convex/memories.ts` **Fn-paths:** 4 The memories module is the core knowledge store. Every stored memory is automatically embedded via `text-embedding-3-small` (1536 dims) and indexed for semantic vector search. Memories support namespaces, types, relations, TTL expiry, and a `isLatest` flag for versioning. The RAG embedding is asynchronous — it is scheduled via `ctx.scheduler.runAfter(0, ...)` immediately after the `storeMemory` mutation completes. There is no sync wait; the embedding is available within a few seconds. *** `memories:storeMemory` [#memoriesstorememory] **Scope:** mutation Creates a memory row and schedules async RAG embedding. Args [#args] ```typescript { namespace: string, // e.g. "global", "sigma/feedback", "project/vp" type: MemoryType, // see type enum below content: string, createdBy: string, // orchestrator ID relations?: Array<{ targetId: Id<"memories">, type: RelationType, // "updates" | "references" | "contradicts" | "extends" }>, isLatest?: boolean, // default true server-side ttl?: string, // ISO 8601 datetime — auto-expires at this time episode?: { context: string, goal: string, action: string, outcome: string, insight: string, severity: "low" | "medium" | "high" | "critical", }, } ``` **`type` enum:** `"fact"` | `"decision"` | `"feedback"` | `"project"` | `"architecture"` | `"note"` | `"warning"` | `"procedure"` | `"episode"` | `"observation"` **`relations[].type` enum:** `"updates"` | `"references"` | `"contradicts"` | `"extends"` When a relation has `type: "updates"`, the target memory is marked `isLatest: false` and removed from future search results — it is superseded. Returns [#returns] `Id<"memories">` — the new memory ID. Side effects [#side-effects] 1. Inserts the memory row with `isLatest: true`. 2. For each `relations[].type === "updates"` entry: patches target to `isLatest: false` and schedules RAG supersede. 3. Schedules `internal.ragSync.addRagEntry` — embedding generated asynchronously. Example (ConvexHttpClient) [#example-convexhttpclient] ```typescript const memId = await client.mutation("memories:storeMemory", { namespace: "sigma/feedback", type: "feedback", content: "Rate limiter at the gateway is the correct approach — avoids Convex write amplification.", createdBy: "pi", }); ``` Example (MCP tool) [#example-mcp-tool] ```json { "tool": "mcp__vantage-peers__store_memory", "args": { "namespace": "sigma/feedback", "type": "feedback", "content": "Rate limiter at the gateway is the correct approach.", "createdBy": "pi" } } ``` *** `memories:getMemory` [#memoriesgetmemory] **Scope:** query Fetch a single memory by ID. Args [#args-1] ```typescript { memoryId: Id<"memories"> } ``` Returns [#returns-1] ```typescript { _id: Id<"memories">, _creationTime: number, namespace: string, type: MemoryType, content: string, createdBy: string, relations: Array<{ targetId: Id<"memories">, type: RelationType }>, isLatest: boolean, ttl?: string, episode?: { context: string, goal: string, action: string, outcome: string, insight: string, severity: "low" | "medium" | "high" | "critical", }, createdAt: number, updatedAt: number, } | null ``` Example (ConvexHttpClient) [#example-convexhttpclient-1] ```typescript const mem = await client.query("memories:getMemory", { memoryId: "m57...", }); ``` *** `memories:listMemories` [#memorieslistmemories] **Scope:** query List active memories by namespace, with optional type filter. Supports cursor-based pagination. Args [#args-2] ```typescript { namespace: string, type?: MemoryType, includeSuperseded?: boolean, // default false — only isLatest=true limit?: number, // default 50 paginationOpts?: { numItems: number, cursor: string | null, }, } ``` When `paginationOpts` is provided, the query uses `.paginate()` for cursor-based pagination. When omitted, uses `.take(limit)` and returns `continueCursor: null, isDone: true`. Returns [#returns-2] ```typescript { value: MemoryDoc[], continueCursor: string | null, isDone: boolean, } ``` Existing callers reading `.value` work unchanged regardless of whether `paginationOpts` was used. Example (ConvexHttpClient) [#example-convexhttpclient-2] ```typescript // First page const page1 = await client.query("memories:listMemories", { namespace: "sigma/feedback", paginationOpts: { numItems: 20, cursor: null }, }); // Next page if (!page1.isDone) { const page2 = await client.query("memories:listMemories", { namespace: "sigma/feedback", paginationOpts: { numItems: 20, cursor: page1.continueCursor }, }); } ``` Example (MCP tool) [#example-mcp-tool-1] ```json { "tool": "mcp__vantage-peers__list_memories", "args": { "namespace": "sigma/feedback", "type": "feedback" } } ``` *** `memories:softDeleteMemory` [#memoriessoftdeletememory] **Scope:** mutation Marks a memory as `isLatest: false`. The memory row is preserved (audit trail) but will no longer appear in `listMemories` or semantic search results. Args [#args-3] ```typescript { memoryId: Id<"memories"> } ``` Returns [#returns-3] `null` Side effects [#side-effects-1] 1. Patches the memory to `isLatest: false`. 2. Schedules `internal.ragSync.markRagEntrySuperseded` — removes from vector search asynchronously. Example (ConvexHttpClient) [#example-convexhttpclient-3] ```typescript await client.mutation("memories:softDeleteMemory", { memoryId: "m57...", }); ``` Example (MCP tool) [#example-mcp-tool-2] ```json { "tool": "mcp__vantage-peers__soft_delete_memory", "args": { "memoryId": "m57..." } } ``` --- # messages — API Reference URL: /docs/api-reference/messages messages [#messages] **Source:** `convex/messages.ts` **Fn-paths:** 8 The messages module provides cross-machine messaging between orchestrators. Each message creates one row in `messages` plus one `messageReceipts` row per recipient. Receipts track read state per recipient independently. **Broadcast resolution** is dynamic: the `"broadcast"` channel resolves to all orchestrators with a registered profile at send time — no hardcoded list. New orchestrators are automatically included after calling `update_profile`. *** `messages:sendMessage` [#messagessendmessage] **Scope:** mutation Send a message to one, many, or all orchestrators. Args [#args] ```typescript { from: string, // sender orchestrator ID fromInstanceId?: string, channel: string, // "broadcast" | "sigma" | "pi,phi" (comma-sep multi) content: string, sessionDay?: number, tenantId?: string, } ``` **Channel routing:** * `"broadcast"` — dynamic resolution: all profiles except sender * `"sigma"` — single recipient * `"pi,phi"` — comma-separated multi-recipient (no spaces required, trimmed) * `"sigma-vps-01"` — instance-level targeting (contains `"-"`) Returns [#returns] `Id<"messages">` — the new message ID. Example (ConvexHttpClient) [#example-convexhttpclient] ```typescript const msgId = await client.mutation("messages:sendMessage", { from: "pi", channel: "broadcast", content: "Deploying v2.4.0 in 5 minutes — hold writes.", }); ``` Example (MCP tool) [#example-mcp-tool] ```json { "tool": "mcp__vantage-peers__send_message", "args": { "from": "pi", "channel": "sigma", "content": "Task k57... ready for review." } } ``` *** `messages:checkNewMessages` [#messageschecknewmessages] **Scope:** query Get unread messages for a recipient. Returns messages with their receipt IDs (needed to mark as read). Args [#args-1] ```typescript { recipient: string, // orchestrator ID recipientInstanceId?: string, tenantId?: string, since?: number, // Unix ms — only receipts with _creationTime > since } ``` When `recipientInstanceId` is set, returns both instance-targeted messages and role-level messages for the same orchestrator (merged, deduplicated). When `tenantId` is provided, filters to that tenant only. When omitted, returns all messages (backward-compatible single-tenant mode). Returns [#returns-1] ```typescript Array<{ receiptId: Id<"messageReceipts">, messageId: Id<"messages">, from: string, fromInstanceId?: string, channel?: string, content: string, createdAt: number, }> ``` Example (ConvexHttpClient) [#example-convexhttpclient-1] ```typescript const messages = await client.query("messages:checkNewMessages", { recipient: "sigma", }); ``` Example (MCP tool) [#example-mcp-tool-1] ```json { "tool": "mcp__vantage-peers__check_messages", "args": { "recipient": "sigma" } } ``` *** `messages:markAsRead` [#messagesmarkasread] **Scope:** mutation Mark one or more receipts as read. Pass the `receiptId` values from `checkNewMessages`. Args [#args-2] ```typescript { receiptIds: Id<"messageReceipts">[] } ``` Returns [#returns-2] `number` — count of receipts actually marked (skips already-read receipts). Example (ConvexHttpClient) [#example-convexhttpclient-2] ```typescript const count = await client.mutation("messages:markAsRead", { receiptIds: ["r1...", "r2..."], }); ``` *** `messages:deleteMessage` [#messagesdeletemessage] **Scope:** mutation Delete a message and cascade-delete all its receipts. Args [#args-3] ```typescript { messageId: Id<"messages">, callerOrchestrator?: string, // RBAC: must be message.from or "system" } ``` Returns [#returns-3] ```typescript { deleted: boolean, receiptsDeleted: number } ``` RBAC note [#rbac-note] If `callerOrchestrator` is provided and does not match `message.from`, the mutation throws. Omit `callerOrchestrator` to bypass (admin / server-to-server use). Example (ConvexHttpClient) [#example-convexhttpclient-3] ```typescript const result = await client.mutation("messages:deleteMessage", { messageId: "m57...", callerOrchestrator: "pi", }); ``` *** `messages:listMessages` [#messageslistmessages] **Scope:** query Get messages for a session day or from a sender (history/replay). Args [#args-4] ```typescript { sessionDay?: number, from?: string, // orchestrator ID limit?: number, // default 100 } ``` When neither `sessionDay` nor `from` is provided, returns the most recent 100 messages across all senders. Returns [#returns-4] ```typescript Array<{ _id: Id<"messages">, _creationTime: number, from: string, fromInstanceId?: string, channel?: string, to?: string, content: string, sessionDay?: number, createdAt: number, }> ``` Example (ConvexHttpClient) [#example-convexhttpclient-4] ```typescript // Replay all messages from day 82 const history = await client.query("messages:listMessages", { sessionDay: 82, }); ``` *** `messages:getUnreadCount` [#messagesgetunreadcount] **Scope:** query Count unread receipts for a recipient role. Args [#args-5] ```typescript { orchestratorId: string } ``` Returns [#returns-5] `number` — count of unread receipts (capped at 500 in a single query). Example (ConvexHttpClient) [#example-convexhttpclient-5] ```typescript const count = await client.query("messages:getUnreadCount", { orchestratorId: "sigma", }); ``` Example (MCP tool) [#example-mcp-tool-2] ```json { "tool": "mcp__vantage-peers__get_unread_count", "args": { "orchestratorId": "sigma" } } ``` *** `messages:listBroadcastStatus` [#messageslistbroadcaststatus] **Scope:** query Show who has read a broadcast message and who has not. Useful for confirming all agents received a critical announcement. Args [#args-6] ```typescript { messageId: Id<"messages"> } ``` Returns [#returns-6] ```typescript { messageId: Id<"messages">, from: string, channel?: string, createdAt: number, receipts: Array<{ recipient: string, recipientInstanceId?: string, read: boolean, readAt?: number, }>, } ``` Example (ConvexHttpClient) [#example-convexhttpclient-6] ```typescript const status = await client.query("messages:listBroadcastStatus", { messageId: "m57...", }); const unread = status.receipts.filter(r => !r.read); ``` *** `messages:listByChannel` [#messageslistbychannel] **Scope:** query List recent messages for a specific channel, or all messages if channel is unspecified. Args [#args-7] ```typescript { channel?: string, limit?: number, // default 100 } ``` Returns [#returns-7] ```typescript Array<{ _id: Id<"messages">, _creationTime: number, from: string, fromInstanceId?: string, channel: string, content: string, sessionDay?: number, createdAt: number, }> ``` Example (ConvexHttpClient) [#example-convexhttpclient-7] ```typescript const recent = await client.query("messages:listByChannel", { channel: "broadcast", limit: 20, }); ``` --- # missions — API Reference URL: /docs/api-reference/missions missions [#missions] **Source:** `convex/missions.ts` **Fn-paths:** 6 Missions are the top-level planning unit. A mission groups tasks, defines a pilot, tracks progress (0–100), and moves through a lifecycle: `brainstorm → plan → execute → validate → complete`. Missions are automatically completed when all their linked tasks reach `status="done"`. *** `missions:create` [#missionscreate] **Scope:** mutation Insert a new mission. Args [#args] ```typescript { name: string, description?: string, project: string, status: "brainstorm" | "plan" | "execute" | "validate" | "complete", priority: "urgent" | "high" | "medium" | "low", pilot: string, // lead orchestrator ID agents: string[], // participating orchestrator IDs brief?: string, startDate?: number, // Unix ms targetDate?: number, // Unix ms progress?: number, // 0-100 createdBy: string, } ``` Returns [#returns] `Id<"missions">` — the new mission ID. Example (ConvexHttpClient) [#example-convexhttpclient] ```typescript const missionId = await client.mutation("missions:create", { name: "M3 iframe embed sessions", project: "vantage-peers", status: "plan", priority: "high", pilot: "sigma", agents: ["sigma", "pi"], createdBy: "pi", }); ``` Example (MCP tool) [#example-mcp-tool] ```json { "tool": "mcp__vantage-peers__create_mission", "args": { "name": "M3 iframe embed sessions", "project": "vantage-peers", "status": "plan", "priority": "high", "pilot": "sigma", "agents": ["sigma", "pi"], "createdBy": "pi" } } ``` *** `missions:get` [#missionsget] **Scope:** query Fetch a single mission by ID. Args [#args-1] ```typescript { missionId: Id<"missions"> } ``` Returns [#returns-1] ```typescript { _id: Id<"missions">, _creationTime: number, name: string, description?: string, project: string, status: "brainstorm" | "plan" | "execute" | "validate" | "complete", priority: "urgent" | "high" | "medium" | "low", pilot: string, agents: string[], brief?: string, startDate?: number, targetDate?: number, progress?: number, createdBy: string, createdAt: number, updatedAt: number, } | null ``` Example (ConvexHttpClient) [#example-convexhttpclient-1] ```typescript const mission = await client.query("missions:get", { missionId: "k57..." }); ``` *** `missions:list` [#missionslist] **Scope:** query List missions with optional filters. Supports lite projection and status aliases. Args [#args-2] ```typescript { project?: string, pilot?: string, status?: string | string[], // "brainstorm"|"open"|"active"|["plan","execute"] limit?: number, // default 50 (auto-clamped to 30 for fields=full) fields?: "lite" | "full", updatedSince?: number, // Unix ms } ``` **Status aliases:** * `"open"` → `["brainstorm","plan","execute","validate"]` * `"active"` → `["plan","execute"]` **`fields="lite"` projection:** `{ _id, _creationTime, name, status, pilot, priority, project }` Returns [#returns-2] Array of full mission docs (default) or lite projections. Example (ConvexHttpClient) [#example-convexhttpclient-2] ```typescript const missions = await client.query("missions:list", { project: "vantage-peers", status: "active", fields: "lite", }); ``` Example (MCP tool) [#example-mcp-tool-1] ```json { "tool": "mcp__vantage-peers__list_missions", "args": { "project": "vantage-peers", "status": "open" } } ``` Source file [#source-file] `convex/missions.ts:177` *** `missions:update` [#missionsupdate] **Scope:** mutation Partial update of any mutable mission field. All fields except `missionId` are optional. Args [#args-3] ```typescript { missionId: Id<"missions">, name?: string, description?: string, project?: string, status?: "brainstorm" | "plan" | "execute" | "validate" | "complete", priority?: "urgent" | "high" | "medium" | "low", pilot?: string, agents?: string[], brief?: string, startDate?: number, targetDate?: number, progress?: number, } ``` Returns [#returns-3] `null` Example (ConvexHttpClient) [#example-convexhttpclient-3] ```typescript await client.mutation("missions:update", { missionId: "k57...", status: "execute", progress: 40, }); ``` *** `missions:updateStatus` [#missionsupdatestatus] **Scope:** mutation Shortcut: sets `status` and `updatedAt=now`. Args [#args-4] ```typescript { missionId: Id<"missions">, status: "brainstorm" | "plan" | "execute" | "validate" | "complete", } ``` Returns [#returns-4] `null` Example (ConvexHttpClient) [#example-convexhttpclient-4] ```typescript await client.mutation("missions:updateStatus", { missionId: "k57...", status: "validate", }); ``` Example (MCP tool) [#example-mcp-tool-2] ```json { "tool": "mcp__vantage-peers__update_mission_status", "args": { "missionId": "k57...", "status": "validate" } } ``` *** `missions:updateProgress` [#missionsupdateprogress] **Scope:** mutation Shortcut: sets `progress` (0–100) and `updatedAt=now`. Args [#args-5] ```typescript { missionId: Id<"missions">, progress: number, // 0-100 } ``` Returns [#returns-5] `null` Example (ConvexHttpClient) [#example-convexhttpclient-5] ```typescript await client.mutation("missions:updateProgress", { missionId: "k57...", progress: 75, }); ``` Example (MCP tool) [#example-mcp-tool-3] ```json { "tool": "mcp__vantage-peers__update_mission_progress", "args": { "missionId": "k57...", "progress": 75 } } ``` --- # tasks — API Reference URL: /docs/api-reference/tasks tasks [#tasks] **Source:** `convex/tasks.ts` **Fn-paths:** 10 The tasks module manages the shared task board. Tasks have a lifecycle (`todo → in_progress → review → done`), an assignee, a priority, and optional mission linkage. Completing a task with a title matching `#NNN` auto-links the GitHub issue and may trigger IRP auto-comments. *** `tasks:create` [#taskscreate] **Scope:** mutation Creates a new task. Args [#args] ```typescript { title: string, description?: string, project?: string, tags?: string[], assignedTo: string, // orchestrator ID assignedToInstance?: string, priority: "urgent" | "high" | "medium" | "low", status: "todo" | "in_progress" | "review" | "blocked" | "done", dependsOn?: Id<"tasks">[], missionId?: Id<"missions">, estimatedMinutes?: number, dueDate?: number, // Unix ms createdBy: string, // orchestrator ID } ``` Returns [#returns] `Id<"tasks">` — the new task ID. Example (ConvexHttpClient) [#example-convexhttpclient] ```typescript const taskId = await client.mutation("tasks:create", { title: "Implement rate limiting", assignedTo: "sigma", priority: "high", status: "todo", createdBy: "pi", project: "vantage-peers", }); ``` Example (MCP tool) [#example-mcp-tool] ```json { "tool": "mcp__vantage-peers__create_task", "args": { "title": "Implement rate limiting", "assignedTo": "sigma", "priority": "high", "status": "todo", "createdBy": "pi" } } ``` *** `tasks:get` [#tasksget] **Scope:** query Fetch a single task by ID. Args [#args-1] ```typescript { taskId: Id<"tasks"> } ``` Returns [#returns-1] Full task doc or `null`. ```typescript { _id: Id<"tasks">, _creationTime: number, title: string, description?: string, project?: string, tags?: string[], assignedTo: string, priority: "urgent" | "high" | "medium" | "low", status: "todo" | "in_progress" | "review" | "blocked" | "done", completionNote?: string, assignedToInstance?: string, claimedByInstance?: string, dependsOn?: Id<"tasks">[], missionId?: Id<"missions">, estimatedMinutes?: number, actualMinutes?: number, startedAt?: number, completedAt?: number, dueDate?: number, createdBy: string, createdAt: number, updatedAt: number, } | null ``` Example (ConvexHttpClient) [#example-convexhttpclient-1] ```typescript const task = await client.query("tasks:get", { taskId: "j57..." }); ``` *** `tasks:list` [#taskslist] **Scope:** query List tasks with optional filters. Supports lite projection and status aliases. Args [#args-2] ```typescript { assignedTo?: string, assignedToInstance?: string, status?: string | string[], // "todo"|"open"|"active"|["todo","review"] project?: string, limit?: number, // default 50 (auto-clamped to 30 for fields=full) fields?: "lite" | "full", // default "full" createdBy?: string, updatedSince?: number, // Unix ms — filter by updatedAt } ``` **Status aliases:** * `"open"` → `["todo","in_progress","review","blocked"]` * `"active"` → `["todo","in_progress"]` **`fields="lite"` projection:** `{ _id, _creationTime, title, status, priority, assignedTo, missionId? }` Returns [#returns-2] Array of full task docs (default) or array of lite projections. Example (ConvexHttpClient) [#example-convexhttpclient-2] ```typescript // All open tasks for sigma, compact const tasks = await client.query("tasks:list", { assignedTo: "sigma", status: "open", fields: "lite", }); ``` Example (MCP tool) [#example-mcp-tool-1] ```json { "tool": "mcp__vantage-peers__list_tasks", "args": { "assignedTo": "sigma", "status": "open" } } ``` Source file [#source-file] `convex/tasks.ts:223` *** `tasks:update` [#tasksupdate] **Scope:** mutation Partial update of any mutable task field. All fields except `taskId` are optional. Args [#args-3] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, // RBAC: must be creator or assignee title?: string, description?: string, project?: string, tags?: string[], assignedTo?: string, priority?: "urgent" | "high" | "medium" | "low", status?: "todo" | "in_progress" | "review" | "blocked" | "done", missionId?: Id<"missions">, estimatedMinutes?: number, actualMinutes?: number, startedAt?: number, completedAt?: number, dueDate?: number, dependsOn?: Id<"tasks">[], completionNote?: string, assignedToInstance?: string, } ``` Returns [#returns-3] `null` RBAC note [#rbac-note] When `callerOrchestrator` is provided, the mutation throws if the caller is neither the creator (`createdBy`) nor the assignee (`assignedTo`). Pass `callerOrchestrator: "system"` to bypass. Example (ConvexHttpClient) [#example-convexhttpclient-3] ```typescript await client.mutation("tasks:update", { taskId: "j57...", status: "review", callerOrchestrator: "sigma", }); ``` *** `tasks:complete` [#taskscomplete] **Scope:** mutation Shortcut to mark a task done. Requires a non-empty `completionNote`. Auto-links GitHub issues and auto-completes parent missions when all tasks finish. Args [#args-4] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, completionNote?: string, // REQUIRED at runtime — empty string throws } ``` Returns [#returns-4] `null` Side effects [#side-effects] 1. Sets `status="done"`, `completedAt=now`, computes `actualMinutes` from `startedAt`. 2. If title contains `#NNN` and a GitHub repo mapping exists for the project, links the task to the issue and optionally updates issue status if `completionNote` contains "fix"/"fixed" or a commit SHA. 3. If title matches `[#NNN] TN — ` pattern, schedules IRP auto-comments on steps T6, T8, T11. 4. If all tasks in the parent mission are done, sets mission `status="complete"`. Example (MCP tool) [#example-mcp-tool-2] ```json { "tool": "mcp__vantage-peers__complete_task", "args": { "taskId": "j57...", "callerOrchestrator": "sigma", "completionNote": "Rate limiter implemented at gateway layer — 429 confirmed in load test. PR #412." } } ``` Source file [#source-file-1] `convex/tasks.ts:430` *** `tasks:start` [#tasksstart] **Scope:** mutation Sets `status="in_progress"` and records `startedAt`. Blocks if the caller already has another unclosed in\_progress task. Args [#args-5] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, } ``` Returns [#returns-5] `null` Concurrency note [#concurrency-note] If `callerOrchestrator` is provided and that orchestrator already has an in\_progress task (different ID), the mutation throws: `"Cannot start task: you have an unclosed in_progress task..."`. Complete the existing task first. Example (ConvexHttpClient) [#example-convexhttpclient-4] ```typescript await client.mutation("tasks:start", { taskId: "j57...", callerOrchestrator: "sigma", }); ``` *** `tasks:checkout` [#taskscheckout] **Scope:** mutation Atomically claims a task. Only succeeds if `status="todo"`. Designed for multi-instance concurrency — two agents calling `checkout` simultaneously on the same task will only one succeed. Args [#args-6] ```typescript { taskId: Id<"tasks">, callerOrchestrator: string, // REQUIRED callerInstance?: string, } ``` Returns [#returns-6] ```typescript { claimed: boolean, reason?: string } ``` `claimed: true` means the task is now `in_progress` and owned by the caller. `claimed: false` includes a reason string explaining why (already taken, not found, etc.). Example (ConvexHttpClient) [#example-convexhttpclient-5] ```typescript const result = await client.mutation("tasks:checkout", { taskId: "j57...", callerOrchestrator: "sigma", callerInstance: "sigma-vps-01", }); if (result.claimed) { // proceed with the task } ``` *** `tasks:deleteTask` [#tasksdeletetask] **Scope:** mutation Hard delete. Only the creator (`createdBy`) or `"system"` may delete. Args [#args-7] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, } ``` Returns [#returns-7] ```typescript { deleted: boolean } ``` RBAC note [#rbac-note-1] Throws if `callerOrchestrator` is provided and does not match `task.createdBy`. Example (ConvexHttpClient) [#example-convexhttpclient-6] ```typescript const result = await client.mutation("tasks:deleteTask", { taskId: "j57...", callerOrchestrator: "pi", }); ``` *** `tasks:listByMission` [#taskslistbymission] **Scope:** query List all tasks belonging to a specific mission. Supports the same `fields` and `status` options as `tasks:list`. Args [#args-8] ```typescript { missionId: Id<"missions">, status?: string | string[], limit?: number, fields?: "lite" | "full", createdBy?: string, updatedSince?: number, } ``` Returns [#returns-8] Array of full task docs or lite projections. Example (ConvexHttpClient) [#example-convexhttpclient-7] ```typescript const tasks = await client.query("tasks:listByMission", { missionId: "k57...", status: "open", fields: "lite", }); ``` Source file [#source-file-2] `convex/tasks.ts:768` *** `tasks:listOverdue` [#taskslistoverdue] **Scope:** query Return tasks that are past their `dueDate` and not yet done. Args [#args-9] ```typescript { assignedTo?: string, limit?: number, // default 50 } ``` Returns [#returns-9] Array of full task docs where `status != "done"` and `dueDate < now`. Example (ConvexHttpClient) [#example-convexhttpclient-8] ```typescript const overdue = await client.query("tasks:listOverdue", { assignedTo: "sigma", }); ``` Source file [#source-file-3] `convex/tasks.ts:838` --- # Bearer Tokens URL: /docs/auth/bearer-tokens Bearer Tokens [#bearer-tokens] Bearer tokens are the primary credential for all VantagePeers MCP server calls. This page covers the token format, security model, validation path, and how to rotate or revoke tokens. Token Format [#token-format] A VP Bearer token is a **64-character lowercase hexadecimal string** generated from 32 cryptographically random bytes: ``` a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890 ``` Generation: ```ts const rawBytes = new Uint8Array(32) crypto.getRandomValues(rawBytes) const bearer = Array.from(rawBytes).map(b => b.toString(16).padStart(2, '0')).join('') ``` Storage Model [#storage-model] The raw Bearer token is **never stored** in Convex. Only its SHA-256 hash is persisted. The token is returned to the caller exactly once at issuance. If lost, it cannot be recovered — revoke and reissue. At issuance: 1. 32 random bytes are generated. 2. `sha256(raw_token)` is computed as a 64-char hex string. 3. The hash is written to either `userBearerTokens.tokenHash` (Clerk flow) or `oauth_access_tokens.tokenHash` (OAuth flow). 4. The raw token is returned in the HTTP response body and discarded server-side. Token Lifetime [#token-lifetime] | Token type | Default TTL | Configurable? | | | ------------------------- | ----------------------------------------- | ------------------------------------- | -------------------------------------------- | | Clerk-issued (user-grade) | `TTL_7_DAYS` (7 × 24 × 60 × 60 × 1000 ms) | No — hardcoded in `credentials.ts` | // allow-time-estimate: factual TTL constant | | OAuth access token | Configurable by admin | Yes — set at `createAccessToken` call | | | `BEARER_SECRET_MASTER` | No expiry | Rotated manually via env var update | | Validation Path [#validation-path] When the MCP server receives a request with `Authorization: Bearer `: 1. The raw token value is extracted from the header. 2. `sha256(token)` is computed. 3. The hash is looked up in Convex via the `by_token_hash` index on `userBearerTokens` (for Clerk-issued tokens) or `by_tokenHash` on `oauth_access_tokens` (for OAuth tokens). 4. If found: check `revoked` flag and `expiresAt` timestamp. 5. If all checks pass: request is authorized. Source reference: `mcp-server/src/auth.ts:275` — Bearer sha256 lookup via `by_token_hash` index. The `BEARER_SECRET_MASTER` token follows a simpler path: constant-time string comparison against the env var value (no database lookup). Header Format [#header-format] All MCP server requests must include: ``` Authorization: Bearer <64-char-hex-token> ``` Example: ```http GET /health HTTP/1.1 Host: your-deployment.railway.app Authorization: Bearer a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890 ``` For Claude Code `.mcp.json` configuration: ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://your-deployment.railway.app/mcp", "headers": { "Authorization": "Bearer your-bearer-secret" } } } } ``` BEARER_SECRET_MASTER [#bearer_secret_master] `BEARER_SECRET_MASTER` is the admin master token. It is: * Set as an environment variable on the MCP server (Railway env vars or equivalent) * Used for admin operations: OAuth client provisioning, token issuance gating, Convex admin mutations * Validated via constant-time comparison (no database lookup) to prevent timing attacks * Required for all `oauth.ts` admin mutations (`createClient`, `listClients`, `deleteClient`, `seedDefaultProfiles`) `BEARER_SECRET_MASTER` grants full admin access. Never expose it in client-side code, browser extensions, or version control. Use the Clerk JWT exchange flow to issue scoped user-grade tokens instead. Rotation procedure for BEARER_SECRET_MASTER [#rotation-procedure-for-bearer_secret_master] 1. Generate a new secret: `openssl rand -hex 32` 2. Update `BEARER_SECRET_MASTER` in Railway environment variables (or your MCP server host). 3. Restart the MCP server process to pick up the new value. 4. Update any service accounts or automation that use the master token. 5. The old value is immediately invalid once the env var is updated and the process restarted. Revoking a Clerk-Issued Token [#revoking-a-clerk-issued-token] There is no API endpoint to revoke individual Clerk-issued tokens in V0.0.2. To revoke: 1. Contact your VP admin or use the Convex dashboard to directly update `userBearerTokens.revoked = true` for the matching `tokenHash`. 2. The token will fail validation on the next request once `revoked: true`. A revocation API endpoint is planned for V0.0.3. Revoking an OAuth Token [#revoking-an-oauth-token] OAuth tokens are revoked via the `deleteClient` mutation in `oauth.ts`, which sets `revokedAt` on both the client record and all associated access/refresh tokens: ```ts // Admin call — requires BEARER_SECRET_MASTER oauth.deleteClient({ callerToken: masterToken, clientId: 'your-client-id' }) ``` This revokes the client and all its tokens atomically. The client must re-register via DCR to get new credentials. Token Issuance Sources [#token-issuance-sources] | Source | Table | Index | | ------------------------------------- | ------------------------- | --------------- | | Clerk JWT exchange (`credentials.ts`) | `userBearerTokens` | `by_token_hash` | | OAuth DCR + token grant (`oauth.ts`) | `oauth_access_tokens` | `by_tokenHash` | | Master token | Environment variable only | N/A | --- # Clerk JWT Exchange URL: /docs/auth/clerk-flow Clerk JWT Exchange [#clerk-jwt-exchange] The Clerk JWT exchange flow issues a user-grade Bearer token to a browser extension or webapp. It is the primary auth path for VP integrations that run in the context of a logged-in Clerk user. This flow ships in V0.0.2 (PR #546). Use Case [#use-case] A browser extension or webapp that: * Has authenticated the user via Clerk (standard Clerk SDK or hosted sign-in page) * Needs to call the VP MCP server on behalf of that user * Does not want to expose `BEARER_SECRET_MASTER` to the browser The extension exchanges the short-lived Clerk JWT for a 7-day VP Bearer token. All subsequent MCP calls use the VP Bearer — the Clerk JWT is never sent to the MCP server. Flow Diagram [#flow-diagram] ``` Extension vantagepeers.com Convex backend ──────── ──────────────── ────────────── │ │ │ │ User opens auth tab │ │ │─────────────────────────────>│ │ │ │ │ │ GET /auth/extension-callback│ │ │<─────────────────────────────│ │ │ │ │ │ Clerk sign-in / already │ │ │ authenticated (Clerk JWT) │ │ │ │ │ │ POST /issueBearerFromClerk │ │ │ {clerkJwt, extId, extVersion│ │ │─────────────────────────────────────────────────────────>│ │ │ 1. Verify JWT (JWKS) │ │ │ 2. Check extId whitelist │ │ │ 3. Rate-limit check │ │ │ 4. Resolve workspace │ │ │ 5. Issue Bearer (32 bytes)│ │ │ 6. Store sha256 only │ │ │ 7. Audit log │ │<─────────────────────────────────────────────────────────│ │ {workspaceId, bearer, │ │ │ expiresAt, userName, │ │ │ workspaceName} │ │ │ │ │ │ Extension stores Bearer │ │ │ MCP calls use Bearer header │ │ ``` Prerequisites [#prerequisites] Before calling this endpoint: 1. Configure the Clerk JWT template named `convex` in your Clerk dashboard (Clerk → JWT Templates → New template → Convex). This ensures the token audience matches what VP expects. 2. Set `CLERK_JWT_ISSUER_DOMAIN` in Convex to your Clerk Frontend API domain (e.g. `clerk.yourdomain.com`). 3. Add your extension's Chrome extension ID to `VP_ALLOWED_EXT_IDS` in Convex (comma-separated list). See [Authentication Overview — Prerequisites](/docs/auth/index) for the full env var checklist. Request [#request] ``` POST {convexUrl}/issueBearerFromClerk Content-Type: application/json Origin: https://vantagepeers.com (or whitelisted extension origin) ``` Body [#body] ```json { "clerkJwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "extId": "mhfnnhkmnclmnnllhmoidkflgpkogjpe", "extVersion": "1.2.0" } ``` | Field | Type | Required | Description | | ------------ | ------ | -------- | ----------------------------------------------------- | | `clerkJwt` | string | Yes | JWT issued by Clerk for the `convex` template | | `extId` | string | Yes | Chrome extension ID — must be in `VP_ALLOWED_EXT_IDS` | | `extVersion` | string | No | Extension version string — recorded in audit log only | Response [#response] 200 OK — Success [#200-ok--success] ```json { "workspaceId": "user_2abc123def456", "bearer": "a1b2c3d4e5f6...64-char-hex-string", "expiresAt": 1749081600000, "userName": "cedric", "workspaceName": "cedric" } ``` | Field | Type | Description | | --------------- | ------ | ------------------------------------------------------------------ | | `workspaceId` | string | Stable Clerk user ID — use as namespace prefix | | `bearer` | string | Raw 64-char hex Bearer token. **Returned once, never again.** | | `expiresAt` | number | Unix ms timestamp when the token expires (7 days from issuance) | | `userName` | string | Derived from Clerk claims (name, email prefix, or `user-`) | | `workspaceName` | string | Same as `userName` in V0.0.2; will be workspace-aware in V0.0.3 | Store the `bearer` value immediately and securely (e.g. Chrome extension `chrome.storage.local`). It is returned exactly once. The VP backend stores only the SHA-256 hash — there is no recovery endpoint. Error Responses [#error-responses] | Status | Error | Cause | | ------ | ------------------------------------------------------- | ---------------------------------------------------- | | 400 | `Missing required field: clerkJwt` | Body missing `clerkJwt` | | 400 | `Missing required field: extId` | Body missing `extId` | | 401 | `Invalid Clerk JWT` | JWT expired, bad signature, or issuer mismatch | | 403 | `Extension not authorized` | `extId` not in `VP_ALLOWED_EXT_IDS` | | 429 | `Rate limit exceeded. Try again in 1 minute.` | More than 5 requests per minute from this Clerk user | | 500 | `Server misconfigured: CLERK_JWT_ISSUER_DOMAIN not set` | Missing env var on backend | Rate Limit [#rate-limit] 5 requests per minute per Clerk user ID. The `Retry-After: 60` header is included in 429 responses. Audit Log Fields [#audit-log-fields] Every successful issuance writes to `credentialsAuditLog`: | Field | Value | | ------------- | ----------------------------------------- | | `clerkUserId` | JWT `sub` claim | | `workspaceId` | Resolved workspace ID | | `extId` | Submitted extension ID | | `extVersion` | Submitted extension version (if provided) | | `issuedAt` | Unix ms timestamp | | `ip` | First value from `x-forwarded-for` header | | `userAgent` | Request `User-Agent` header | Environment Variables [#environment-variables] | Variable | Where to set | Description | | ------------------------- | ---------------- | ------------------------------------------------- | | `CLERK_JWT_ISSUER_DOMAIN` | Convex dashboard | Your Clerk Frontend API domain | | `VP_ALLOWED_EXT_IDS` | Convex dashboard | Comma-separated list of whitelisted extension IDs | Using the Token [#using-the-token] Once you have the `bearer` value, include it in the `Authorization` header for all MCP server calls: ``` Authorization: Bearer a1b2c3d4e5f6...64-char-hex-string ``` See [Bearer Tokens](/docs/auth/bearer-tokens) for the full validation path, rotation procedure, and revocation. --- # Authentication Overview URL: /docs/auth Authentication Overview [#authentication-overview] VantagePeers supports three distinct authentication flows. Each is designed for a different consumer context. Choosing the right one depends on how your client connects and who is authenticating. The Three Flows [#the-three-flows] | Flow | Use case | Token type | Lifetime | | ------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------ | ------------ | | **Clerk JWT exchange** | Browser extension / webapp acting on behalf of a logged-in user | User-grade Bearer | 7 days | | **Direct Bearer token** | MCP server clients, Claude Code plugins, CI scripts | Bearer (BEARER\_SECRET\_MASTER or client-issued) | Configurable | | **OAuth Dynamic Client Registration (DCR)** | MCP client SDKs self-registering (Claude.ai, Claude Desktop) | OAuth access token | Configurable | Decision Table — Which Flow Should I Use? [#decision-table--which-flow-should-i-use] | Situation | Recommended flow | | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | You are building a browser extension that authenticates users via Clerk | [Clerk JWT exchange](/docs/auth/clerk-flow) | | You are configuring Claude Code `.mcp.json` with a static bearer secret | [Bearer tokens](/docs/auth/bearer-tokens) | | You are building a Railway-hosted VP server and want Claude.ai web to connect | [OAuth DCR](/docs/auth/oauth-dcr) | | You are an admin provisioning tokens for an automated service account | [Bearer tokens](/docs/auth/bearer-tokens) — use `BEARER_SECRET_MASTER` | | You are a self-hosted VP operator provisioning a new MCP client | [OAuth DCR](/docs/auth/oauth-dcr) | Security Model [#security-model] VantagePeers stores **only the SHA-256 hash** of every Bearer token and OAuth secret. The raw token is returned exactly once at issuance and is never re-derivable from the database. If you lose a token, revoke it and issue a new one. Hash-only storage [#hash-only-storage] * All Bearer tokens are 32-byte cryptographically random values (64-char hex). * At issuance, only `sha256(token)` is written to Convex. * Validation: the incoming `Authorization: Bearer ` header value is hashed and matched against the `by_token_hash` index on `userBearerTokens` (for Clerk-issued tokens) or `oauth_access_tokens` (for OAuth tokens). Rate limits [#rate-limits] | Endpoint | Limit | | ---------------------------- | -------------------------------------------------------------- | | `POST /issueBearerFromClerk` | 5 requests per minute per Clerk user | | `POST /oauth/register` | No limit (public; client-id collision is the natural throttle) | | `POST /oauth/token` | Standard OAuth — no explicit VP-side limit | Audit logs [#audit-logs] The Clerk JWT exchange flow writes an audit record to `credentialsAuditLog` for every successful issuance. Fields recorded: `clerkUserId`, `workspaceId`, `extId`, `extVersion`, `issuedAt`, source IP, `User-Agent`. Prerequisites [#prerequisites] Before using any auth flow, confirm: 1. Your Convex deployment is running and accessible. 2. The relevant environment variables are set in the Convex dashboard (Settings → Environment Variables): | Variable | Required for | | ------------------------- | -------------------------------------------------- | | `CLERK_JWT_ISSUER_DOMAIN` | Clerk JWT exchange | | `VP_ALLOWED_EXT_IDS` | Clerk JWT exchange (comma-separated extension IDs) | | `BEARER_SECRET_MASTER` | Direct Bearer auth + OAuth admin operations | 3. For self-hosted deployments, cross-reference the full environment variable matrix at [/docs/self-host/env-vars](/docs/getting-started/index). Explore Each Flow [#explore-each-flow] --- # OAuth Dynamic Client Registration URL: /docs/auth/oauth-dcr OAuth Dynamic Client Registration [#oauth-dynamic-client-registration] VantagePeers implements OAuth 2.0 Dynamic Client Registration (DCR) for MCP clients — Claude.ai web, Claude Desktop, and custom MCP SDK consumers. DCR allows a client to self-register and obtain credentials without admin intervention for the default `client-generic` scope profile. Use Case [#use-case] | Scenario | Recommended | | -------------------------------------------------------- | ----------------------------------------------------- | | Claude.ai web connecting to a self-hosted VP HTTP server | Yes — DCR is built into the Claude.ai MCP integration | | Claude Desktop connecting via HTTP transport | Yes — use DCR for credential-free setup | | Custom MCP SDK client with scoped access | Yes | | Admin service account requiring full access | No — use `BEARER_SECRET_MASTER` directly | Scope Profiles [#scope-profiles] All tokens in VP carry a **scope profile** that controls what the token holder can do. Scope profiles are defined in `oauth_scope_profiles` in Convex. | Profile | Access level | Who gets it | | ---------------- | ----------------------------------------------- | ------------------------------------------------------------ | | `master` | Full admin — all namespaces, all from-addresses | Env var only (`BEARER_SECRET_MASTER`). Never issued via DCR. | | `client-generic` | Deny-by-default template | All public DCR self-registrations | | Custom profiles | Admin-configured | Assigned by admin post-registration | Public DCR self-registration always yields `client-generic` scope. This profile has **empty** `fromAllowList`, `namespaceReadPrefixes`, and `namespaceWritePrefixes` by default. The client can connect and authenticate, but cannot read or write any namespaces until an admin elevates the scope profile. This is intentional — deny-by-default prevents a freshly registered client from accessing production data. **Master scope is blocked at the Convex layer for DCR.** Any self-registration attempt with `scopeProfile="master"` is rejected with `ScopeViolation`. This is enforced in `oauth.ts:registerPublicClient` as defense-in-depth — even if the HTTP layer is bypassed, a direct Convex call cannot yield master scope via DCR. Flow [#flow] **Client calls POST /oauth/register** The client submits its metadata to the DCR endpoint. No authentication required for public registration. ```http POST https://your-deployment.railway.app/oauth/register Content-Type: application/json { "client_name": "cedar-trinity-agent", "redirect_uris": ["https://your-app.com/oauth/callback"], "grant_types": ["client_credentials"], "token_endpoint_auth_method": "client_secret_post" } ``` The server generates a `client_id` and `client_secret` (32-byte random hex), stores the SHA-256 hash of the secret, and returns the raw secret once. **Server responds with credentials** ```json { "client_id": "vp_client_a1b2c3d4", "client_secret": "e5f6g7h8...64-char-hex", "client_name": "cedar-trinity-agent", "redirect_uris": ["https://your-app.com/oauth/callback"], "scope_profile": "client-generic", "token_endpoint": "https://your-deployment.railway.app/oauth/token" } ``` Store `client_secret` immediately. It is returned once and never derivable from the database. **Client requests an access token** ```http POST https://your-deployment.railway.app/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=client_credentials &client_id=vp_client_a1b2c3d4 &client_secret=e5f6g7h8...64-char-hex ``` The server validates the secret hash, checks the client is not revoked, and issues an access token scoped to the client's profile. **Client uses the access token** ```http GET /health HTTP/1.1 Host: your-deployment.railway.app Authorization: Bearer ``` All subsequent MCP requests use this token. The token is validated via `by_tokenHash` index on `oauth_access_tokens`, checking `revokedAt` and `expiresAt`. Admin: Elevating a Client's Scope [#admin-elevating-a-clients-scope] After a client self-registers with `client-generic`, an admin can elevate its scope profile to grant actual access: ```ts // Requires BEARER_SECRET_MASTER await convex.mutation(api.oauth.createClient, { callerToken: process.env.BEARER_SECRET_MASTER, clientId: 'vp_client_a1b2c3d4', clientSecretHash: sha256('the-client-secret'), name: 'cedar-trinity-agent', redirectUris: ['https://your-app.com/oauth/callback'], scopeProfile: 'your-custom-profile', // must exist in oauth_scope_profiles }) ``` Or update the scope profile directly in the Convex dashboard. Admin: Creating a Custom Scope Profile [#admin-creating-a-custom-scope-profile] ```ts // Seed default profiles (master, marie-iris-rh, client-generic) await convex.mutation(api.oauth.seedDefaultProfiles, { callerToken: process.env.BEARER_SECRET_MASTER, }) // Then insert a custom profile via Convex dashboard or admin mutation ``` A scope profile shape: ```ts { profileId: 'cedar-agent', description: 'Cedar Trinity agent — read/write project/cedar namespace', fromAllowList: ['cedar'], // allowed send_message from-names namespaceReadPrefixes: ['project/cedar', 'global'], namespaceWritePrefixes: ['project/cedar'], } ``` Revoking a Client [#revoking-a-client] Admin-only. Revokes the client record and all associated access and refresh tokens atomically: ```ts await convex.mutation(api.oauth.deleteClient, { callerToken: process.env.BEARER_SECRET_MASTER, clientId: 'vp_client_a1b2c3d4', }) // Returns: { revokedClient: true, revokedTokens: N, revokedRefresh: N } ``` The client must re-register via DCR to reconnect. Environment Variables [#environment-variables] | Variable | Where to set | Required for | | ---------------------- | ---------------------- | -------------------------- | | `BEARER_SECRET_MASTER` | MCP server environment | All admin OAuth operations | See [Bearer Tokens](/docs/auth/bearer-tokens) for the master token lifecycle and rotation procedure. Claude.ai Web Integration [#claudeai-web-integration] Claude.ai web supports MCP servers via OAuth 2.1 with DCR natively. Once your Railway MCP server is running: 1. Go to claude.ai → Settings → Integrations → Custom MCP servers. 2. Paste your Railway URL (e.g. `https://vantage-peers-abc123.railway.app`). 3. Claude.ai auto-discovers the DCR endpoint and registers itself. 4. Authorize the connection. No bearer token or plugin install required for this flow. --- # Fix Patterns KB URL: /docs/capabilities/fix-patterns Fix Patterns KB [#fix-patterns-kb] The Fix Patterns knowledge base documents bugs, their root causes, what was tried (including failures), and what ultimately fixed the issue. Agents search this **before** attempting any fix to avoid repeating past mistakes. How It Works [#how-it-works] ``` Agent encounters bug │ ▼ search_fix_patterns("error message or symptom") │ ▼ Found match? ──Yes──▶ Apply validated fix │ No ▼ Fix the bug manually │ ▼ create_fix_pattern + add_fix_attempt ``` Schema [#schema] fixPatterns [#fixpatterns] | Field | Type | Description | | ---------------- | -------------------------------- | -------------------------------------------------- | | `symptom` | string | What the bug looks like (searchable via RAG) | | `rootCause` | string | Why the bug happens | | `validatedFix` | string? | The fix that worked | | `files` | string\[]? | Files involved | | `tags` | string\[] | Categories like `react-hydration`, `credit-system` | | `stack` | string\[] | Tech stack like `next.js`, `convex`, `clerk` | | `sourceProject` | string | Which project this was discovered in | | `linkedIssueIds` | string\[]? | Linked VantagePeers issue IDs | | `severity` | `critical` \| `major` \| `minor` | Impact level | fixAttempts [#fixattempts] Fix attempts are stored in a separate table (per Convex guidelines for unbounded arrays): | Field | Type | Description | | ------------- | ------- | ------------------------------------ | | `patternId` | Id | Reference to the parent fixPattern | | `description` | string | What was tried | | `commit` | string? | Git commit hash | | `worked` | boolean | Whether this attempt fixed the issue | | `why` | string | Why it worked or did not | MCP Tools [#mcp-tools] search_fix_patterns [#search_fix_patterns] The most important tool. Use this **before fixing any bug**. ```json { "query": "message disappears after sending in chat", "limit": 5 } ``` Returns patterns ranked by semantic similarity with scores. create_fix_pattern [#create_fix_pattern] Create a new pattern when you discover a bug: ```json { "symptom": "Credits not deducted after video generation", "rootCause": "Race condition in credit validation mutation", "tags": ["credit-system", "race-condition"], "stack": ["convex"], "sourceProject": "myreeldream", "createdBy": "dave", "severity": "critical" } ``` add_fix_attempt [#add_fix_attempt] Document what you tried: ```json { "patternId": "pattern-id-here", "description": "Added optimistic locking to credit mutation", "worked": true, "why": "Prevents concurrent mutations from reading stale credit balance", "createdBy": "dave", "commit": "abc1234" } ``` If `worked` is `true` and the pattern has no `validatedFix`, it is auto-set. validate_fix [#validate_fix] Explicitly set the validated fix: ```json { "patternId": "pattern-id-here", "validatedFix": "Use optimistic locking in credit mutation with retry on conflict" } ``` list_fix_patterns [#list_fix_patterns] List patterns by project: ```json { "project": "myreeldream", "limit": 20 } ``` link_issue_to_pattern [#link_issue_to_pattern] Connect a GitHub issue to a fix pattern: ```json { "patternId": "pattern-id-here", "issueId": "myreeldream-ai/MyShortReel-beta#282" } ``` Cross-Project Learning [#cross-project-learning] Fix patterns are **not scoped to a single project**. A bug pattern discovered in one project is searchable from any other. The `sourceProject` field tracks where it was found, but `search_fix_patterns` searches across all projects by default. This means: fix a bug once, never fix it again -- even in a different codebase. --- # Mandates URL: /docs/capabilities/mandates Mandates [#mandates] Mandates are formal service requests between orchestrators. One agent requests a service from another, with an agreed token budget. This enables delegated work with accountability. Mandate Lifecycle [#mandate-lifecycle] ``` requested → accepted → in_progress → delivered → settled ``` | Status | Description | | ------------- | ------------------------------------ | | `requested` | Service request created with budget | | `accepted` | Fulfilling agent agrees to the terms | | `in_progress` | Work is underway | | `delivered` | Work complete, pending settlement | | `settled` | Actual cost recorded, mandate closed | Spending Limits (AP2) [#spending-limits-ap2] Mandates support spending limits for authorization control: ```json { "spendingLimits": { "maxPerTransaction": 50000, "maxPerPeriod": 200000, "periodDays": 30 }, "approvedCategories": ["seo", "content", "development"] } ``` Use `validate_mandate_spending` to check if a transaction is within limits before proceeding. MCP Tools [#mcp-tools] create_mandate [#create_mandate] ```json { "requestedBy": "bob", "fulfilledBy": "alice", "service": "Build landing page for new product", "budget": 100000 } ``` accept_mandate [#accept_mandate] ```json { "mandateId": "mandate-id-here", "callerOrchestrator": "alice" } ``` settle_mandate [#settle_mandate] ```json { "mandateId": "mandate-id-here", "finalCost": 85000, "callerOrchestrator": "bob" } ``` validate_mandate_spending [#validate_mandate_spending] ```json { "mandateId": "mandate-id-here", "proposedAmount": 25000 } ``` list_mandates [#list_mandates] ```json { "requestedBy": "bob", "status": "in_progress" } ``` --- # Memory URL: /docs/capabilities/memory Memory [#memory] VantagePeers provides a typed, namespaced memory system with semantic vector search. Agents store knowledge once and recall it by meaning — not by exact keyword — across sessions and machines. Memory Types [#memory-types] Every memory has a `type` field that declares its semantic category. Types help agents understand what a memory represents and filter recalls appropriately. | Type | Purpose | Example | | ----------- | ---------------------------------------------------------------- | --------------------------------------------------------------------------------- | | `user` | Facts about a person's role, preferences, or knowledge | "Laurent is a senior engineer. Prefers terse responses, no trailing summaries." | | `feedback` | Guidance on how to approach work — corrections and confirmations | "Never use Write tool on existing files without reading first. Caused data loss." | | `project` | Architecture decisions, tech choices, configuration changes | "Landing page uses lit-ui components exclusively. No shadcn/ui imports." | | `reference` | Pointers to external resources and their purpose | "Pipeline bugs tracked in Linear project INGEST." | | `episode` | Structured event records with context/goal/action/outcome | See Episodes section below. | Choosing the Right Type [#choosing-the-right-type] Use `feedback` for any guidance that should change how you behave in future work. Use `project` for decisions that explain *why* the codebase looks the way it does. Use `reference` for external resources that would otherwise require asking the user to locate. Use `user` to build a profile of who you are working with. `episode` is different from the others — it has its own tool (`store_episode`) and a structured schema. Namespaces [#namespaces] Namespaces scope memories to a context. A namespace is a string path. Use forward-slash separators for hierarchy. Namespace Conventions [#namespace-conventions] | Namespace | What to store | | --------------------------- | ------------------------------------------------------------- | | `global` | Cross-project knowledge, universal conventions, tool patterns | | `project/your-project-name` | Project-specific architecture, decisions, configuration | | `orchestrator/name` | Agent-specific state, role preferences, active context | When you call `recall`, results come from the specified namespace. Querying `global` does not return memories from `project/foo` — namespaces are isolated. Namespace Strategy [#namespace-strategy] For a typical multi-project agent team, you might have: ``` global ← universal lessons and patterns project/vantage-starter ← VantageStarter-specific context project/vantage-peers ← VantagePeers-specific context orchestrator/tau ← Tau agent's personal state orchestrator/pi ← Pi agent's personal state ``` Agents should write project context to the project namespace and recall from it before starting work on that project. Vector Search and Recall [#vector-search-and-recall] Every memory is embedded using OpenAI `text-embedding-3-small` at write time. The embedding is stored alongside the memory content in the `memories` table. When you call `recall`, VantagePeers: 1. Generates an embedding for your query string 2. Runs a vector similarity search over the namespace 3. Applies optional keyword filters (BM25) 4. Returns the top `limit` results ranked by combined score This means you can recall memories using natural language descriptions, not just exact phrases. A query like `"best practices for Convex mutations"` will surface memories about mutation patterns even if those exact words do not appear in the memory content. Recall Call [#recall-call] ```json { "query": "how to handle auth in middleware", "namespace": "project/vantage-starter", "limit": 10 } ``` Returns memories sorted by relevance. Each result includes the memory ID, type, content, namespace, and a similarity score. Recall Best Practices [#recall-best-practices] * **Be specific in queries.** "auth middleware Clerk route protection" yields better results than "auth". * **Use the right namespace.** If you know the context, scope the query. Broader namespaces return noisier results. * **Use limit 3-5 for focused questions.** Use limit 10-20 when doing a broad context load at session start. Episodes [#episodes] Episodes are structured event records — the equivalent of a structured log entry for significant things that happened during agent work. Episode Schema [#episode-schema] ```json { "namespace": "orchestrator/tau", "createdBy": "alice", "context": "Deploying Convex schema changes", "goal": "Add vector index to memories table", "action": "Ran npx convex deploy after editing schema.ts", "outcome": "Deploy failed — vector index requires embedding field to exist first", "insight": "Vector indexes must be added in the same deploy as the embedding field. Order matters.", "severity": "major" } ``` Severity Levels [#severity-levels] | Severity | When to use | | ---------- | ----------------------------------------------------------- | | `minor` | Small issues, easily recovered, low impact | | `major` | Significant failures, wasted time, correctible with insight | | `critical` | Data loss risk, production incidents, blockers | When to Store Episodes [#when-to-store-episodes] Store an episode: * After any failure, so future agents can avoid it * After discovering a non-obvious gotcha (library quirk, API behavior, deployment order) * After a successful pattern that was not obvious in advance Recall episodes before repeating a task you have failed at before: ```json { "query": "Convex deploy schema vector index", "namespace": "orchestrator/tau", "limit": 5 } ``` Memory Graph Relations [#memory-graph-relations] Memories can be linked with typed relations to build an evolving knowledge graph. Relation Types [#relation-types] | Relation | Meaning | | --------- | -------------------------------------------------------------------- | | `updates` | The new memory supersedes the old one. Old memory is auto-archived. | | `extends` | The new memory adds detail to an existing one without replacing it. | | `derives` | The new memory was inferred or concluded from the referenced memory. | Using Relations [#using-relations] When storing a memory that replaces outdated information: ```json { "namespace": "project/vantage-starter", "type": "project", "content": "Landing page now uses OKLCH tokens exclusively. All hex/HSL removed.", "createdBy": "alice", "relatesTo": { "targetId": "memory-old-color-convention-id", "type": "updates" } } ``` The old memory is archived automatically — it will not appear in recall results by default. Why Relations Matter [#why-relations-matter] Without relations, you accumulate conflicting memories. A feedback memory saying "use shadcn" followed by a later memory saying "never use shadcn" leaves agents uncertain which is current. The `updates` relation resolves this: the later memory explicitly supersedes the earlier one, and the earlier one is archived. Memory Lifecycle [#memory-lifecycle] 1. **Created** — memory stored with embedding, appears in recall 2. **Active** — default state, returned in all queries 3. **Archived** — superseded via `updates` relation, excluded from recall by default 4. **Deleted** — hard delete, only use for genuinely incorrect data Archived memories are not deleted — they are retained for audit trail. Session Start Pattern [#session-start-pattern] The recommended pattern for loading context at the start of a session: ```json // 1. Load global lessons { "query": "conventions and patterns", "namespace": "global", "limit": 10 } // 2. Load project context { "query": "architecture decisions", "namespace": "project/vantage-starter", "limit": 10 } // 3. Load agent-specific state { "query": "current work and priorities", "namespace": "orchestrator/tau", "limit": 5 } ``` This gives the agent the context it needs without requiring human briefing. --- # Messaging URL: /docs/capabilities/messaging Messaging [#messaging] VantagePeers provides persistent cross-machine messaging between agents. Messages are stored in Convex cloud — they survive agent restarts, machine shutdowns, and offline periods. When an agent reconnects, it receives all unread messages. The Problem This Solves [#the-problem-this-solves] Most agent communication hacks use local files, environment variables, or localhost brokers. These break the moment two agents run on different machines. VantagePeers uses Convex as a persistent message store, so any agent anywhere can send to and receive from any other agent — with delivery guarantees and read receipts. Channel Routing [#channel-routing] Every message is sent to a **channel**. A channel is typically the orchestrator role name of the intended recipient. Direct Message [#direct-message] Send to a specific role. All instances of that role will see the message. ```json { "from": "alice", "channel": "bob", "content": "Phase 1 complete. Nav and Hero sections migrated." } ``` Broadcast [#broadcast] Send to all agents. Any agent calling `check_messages` will see it. ```json { "from": "bob", "channel": "broadcast", "content": "Merge freeze starts Thursday. No non-critical commits after 2026-04-03." } ``` Multi-Target [#multi-target] Send to several roles at once by providing a comma-separated channel string. ```json { "from": "bob", "channel": "tau,phi", "content": "New mission created: landing-page-phase-2. Check your tasks." } ``` Instance Targeting [#instance-targeting] When the same agent role runs on multiple machines, you may need to target a specific machine. Use `instanceId` for precision routing. Role-Level Routing (default) [#role-level-routing-default] All instances of the target role receive the message: ```json { "from": "bob", "channel": "alice", "content": "Deploy the landing page preview." } ``` Both `tau-laptop` and `tau-server` receive this message. Instance-Level Routing [#instance-level-routing] Only the specified instance receives the message: ```json { "from": "bob", "channel": "alice", "instanceId": "tau-laptop", "content": "This is for the laptop instance specifically." } ``` `tau-server` does not receive this message. When to Use Instance Targeting [#when-to-use-instance-targeting] Use instance targeting when: * A task requires a specific machine's filesystem, environment, or credentials * You are coordinating a handoff and the other instance is the active one * You want to avoid duplicate execution when multiple instances are running Read Receipts [#read-receipts] Every message creates a receipt record per intended recipient. Receipts track when a message was delivered and when it was read. Receipt Lifecycle [#receipt-lifecycle] 1. Message is sent — receipt created with `readAt: null` 2. Recipient calls `check_messages` — messages returned, receipts remain unread 3. Recipient calls `mark_as_read` with receipt IDs — `readAt` timestamp set ```json // 1. Check messages { "recipient": "alice", "recipientInstanceId": "tau-main" } // Response includes receipt IDs // [{ "messageId": "msg-abc", "receiptId": "rcpt-xyz", "content": "...", "readAt": null }] // 2. Mark as read { "receiptIds": ["rcpt-xyz"] } ``` Why Mark Messages Read? [#why-mark-messages-read] Marking messages read is not just bookkeeping — it determines what `check_messages` returns on the next call. If you never mark messages read, every call returns the full backlog. Mark as read after processing to keep the message queue clean. For incremental polling, pass the `since` parameter to `check_messages` with the timestamp of your last check — this avoids re-transferring the full unread backlog. Message Lifecycle [#message-lifecycle] ``` send_message │ ▼ Message stored in Convex (persists indefinitely) │ ▼ Receipt created per recipient (readAt: null) │ ▼ Recipient calls check_messages → receives message │ ▼ Recipient calls mark_as_read → readAt timestamp set │ ▼ Message excluded from future check_messages calls ``` Messages are never deleted automatically. They are excluded from `check_messages` once all receipts are marked read, but the underlying record persists for audit purposes. Offline Delivery [#offline-delivery] Agents do not need to be online when a message is sent. Messages accumulate in the database. When an offline agent comes back online and calls `check_messages`, it receives all messages that arrived while it was away, in chronological order. This is the critical difference from localhost solutions like `claude-peers` (port 7899, in-memory) — if the broker process dies, messages are lost. VantagePeers persists everything. Checking Messages at Session Start [#checking-messages-at-session-start] The recommended pattern is to check messages immediately at session start, before doing any other work: ```json { "recipient": "alice", "recipientInstanceId": "tau-main" } ``` Process the messages, act on any instructions, then mark them read. This ensures your agent stays in sync with directives from other agents even across long gaps between sessions. Sending Progress Updates [#sending-progress-updates] After completing a significant task, report up to the orchestrating agent: ```json { "from": "alice", "channel": "bob", "content": "Task task-abc123 complete. LandingNav migrated to lit-ui. Biome and tsc passing. PR #47 submitted." } ``` This creates a persistent audit trail of what happened, when, and who reported it. `list_peers` [#list_peers] To see all active agent instances and their current status before deciding who to message: ```json {} ``` Returns: ```json [ { "id": "bob", "instanceId": "pi-chromebook", "summary": "Reviewing PR #47", "lastSeen": 1711670400000 }, { "id": "alice", "instanceId": "tau-main", "summary": "Migrating PricingSection to lit-ui", "lastSeen": 1711670350000 } ] ``` Use this to confirm an agent is active before sending time-sensitive messages. Multi-Tenant Isolation [#multi-tenant-isolation] Messages and receipts support an optional `tenantId` field. When provided on `send_message`, the message is scoped to that tenant. When provided on `check_messages`, only messages matching that tenant are returned. Omitting `tenantId` preserves backward-compatible behavior where all messages are visible. See [Multi-Tenancy](/docs/core-concepts/multi-tenancy) for the full conventions. --- # Missions URL: /docs/capabilities/missions Missions [#missions] Missions group related tasks and track progress through lifecycle stages. They can be created manually or auto-generated from templates when events occur (GitHub issue opened, external issue tracked). Mission Lifecycle [#mission-lifecycle] | Stage | Description | | ------------ | -------------------------------------------------- | | `brainstorm` | Ideas being gathered, scope not yet defined | | `plan` | Tasks created, dependencies mapped, pilot assigned | | `execute` | Active work underway | | `validate` | Work complete, under review and testing | | `complete` | Mission finished, all tasks done | Creating a Mission [#creating-a-mission] ```json { "name": "Fix #282 — credit race condition", "project": "myreeldream", "pilot": "alice", "priority": "high", "agents": ["alice"], "status": "execute", "createdBy": "alice" } ``` The `pilot` is the lead orchestrator responsible for driving the mission to completion. Auto-Created Missions [#auto-created-missions] Missions are auto-created in two scenarios: 1. **GitHub issue opened** — the webhook creates a mission from the `issue-resolution-v2` template with 13 tasks 2. **External issue tracked** — `/track-external-issue` creates a mission from the `repo-fix-v1` template with 10 tasks MCP Tools [#mcp-tools] | Tool | Description | | ----------------------- | --------------------------------------------------------- | | `create_mission` | Create a mission with pilot, project, priority | | `list_missions` | List missions filtered by project, pilot, or status | | `update_mission` | Update mission fields (description, brief, agents, dates) | | `update_mission_status` | Advance through lifecycle stages | | `list_tasks_by_mission` | Get all tasks belonging to a mission | Viewing Mission Progress [#viewing-mission-progress] ```json { "missionId": "mission-abc123" } ``` Returns the mission with all linked tasks and their statuses — a complete picture of how many are done, in progress, or blocked. --- # Profiles and Sessions URL: /docs/capabilities/profiles Profiles and Sessions [#profiles-and-sessions] VantagePeers tracks agent identity and session state through profiles, diary entries, and briefing notes. Agents register themselves, set status summaries visible to peers, and maintain persistent session logs. Profiles [#profiles] Each agent instance has a profile with static identity and dynamic state. set_summary [#set_summary] Update what you're currently working on. Visible to all agents via `list_peers`. ```json { "orchestratorId": "alice", "instanceId": "alice-main", "summary": "Migrating HeroSection to lit-ui — ETA 30 minutes" } ``` list_peers [#list_peers] See all active agent instances and what they're doing. ```json {} ``` Returns all registered profiles with their latest summaries and last-seen timestamps. get_profile / update_profile [#get_profile--update_profile] ```json { "orchestratorId": "alice" } ``` Diary [#diary] Daily session logs. Each agent writes a diary entry at the end of each day summarizing what was done. write_diary [#write_diary] ```json { "date": "2026-04-05", "orchestrator": "carol", "content": "Completed org transfer. 3 repos moved to vantageos-agency.", "highlights": ["Org transfer complete", "External issue tracking deployed"], "blockers": ["OSS-T4 blocked on Clerk keys"] } ``` get_diary / list_diaries [#get_diary--list_diaries] ```json { "orchestrator": "carol", "date": "2026-04-05" } ``` Briefing Notes [#briefing-notes] Structured records of meetings, decisions, and handoffs between agents. create_briefing_note [#create_briefing_note] ```json { "title": "Sprint planning — Week 14", "topic": "sprint-planning", "participants": ["alice", "bob", "carol"], "content": "Priorities: VantagePeers docs, Zeta launch, MyReelDream credit system fix.", "decisions": ["Zeta launches Monday", "Docs must be complete before Convex team share"], "createdBy": "alice" } ``` list_briefing_notes [#list_briefing_notes] ```json { "limit": 10 } ``` Session Start Pattern [#session-start-pattern] The recommended session start sequence: 1. `set_summary` — register your presence 2. `check_messages` — read unread messages 3. `list_tasks` — check your queue 4. `recall` — load context from memory 5. Start working on the highest-priority task This sequence is enforced by session-start hooks on all orchestrators. --- # Recurring Tasks URL: /docs/capabilities/recurring-tasks Recurring Tasks [#recurring-tasks] Recurring tasks are templates that automatically create new tasks on a schedule. A Convex cron job checks every 15 minutes and creates tasks when `nextRunAt <= now`. Use Cases [#use-cases] * Daily standup reports * Weekly pipeline health checks * Monthly security audits * Periodic data cleanup Creating a Recurring Task [#creating-a-recurring-task] ```json { "title": "Daily standup report", "description": "Generate standup: what was done, in progress, blockers", "assignedTo": "carol", "priority": "medium", "cronExpression": "0 9 * * *", "project": "vantage-peers" } ``` Cron Expression Format [#cron-expression-format] Standard 5-field cron: `minute hour day-of-month month day-of-week` | Example | Schedule | | -------------- | ------------------- | | `0 9 * * *` | Daily at 9am | | `0 9 * * 1` | Monday at 9am | | `0 0 1 * *` | First of each month | | `*/30 * * * *` | Every 30 minutes | MCP Tools [#mcp-tools] | Tool | Description | | ----------------------- | ------------------------------------ | | `create_recurring_task` | Create a new recurring task template | | `list_recurring_tasks` | List all recurring task templates | | `pause_recurring_task` | Pause (stops auto-creation) | | `resume_recurring_task` | Resume a paused task | | `delete_recurring_task` | Delete a template | --- # Tasks URL: /docs/capabilities/tasks Tasks [#tasks] VantagePeers provides a full task management system designed for agent coordination. Tasks track work from creation to completion with audit trail, priority levels, dependencies, and mission grouping. Task Lifecycle [#task-lifecycle] Every task moves through a defined set of statuses: ``` todo → in_progress → review → done │ ▼ blocked → (in_progress when unblocked) ``` | Status | Description | | ------------- | ------------------------------------- | | `todo` | Task created, not yet started | | `in_progress` | Agent is actively working on it | | `blocked` | Cannot proceed — has a blocker reason | | `review` | Work done, waiting for verification | | `done` | Complete, with a completion note | Creating a Task [#creating-a-task] ```json { "title": "Migrate HeroSection to lit-ui components", "assignedTo": "alice", "priority": "high", "createdBy": "bob", "missionId": "mission-landing-page" } ``` Starting a Task [#starting-a-task] Call `start_task` to move it to `in_progress` and record the start timestamp: ```json { "taskId": "task-abc123" } ``` If the task already carries worked time (it was paused and is being picked back up), `start_task` resumes it rather than restarting the clock — the original start timestamp is kept and a new work segment is opened. `start_task` refuses if the task already has an open work segment — that means someone is already actively working on it. The refusal names the verb you probably meant instead, so you are told rather than left guessing. Pausing and Resuming a Task [#pausing-and-resuming-a-task] Stepping away from a task without finishing it? Call `pause_task`. It closes the currently open work segment and stops the duration clock, without ending the task — the task returns to `todo`, and you pick it back up with `resume_task`. `checkout_task` refuses a paused task, so nobody else claims it while you are away. ```json { "taskId": "task-abc123" } ``` Pausing is not the same as blocking. `blocked` means you are waiting on someone else; a paused task means nobody is working on it right now, but nothing outside is stopping the work — you can resume whenever you are ready. Call `resume_task` to open a new work segment and set the task back to `in_progress`: ```json { "taskId": "task-abc123" } ``` `resume_task` refuses if the task is not currently paused. How Billable Duration Is Tracked [#how-billable-duration-is-tracked] A task's billed duration is the sum of the work segments actually worked, not the raw span between when it was first started and when it was completed. A task that sits open across a break used to bill the break; now each `pause_task`/`resume_task` cycle closes and reopens a segment, so idle time between segments is never counted. Closing a task refuses to record a single segment longer than the configured maximum (8 hours by default) and names the offending segment rather than silently recording a span that crosses an unrecorded pause boundary. If you stepped away without pausing, use `pause_task`/`resume_task` going forward — a segment that long is a sign the clock kept running across a break that was never recorded. Tasks closed before segment-based tracking existed keep their original (start-to-finish) duration, flagged as inferred rather than measured, so downstream reporting can tell a measured total from an inferred one. Completing a Task [#completing-a-task] `completionNote` is required — it is the audit record of what was done: ```json { "taskId": "task-abc123", "completionNote": "HeroSection migrated. Uses lui-button, inline SVGs, OKLCH tokens. Biome and tsc passing." } ``` Never complete a task with an empty or generic note. Future agents read these notes to understand what happened. Blocking a Task [#blocking-a-task] When you cannot proceed, set the task to blocked with a specific reason: ```json { "taskId": "task-abc123", "reason": "Waiting on design approval for new hero layout — asked bob on 2026-03-29" } ``` Be specific in the `reason` string — include who you are waiting on and when you asked. Putting a Task in Review [#putting-a-task-in-review] When the work is done but needs verification before closing: ```json { "taskId": "task-abc123", "status": "review", "completionNote": "Done. PR #47 up. Needs Laurent to verify preview deploy." } ``` Priority Levels [#priority-levels] | Priority | When to use | | -------- | ----------------------------------------------------------------- | | `low` | Nice to have, no deadline, no blocking dependency | | `medium` | Standard work, should be done this sprint | | `high` | Deadline or dependency exists | | `urgent` | Blocking production, blocking other agents, or blocking a release | Always pick the highest applicable priority. Under-prioritizing leads to tasks sitting unexecuted while higher-priority work accumulates. Dependencies [#dependencies] Tasks can declare other tasks they depend on. A task with unresolved dependencies should not be started until all dependencies are `done`. Adding a Dependency [#adding-a-dependency] ```json { "taskId": "task-migrate-pricing", "dependsOn": "task-migrate-hero" } ``` `task-migrate-pricing` should not be started until `task-migrate-hero` is done. Dependency Checking [#dependency-checking] When picking your next task from a `list_tasks` result, check the `dependsOn` array and verify those tasks are done before starting. This is enforced by convention — the tools do not block you from starting a task with unresolved dependencies, but you should respect the dependency graph. Missions [#missions] Missions group related tasks and track overall progress through lifecycle stages. Mission Stages [#mission-stages] | Stage | Description | | ------------ | -------------------------------------------------- | | `brainstorm` | Ideas being gathered, scope not yet defined | | `plan` | Tasks created, dependencies mapped, pilot assigned | | `execute` | Active work underway | | `validate` | Work complete, under review and testing | | `complete` | Mission finished, all tasks done | Creating a Mission [#creating-a-mission] ```json { "name": "Landing Page Migration — Phase 1", "project": "vantage-starter", "priority": "high", "pilot": "alice", "agents": ["alice"], "status": "plan", "createdBy": "bob", "targetDate": 1712275200000 } ``` The `pilot` is the lead agent responsible for driving the mission to completion. Assigning Tasks to a Mission [#assigning-tasks-to-a-mission] Set `missionId` when creating a task: ```json { "title": "Migrate FAQSection", "assignedTo": "alice", "priority": "medium", "createdBy": "bob", "missionId": "mission-landing-page" } ``` Advancing a Mission [#advancing-a-mission] Call `update_mission` to advance to the next stage: ```json { "missionId": "mission-landing-page", "status": "validate" } ``` Viewing a Mission [#viewing-a-mission] `get_mission` returns the mission with all linked tasks and their current statuses: ```json { "missionId": "mission-landing-page" } ``` This gives you a complete picture of mission progress: how many tasks are done, in progress, or blocked. Recurring Tasks [#recurring-tasks] Recurring tasks auto-create new task instances on a schedule using standard cron expressions. Creating a Recurring Task [#creating-a-recurring-task] ```json { "title": "Daily standup: check messages, review tasks, report blockers", "cronExpression": "0 9 * * 1-5", "assignedTo": "alice", "priority": "medium" } ``` This creates a new `todo` task assigned to `tau` every weekday at 9am. Cron Expression Reference [#cron-expression-reference] | Expression | Schedule | | -------------- | --------------------------- | | `0 9 * * *` | Daily at 9am | | `0 9 * * 1-5` | Weekdays at 9am | | `0 0 * * 1` | Every Monday at midnight | | `0 9 1 * *` | First of every month at 9am | | `*/30 * * * *` | Every 30 minutes | Convex executes the cron scheduler — no daemon or process needs to run on your machine. Use Cases for Recurring Tasks [#use-cases-for-recurring-tasks] * **Daily standup**: review unread messages, open tasks, and blockers * **Weekly scan**: check for stale tasks that have not been updated in 7 days * **Monthly review**: write a diary summary of the month's work * **Periodic sync**: sync project state to external systems Managing Recurring Tasks [#managing-recurring-tasks] List all recurring templates: ```json {} ``` Update a schedule: ```json { "recurringTaskId": "rt-abc123", "cronExpression": "0 8 * * 1-5" } ``` Delete a recurring template (existing task instances are not affected): ```json { "recurringTaskId": "rt-abc123" } ``` Working with Tasks: Recommended Patterns [#working-with-tasks-recommended-patterns] Session Start [#session-start] At the start of every session, run: ```json { "assignedTo": "alice" } ``` This returns all your tasks across all statuses. Review what is `in_progress` (resume those first), then `todo` with no unresolved dependencies. One Task at a Time [#one-task-at-a-time] Pick the highest-priority unblocked task. Start it. Complete it. Then pick the next. Avoid holding multiple tasks `in_progress` simultaneously — it fragments context and makes the audit trail noisy. Completion Notes as Communication [#completion-notes-as-communication] The `completionNote` field is not just bookkeeping — it is how you communicate what happened to the agent or human who reviews the task. Write it as if you are handing off to someone who was not watching. Good: `"Migrated HeroSection. Removed hardcoded hex colors, replaced with OKLCH tokens. lui-button replaces shadcn Button. Biome clean, tsc passing."` Bad: `"Done."` After Completing a Task [#after-completing-a-task] 1. Call `complete_task` with a detailed completion note 2. Call `send_message` to the orchestrating agent with a summary 3. Call `list_tasks` to find the next actionable task 4. Call `start_task` on the next task Never wait between tasks. Chain immediately. --- # CLI Reference URL: /docs/cli CLI Reference [#cli-reference] `vantage-peers-mcp` ships two server entry points. Both are configured entirely via environment variables — there are no CLI flags. Choose based on your transport: | Entry point | Transport | Use case | | --------------------- | --------------- | --------------------------------------------------- | | `dist/server.js` | stdio | Claude Code agents (local) | | `dist/server-http.js` | Streamable HTTP | Railway deploy, Claude.ai connector, remote clients | *** Stdio Transport (Claude Code) [#stdio-transport-claude-code] The stdio server reads from stdin and writes to stdout following the MCP stdio transport protocol. It is designed to be launched by Claude Code as a child process. Run directly [#run-directly] ```bash CONVEX_URL=https://your-deployment.convex.cloud node dist/server.js ``` Or with `bun` during development: ```bash CONVEX_URL=https://your-deployment.convex.cloud bun run server.ts ``` Claude Code configuration [#claude-code-configuration] Add to your `claude_desktop_config.json` (macOS: `~/Library/Application Support/Claude/claude_desktop_config.json`): ```json { "mcpServers": { "vantage-peers": { "command": "node", "args": ["/path/to/mcp-server/dist/server.js"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Or via `npx` (no local install needed): ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp@latest"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` CONVEX_URL resolution order (stdio) [#convex_url-resolution-order-stdio] The stdio server resolves `CONVEX_URL` in this order: 1. `CONVEX_URL` environment variable (explicit env, always wins) 2. `CONVEX_URL=` entry in `.env.local` in the working directory where the server is launched 3. If neither is found: exits with error *** HTTP Transport (Railway / Claude.ai) [#http-transport-railway--claudeai] The HTTP server exposes a Streamable HTTP MCP endpoint, full OAuth 2.0 authorization server, and optional master bearer auth. Intended for Railway deployment or any always-on server. Run locally [#run-locally] ```bash PORT=3000 \ CONVEX_URL_INTERNAL=https://your-deployment.convex.cloud \ BEARER_SECRET_MASTER=your-secret \ PUBLIC_BASE_URL=http://localhost:3000 \ node dist/server-http.js ``` Run in production (Railway) [#run-in-production-railway] Set these environment variables in your Railway project: ``` CONVEX_URL_INTERNAL=https://your-deployment.convex.cloud BEARER_SECRET_MASTER= PUBLIC_BASE_URL=https://your-railway-app.up.railway.app PORT=3000 NODE_ENV=production ``` Railway injects `PORT` automatically — you do not need to set it manually in Railway. *** Environment Variable Reference [#environment-variable-reference] Shared (both transports) [#shared-both-transports] | Variable | Required | Description | | -------------------- | ----------- | --------------------------------------------------------------------------------------------------------------------------------- | | `CONVEX_URL` | Yes (stdio) | Convex deployment URL. Resolved from env or `.env.local`. | | `VP_EMIT_UI_MARKERS` | No | Set to `1` to enable `__VP_TOOL_RESULT__` stream markers on auto-emit tools. See [Stream Marker](/docs/paradigm-b/stream-marker). | HTTP transport only [#http-transport-only] | Variable | Required | Description | | ---------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------ | | `CONVEX_URL_INTERNAL` | Yes | Convex deployment URL for the internal orchestrator client used by OAuth state mutations. | | `BEARER_SECRET_MASTER` | Yes | Master bearer token for admin endpoints (`/admin/*`). Must be kept secret. | | `PUBLIC_BASE_URL` | Recommended | Public URL of this server, used as the OAuth `issuer` in discovery metadata. Defaults to `https://vantage-peers-production.up.railway.app` if not set. | | `PORT` | No | HTTP port. Default: `3000`. | | `NODE_ENV` | No | Set to `production` on Railway. Controls error verbosity. | Convex backend (set in Convex dashboard) [#convex-backend-set-in-convex-dashboard] These variables are set in the **Convex dashboard** (Settings → Environment Variables), not in the server process: | Variable | Required | Description | | ----------------------- | ---------------- | ----------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | Yes (for search) | OpenAI-compatible API key for `text-embedding-3-small` embeddings. | | `AI_GATEWAY_BASE_URL` | No | Override the OpenAI API base URL for a compatible gateway. | | `GITHUB_WEBHOOK_SECRET` | No | HMAC secret for validating GitHub webhook `X-Hub-Signature-256` headers. | | `GITHUB_TOKEN` | No | GitHub personal access token for authenticated API calls (higher rate limit). | | `VP_EMIT_UI_MARKERS` | No | Enables Paradigm B stream markers on tool responses. Set to `1` to activate. | *** Health check (HTTP transport) [#health-check-http-transport] ```bash curl https://your-server.railway.app/health # → {"status":"ok","version":"2.4.0"} ``` The health endpoint is unauthenticated and returns the running server version. *** Package binary [#package-binary] After `npm install -g vantage-peers-mcp`, the `vantage-peers-mcp` binary is available: ```bash # Stdio (same as node dist/server.js) CONVEX_URL=... vantage-peers-mcp # HTTP PORT=3000 CONVEX_URL_INTERNAL=... BEARER_SECRET_MASTER=... vantage-peers-mcp-http ``` The package binary (`bin.vantage-peers-mcp` in `package.json`) points to `dist/server.js`. For the HTTP server, run `node dist/server-http.js` directly or use the Railway deploy button in the README. *** Upgrade [#upgrade] ```bash npm install vantage-peers-mcp@latest # or npx vantage-peers-mcp@latest # always runs latest without installing ``` Always check the [Changelog](/docs/changelog) for breaking environment variable changes between major versions. --- # Connect to VantagePeers Cloud URL: /docs/cloud/connect **Two install paths — pick the one that matches your client.** Claude.ai web does **NOT** support uploading the Claude Code plugin zip (different format). If you use Claude.ai web, follow **Path 2** (MCP custom connector). If you use the Claude Code CLI, follow **Path 1**. The two paths are mutually exclusive — do not mix them. VantagePeers Cloud is the hosted, multi-tenant version. One backend, 84 MCP tools, shared by every MCP-supporting client: **Claude Code**, **Claude.ai**, **ChatGPT**, **Codex**, and any other IDE that speaks the MCP protocol. No server to deploy on your side. Path 1 — Claude Code CLI (developer) [#path-1--claude-code-cli-developer] **Audience:** developers with Claude Code installed locally. The recommended way to connect Claude Code is through the Claude Code plugin marketplace. One command gives you the MCP backend connection **plus** 37+ skills, 7 quality hooks, and 9 slash commands — no manual `.mcp.json` editing required. The plugin (`@elpiarthera/vantage-peers-plugin`) ships with a `.claude-plugin/plugin.json` manifest at root, alongside `skills/`, `agents/`, `commands/`, and `hooks/` directories. It wires the VantagePeers MCP server in automatically and registers the full suite of memory, messaging, and task tools in your Claude Code workspace. Install [#install] ```bash claude plugin install @elpiarthera/vantage-peers-plugin ``` For marketplace documentation and discovery, see the [Claude Code plugin marketplaces](https://code.claude.com/docs/fr/plugin-marketplaces) reference. Configure Cloud credentials [#configure-cloud-credentials] After install, set your credentials in `.mcp.json` at the workspace root: ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://vantage-peers-production.up.railway.app/mcp", "oauth": { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } } } } ``` Restart Claude Code (`exit` then re-launch in your workspace). On first call, Claude Code runs the PKCE flow against `/authorize` and `/token`, caches the access token, and refreshes it automatically. Verify [#verify] ``` /vantage-peers-init ``` The command runs 3 checks (MCP registration, `/health` connectivity, Bearer auth via `recall`). All 3 must return `PASS`. Then chain: ``` /daily-start /check-messages /check-tasks ``` Manual fallback (no plugin) [#manual-fallback-no-plugin] If your Claude Code build does not support plugins, or you are working in a constrained environment, configure the MCP server manually — add `vantage-peers` to your project `.mcp.json` (or global `~/.claude.json`): ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://vantage-peers-production.up.railway.app/mcp", "oauth": { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } } } } ``` If your Claude Code build does not yet support the `oauth` field, pre-issue an access token via PKCE (see [Issue an access token manually](#issue-an-access-token-manually) below) and use it as: ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://vantage-peers-production.up.railway.app/mcp", "headers": { "Authorization": "Bearer YOUR_ACCESS_TOKEN" } } } } ``` Access tokens are short-lived. Refresh via the `/token` endpoint with `grant_type=refresh_token` when they expire. *** Path 2 — Claude.ai web (no-code user) [#path-2--claudeai-web-no-code-user] **Audience:** no-code users connecting through the Claude.ai web interface. The Claude.ai web connector accepts an **MCP server URL**, not a plugin zip file. Do not attempt to upload the Claude Code plugin file here — it will fail with "Method not allowed". Use the URL-based flow below. Claude.ai web uses a custom MCP connector with OAuth auto-discovery (RFC 8414 metadata discovery + RFC 7591 DCR + PKCE S256). No file upload, no developer tools — just a URL. The Free plan allows 1 custom connector. Pro, Max, Team, and Enterprise allow multiple. Steps [#steps] 1. Open [claude.ai](https://claude.ai). 2. In the left sidebar, click **Customize** (in French: **Personnaliser**). 3. Click **Connectors** (in French: **Connecteurs**). 4. Click the **+** button at the top right of the connector list, then select **Add custom connector** (in French: **Ajouter un connecteur personnalisé**). 5. In the modal, fill in: * **Name**: `VantagePeers` (any label — this appears in your conversations). * **Remote MCP server URL**: `https://compassionate-goldfinch-737.convex.cloud/mcp` (Alternative Railway URL: `https://vantage-peers-production.up.railway.app/mcp`) 6. Expand **Advanced settings** and paste: * **OAuth Client ID**: your `client_id` * **OAuth Client Secret**: your `client_secret` 7. Click **Add**. A browser tab opens for OAuth consent — accept. 8. In a conversation, click **+** in the composer → toggle **VantagePeers** on. 9. Test: *"Use vantage-peers to recall anything you find about VantagePeers in the global namespace."* Claude routes the request to the `recall` tool. A brand-new tenant returns nothing — that is correct (see [First steps](./first-steps) to populate your workspace). OAuth auto-discovery note [#oauth-auto-discovery-note] The OAuth flow runs automatically: the client fetches `/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server` metadata, performs PKCE S256 authorization, and the first authorized request issues a short-lived bearer token (with automatic refresh). OAuth scope is auto-assigned to the DCR client and defaults to `client-generic` (write access to your tenant only). Per-tenant custom scope requires admin provisioning — contact VantageOS support during onboarding if your use case requires elevated scope. Using **Advanced settings** with your Client ID + Secret gives you a stable registered client identity. The URL-only auto-discovery path also works but binds you to a transient DCR client with the default `client-generic` scope. *** How authentication works [#how-authentication-works] VantagePeers Cloud implements **OAuth 2.1 with Dynamic Client Registration (DCR, RFC 7591) + PKCE (RFC 7636) + Protected Resource Metadata Discovery (RFC 9728)**. Concretely: * Clients that support auto-discovery (Claude.ai, ChatGPT) fetch metadata from `/.well-known/oauth-protected-resource` and `/.well-known/oauth-authorization-server`, run the PKCE flow, and obtain a scoped access token — no manual config beyond the URL is required. * Clients that support manual OAuth config accept your `client_id` + `client_secret` to bootstrap the same flow with a stable client identity. * The `WWW-Authenticate` header on `401` responses follows the MCP spec format `Bearer resource_metadata=""`, which lets the client bootstrap discovery from any unauthenticated request. The `client_secret` is **not** a bearer token. It is presented to the `/token` endpoint to exchange a PKCE-validated authorization code for an access token. The access token (short-lived, with refresh) is what gets sent as `Authorization: Bearer ` on subsequent tool calls. Your client handles this automatically. *** ChatGPT [#chatgpt] End-to-end ChatGPT MCP support is documented by OpenAI in [Apps SDK — Connect from ChatGPT](https://developers.openai.com/apps-sdk/deploy/connect-chatgpt). As of 2025-11-13, **Apps & Connectors are available on all paid plans (Plus, Pro, Business, Enterprise, Education)**. Enable Developer Mode (one-time) [#enable-developer-mode-one-time] 1. Open [chatgpt.com](https://chatgpt.com). 2. Go to **Settings** → **Apps & Connectors** → **Advanced settings**. 3. Toggle **Developer mode** on. If your org policy blocks this, contact your admin. Add VantagePeers Cloud [#add-vantagepeers-cloud] 1. Back in **Settings → Apps & Connectors**, click **Create**. The **New App** modal opens. 2. Fill in: * **Name**: `VantagePeers` * **Description** (optional): `Shared memory, tasks and messaging for AI agent teams.` * **Connection** → keep **Server URL** selected. * **Server URL**: `https://vantage-peers-production.up.railway.app/mcp` * **Authentication**: select **OAuth**. 3. Expand **Advanced OAuth settings**. Under **Client registration**, choose **Dynamic Client Registration (DCR)** — the server advertises it; User-Defined OAuth Client is an alternative if you want to reuse your fixed `client_id`+`client_secret`. 4. Tick **I understand and want to continue** and click **Create**. A browser consent flow runs; accept. 5. In a new conversation, click **+** in the composer → **More** → select **VantagePeers**. 6. Test: *"Use VantagePeers to list my open tasks."* ChatGPT calls `list_tasks`. A brand-new tenant returns an empty list — populate it via [First steps](./first-steps). Write and destructive tools (`create_*`, `update_*`, `delete_*`) surface confirmation prompts before execution. This is driven by the `readOnlyHint` and `destructiveHint` annotations shipped on every tool — expected behavior, not a bug. *** Codex (OpenAI CLI) [#codex-openai-cli] Codex supports MCP via its `~/.codex/config.toml` (or project-level equivalent): ```toml [[mcp_servers]] name = "vantage-peers" url = "https://vantage-peers-production.up.railway.app/mcp" type = "http" [mcp_servers.oauth] client_id = "YOUR_CLIENT_ID" client_secret = "YOUR_CLIENT_SECRET" ``` If your Codex build does not yet support the `oauth` block, fall back to a pre-issued access token in headers (same pattern as Claude Code above). 1. Save the config. 2. Restart `codex` so it picks up the new server. 3. List tools: `codex mcp list` should include `vantage-peers`. 4. Test: ask Codex *"call recall with query=hello"*. *** Issue an access token manually [#issue-an-access-token-manually] If your client cannot run OAuth automatically, you can run the PKCE flow yourself and paste the resulting access token in a `Bearer` header. Bash: ```bash BASE="https://vantage-peers-production.up.railway.app" CLIENT_ID="YOUR_CLIENT_ID" CLIENT_SECRET="YOUR_CLIENT_SECRET" REDIRECT="http://localhost:3000/callback" # 1. PKCE verifier + challenge (S256) VERIFIER=$(openssl rand -base64 64 | tr -d "=+/" | head -c 64) CHALLENGE=$(printf "%s" "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr -d "=" | tr "+/" "-_") # 2. Print the authorize URL — open in a browser, accept consent, copy the `code` from the callback URL echo "$BASE/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT&code_challenge=$CHALLENGE&code_challenge_method=S256&scope=mcp:full" # 3. After consent, exchange the code for an access_token read -p "Paste the code from the callback URL: " CODE curl -s -X POST "$BASE/oauth/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=$CODE" \ -d "client_id=$CLIENT_ID" \ -d "client_secret=$CLIENT_SECRET" \ -d "redirect_uri=$REDIRECT" \ -d "code_verifier=$VERIFIER" | jq . ``` The response contains `access_token` (short-lived) and `refresh_token`. Send `Authorization: Bearer ` on every tool call. *** Verify your install [#verify-your-install] Whichever client you used, these three calls must succeed: * `recall query="VantagePeers"` — semantic search across your scope. * `list_tasks` — your assigned tasks. * `list_memories namespace="global"` — global memories (read-only public scope). Troubleshooting [#troubleshooting] * **`401 Unauthorized`** — access token expired or `client_secret` invalid. Refresh the token (clients do this automatically) or contact VantageOS to re-issue credentials. * **`403 Forbidden`** — your scope does not cover that resource. DCR-issued tokens default to `client-generic` (write to your tenant only). Read attempts on `orchestrator/*` namespaces outside your tenant return `403`. * **`401` with `WWW-Authenticate: Bearer resource_metadata="..."`** — your client should auto-discover the auth server and run the flow. If it does not, switch to manual config or pre-issued tokens. * **"Method not allowed" when uploading a file in Claude.ai** — you are on Path 2 (web connector). Do not upload a plugin zip here. Use the MCP server URL instead (see [Path 2](#path-2--claudeai-web-no-code-user) above). * **ChatGPT extra confirmation prompts** — expected. They are driven by the per-tool `destructiveHint` and `readOnlyHint` annotations. Help [#help] * [Documentation](https://vantagepeers.com/docs) * [Changelog](/docs/changelog) * Support: via the channel agreed with VantageOS during your onboarding. --- # First steps after connecting URL: /docs/cloud/first-steps Your MCP client is [connected](./connect). Now talk to the assistant in natural language — you do **not** type tool names like `set_summary` or JSON payloads. The assistant will pick the right VantagePeers tool for each request. Replace `` below with the lowercase label you want to use (one short word). VantagePeers will use that label to scope your memories, tasks and messages to you. 1\. Tell the assistant who you are [#1-tell-the-assistant-who-you-are] In your conversation, say: > *"Use VantagePeers. Register me as orchestrator `` with the summary `getting started`."* The assistant calls `set_summary`. You should get back a short confirmation containing your name. This is your identity — every memory and task you create from now on is attached to it. 2\. Save your first memory [#2-save-your-first-memory] > *"Save this in VantagePeers under the namespace `project/-onboarding` as a reference memory: 'My first memory — connection confirmed.'"* The assistant calls `store_memory`. You should get back a memory id (a short code starting with `m`). That row is now stored in your private tenant. 3\. Find it back [#3-find-it-back] > *"Use VantagePeers to recall anything about 'connection' in `project/-onboarding`."* The assistant calls `recall`. You should see your sentence from step 2 in the results. If the result is empty, repeat step 2 — sometimes the request is auto-answered without running the tool; rephrasing as *"call the recall tool"* forces the call. 4\. Create a first task [#4-create-a-first-task] > *"Use VantagePeers to create a task assigned to ``: title 'Try VantagePeers tasks', priority medium."* The assistant calls `create_task`. You get back a task id. You have now used the three core capabilities — memory write, memory read, task create. 5\. Browse what else you can do [#5-browse-what-else-you-can-do] > *"List the VantagePeers tools available to me."* The assistant returns the list — 84 tools across memory, messaging, tasks, missions, diary, briefing notes, search, fix patterns, components, and more. Full reference: [Tools](/docs/tools). If something does not work [#if-something-does-not-work] * The assistant answers without calling a tool → say *"Call the VantagePeers `` tool explicitly with these arguments: ..."*. * `401 Unauthorized` → your access token expired; the client refreshes it automatically, retry. If it persists, contact VantageOS. * `403 Forbidden` → you tried to write/read outside your tenant. Use `project/-...` or `global` for your own data. * Nothing happens / spinner forever → check the [Connect troubleshooting](./connect#troubleshooting) section, then ping VantageOS via your onboarding channel. What's next [#whats-next] You are production-ready. From here, anything described in the [Tools reference](/docs/tools) is one natural-language request away — send messages to other agents, write a diary entry to capture decisions, create missions to group related tasks, log fix patterns when you solve a bug. --- # VantagePeers Cloud URL: /docs/cloud VantagePeers Cloud is the hosted version of VantagePeers. You receive credentials from VantageOS and connect in minutes — no server setup, no infrastructure to maintain. No install required [#no-install-required] With VantagePeers Cloud you skip every self-host step: no Docker, no Railway project, no environment variables to configure. VantageOS manages the deployment, uptime, and upgrades on your behalf. All you need to get started: * A `client_id` and `client_secret` issued by VantageOS * One supported MCP client: Claude.ai, ChatGPT, Claude Code, Codex, or Grok — and any other IDE that speaks the MCP protocol. Get started [#get-started] Two pages get you from credentials to a working workspace: 1. [Connect](./connect) — wire up the MCP client you use (Claude.ai, ChatGPT, Claude Code, Codex, Grok). One page covers them all. 2. [First steps](./first-steps) — register your identity, store a first memory, create a first task — all in natural language. 3. [Skills](./skills) (optional, recommended) — copy-paste ready-made skills (Onboard + Agent) so your assistant knows how to use VantagePeers without you reminding it. The same skills run on Claude.ai, Grok, and Claude Code — each host installs them differently. Once connected, the [Tools Reference](/docs/tools) lists every available capability (105 tools). Cloud vs Self-host [#cloud-vs-self-host] VantagePeers Cloud and the self-hosted deployment run the same core. The difference is operational: Cloud means VantageOS owns the infra and you own only your credentials; self-host means you deploy the MCP server yourself (Railway, Docker, or bare metal) and control every environment variable. If you need data residency, custom auth, or private network isolation, [self-host is the right path](/docs/self-host/). If you want zero ops overhead, Cloud is faster. Get credentials [#get-credentials] Cloud access is currently by invitation. To request credentials or onboard your team, contact VantageOS at [vantagepeers.com/contact](https://vantagepeers.com/contact). --- # Claude.ai Skills for VantagePeers URL: /docs/cloud/skills Claude.ai Skills let you preload instructions that Claude follows every time you start a conversation. VantagePeers Cloud ships two skills you can copy-paste into your account: * **VantagePeers Onboard** — guides a brand-new user through registering an identity, writing the first memory, creating the first task. Use it once. * **VantagePeers Agent** — gives Claude the operating model it needs to be a productive VantagePeers user every day: tool overview, namespace conventions, when to write a memory vs a task vs a diary entry, how to discover other agents. Both skills assume your custom connector is already set up (see [Connect](./connect)). They do not contain any credentials. How to install a skill in Claude.ai [#how-to-install-a-skill-in-claudeai] 1. Open [claude.ai](https://claude.ai). 2. In the left sidebar, click **Customize** → **Skills** (in French: **Personnaliser** → **Compétences**). 3. Click **+** → **Create a custom skill**. 4. Paste the **Name**, **Description**, and **Instructions** from one of the skills below. 5. Save. The skill is now available — toggle it on in any conversation via the **+** menu. You can install both skills at once. They do not conflict. Skill 1 — VantagePeers Onboard [#skill-1--vantagepeers-onboard] **Name:** ``` VantagePeers Onboard ``` **Description:** ``` Walks the user through their first 5 minutes on VantagePeers Cloud: register identity, write first memory, recall it, create first task, list tools. Use only on first run. ``` **Instructions:** ``` You are guiding a brand-new user through their first VantagePeers Cloud session. GOAL: by the end of this conversation the user must have (1) registered an orchestrator identity, (2) stored at least one memory, (3) recalled it, (4) created at least one task, and (5) seen the list of available tools. PROCEDURE: 1. Ask the user for a single lowercase word to use as their orchestrator id. Suggest examples (first name, project name) but do not pick for them. Wait for their answer. 2. Call set_summary with orchestratorId=, instanceId=-web, summary="Onboarding VantagePeers Cloud". Show them the JSON response and explain what it means in one sentence. 3. Ask them what they want their first memory to say. Wait. Call store_memory namespace=project/-onboarding, type=reference, content=, createdBy=. Show the memoryId. 4. Call recall query= namespace=project/-onboarding limit=5. Show the match. 5. Ask them what they want their first task to be (title). Wait. Call create_task assignedTo=, createdBy=, priority=medium, title=, description="First task created via Onboard skill". 6. Call list_tasks assignedTo= status=todo. Confirm their task is there. 7. End by linking them to https://vantagepeers.com/docs/tools and offering to help with their next action. RULES: - Never invent values; always wait for the user's answer. - After every tool call, briefly explain (in one sentence) what just happened. - If a tool call returns 401/403, stop and tell them to check the Connect doc. - Do not invent placeholder names for the user's identity — always wait for their answer in step 1 and use that exact value everywhere. - Disable yourself (suggest the user turn this skill off) once step 7 is done. ``` Skill 2 — VantagePeers Agent [#skill-2--vantagepeers-agent] **Name:** ``` VantagePeers Agent ``` **Description:** ``` Operating model for a Claude conversation that uses VantagePeers as its long-term memory and task system. Activate this skill on every workspace conversation. ``` **Instructions:** ``` You operate inside VantagePeers Cloud. The custom connector "vantage-peers" exposes 84 MCP tools. Use them proactively — they are how you remember, coordinate and ship across sessions. IDENTITY: - The user has an orchestrator id (a lowercase label) declared via set_summary. If you do not know it, ask once at the start of the conversation, then never again. - All memories, tasks and messages the user creates must be attached to that identity. NAMESPACES: - `project/-...` for user-owned data (their tasks, their notes, their reference memories). - `global` for things the whole tenant can see (read-only by default for non-master clients). - Never write to `orchestrator/` — that is another tenant's scope, you will get 403. WHEN TO REACH FOR A TOOL: - The user shares a decision, a lesson, a snippet of context that should survive this conversation → store_memory (type=reference for facts, type=feedback for behavioral guidance, type=project for in-flight context). - The user mentions something they want to do later → create_task with a clear title and the right priority. - The user asks "what do I have on X?" → recall (semantic) or text_search (exact match) or hybrid_search (both). - The user wants to send something to another agent → send_message (channel=). - The user wraps up a working session → write_diary for the day, with highlights and blockers. - The user solved a bug → create_fix_pattern so future-them does not redo the work. OUTPUT DISCIPLINE: - After a tool call, summarize the result in one sentence — do not dump raw JSON unless asked. - If a tool returns nothing, say so explicitly ("recall returned 0 hits in your namespace"). - If a tool errors, surface the error code (401/403/timeout) and the obvious next step. DO NOT: - Invent ids — always read them from a tool response, never make up `mAbCdEf...`. - Call destructive tools (`delete_*`) without explicit user confirmation in the same turn. - Invent placeholder identities when illustrating examples — only refer to the actual orchestrator id the user declared. If something is unclear, ask one short clarifying question before calling a tool. ``` Troubleshooting the skills themselves [#troubleshooting-the-skills-themselves] * Claude does not use the skill → make sure it is toggled on for the conversation (**+** → **Skills**) and that the VantagePeers connector is also toggled on. * Claude calls the wrong tool → reset the conversation; skill instructions apply on each new turn but won't override a long stale context. * You changed your orchestrator id → restart with the Onboard skill so set\_summary captures the new value. --- # Architecture URL: /docs/core-concepts/architecture Architecture [#architecture] VantagePeers is a Convex-backed MCP server. Convex provides the database, serverless functions, vector indexes, and scheduling. The MCP layer exposes all capabilities as tools that Claude Code agents call natively. System Overview [#system-overview] ``` ┌─────────────────────────────────────────────────────────┐ │ Your Agent Team │ │ │ │ Agent A (Machine 1) Agent B (Machine 2) │ │ Claude Code + MCP Claude Code + MCP │ └──────────────┬───────────────────┬──────────────────────┘ │ MCP Protocol │ ▼ ▼ ┌─────────────────────────────────────────────────────────┐ │ VantagePeers MCP Server │ │ (Node.js process, runs locally per agent) │ │ │ │ 82 tools across 14 categories │ └──────────────────────────┬──────────────────────────────┘ │ Convex SDK ▼ ┌─────────────────────────────────────────────────────────┐ │ Convex Cloud Backend │ │ │ │ 20 database tables Vector indexes (memories) │ │ Serverless functions OpenAI embeddings pipeline │ │ Cron scheduler Real-time subscriptions │ └─────────────────────────────────────────────────────────┘ ``` Each agent runs its own local MCP server process. All agents share the same Convex deployment — that is how cross-machine coordination works. The Convex deployment is your single source of truth. Core Concepts [#core-concepts] Orchestrators [#orchestrators] An **orchestrator** is a named role in your agent team. Examples: `alice`, `bob`, `carol`. An orchestrator represents what the agent *does* — its responsibility in the system. Orchestrator names are used as identities for memory namespaces, message routing, task assignment, and agent profiles. When you store a memory with `createdBy: "alice"`, it is attributed to the `alice` orchestrator. When you send a message `from: "alice"` to `channel: "bob"`, the `bob` orchestrator receives it. Instances [#instances] An **instance** is a specific running copy of an orchestrator. If you run the `tau` orchestrator on two machines — a laptop and a server — they are two instances: `tau-laptop` and `tau-server`. Instances matter for message routing. You can send a message to all instances of an orchestrator (by role) or to a specific instance (by instance ID). This lets you target a specific machine when you need to. Namespaces [#namespaces] **Namespaces** scope memories and prevent cross-contamination between projects. A namespace is a string path like `global`, `project/vantage-starter`, or `orchestrator/tau`. Use `global` for knowledge that applies everywhere. Use `project/your-project` for project-specific context. Use `orchestrator/name` for agent-specific state. When calling `recall`, queries only search within the specified namespace by default. You can query across namespaces by omitting the namespace filter. Database Schema [#database-schema] VantagePeers uses 20 Convex tables. Each table has a defined schema with typed validators and indexes for efficient querying. memories [#memories] The core memory store. Each document contains: | Field | Type | Description | | ----------- | ---------- | -------------------------------------------------------- | | `namespace` | string | Scoping path (e.g., `global`, `project/foo`) | | `type` | string | `user`, `feedback`, `project`, `reference`, or `episode` | | `content` | string | The memory text content | | `createdBy` | string | Orchestrator that created the memory | | `embedding` | float64\[] | Vector embedding (OpenAI text-embedding-3-small) | | `archived` | boolean | Whether superseded by a newer memory | | `relatedTo` | string\[] | IDs of related memories | Vector index on `embedding` enables semantic similarity search. messages [#messages] Persistent message store for cross-agent communication: | Field | Type | Description | | ------------ | ------- | --------------------------------- | | `from` | string | Sender orchestrator ID | | `channel` | string | Target channel or role | | `content` | string | Message text | | `instanceId` | string? | Optional specific instance target | | `createdAt` | number | Unix timestamp | messageReceipts [#messagereceipts] Per-recipient read tracking: | Field | Type | Description | | --------------------- | ------- | ----------------------------------- | | `messageId` | string | Reference to message | | `recipient` | string | Recipient orchestrator ID | | `recipientInstanceId` | string? | Specific instance, if targeted | | `readAt` | number? | Timestamp when read, null if unread | tasks [#tasks] Task coordination table: | Field | Type | Description | | ---------------- | --------- | -------------------------------------------------- | | `title` | string | Task title | | `assignedTo` | string | Orchestrator responsible | | `status` | string | `todo`, `in_progress`, `review`, `blocked`, `done` | | `priority` | string | `low`, `medium`, `high`, `urgent` | | `missionId` | string? | Parent mission, if grouped | | `dependsOn` | string\[] | Task IDs that must complete first | | `blockedBy` | string? | Blocker description (set when status is `blocked`) | | `completionNote` | string? | What was done, set on completion | | `dueDate` | number? | Unix timestamp deadline | missions [#missions] Groups of related tasks with lifecycle tracking: | Field | Type | Description | | ------------ | ------- | ------------------------------------------------------- | | `title` | string | Mission name | | `status` | string | `brainstorm`, `plan`, `execute`, `validate`, `complete` | | `pilot` | string | Lead orchestrator | | `targetDate` | number? | Target completion timestamp | recurringTasks [#recurringtasks] Cron-based task templates: | Field | Type | Description | | ---------------- | ------- | ------------------------ | | `title` | string | Task title template | | `cronExpression` | string | Standard cron expression | | `assignedTo` | string | Default assignee | | `lastTriggered` | number? | Last creation timestamp | profiles [#profiles] Static identity and dynamic state per orchestrator instance: | Field | Type | Description | | ---------------------- | --------- | -------------------------- | | `orchestratorId` | string | Role name | | `instanceId` | string | Instance identifier | | `name` | string | Display name | | `static` | object | Immutable identity fields | | `static.role` | string | What this agent does | | `static.workspace` | string | Working directory path | | `static.capabilities` | string\[] | What this agent can do | | `dynamic` | object | Mutable runtime state | | `dynamic.currentTask` | string? | Active task description | | `dynamic.lastSeen` | number | Timestamp of last activity | | `dynamic.sessionCount` | number | Total sessions started | diary [#diary] Daily session logs: | Field | Type | Description | | -------------- | --------- | ------------------------------------ | | `date` | string | ISO date string (e.g., `2026-03-29`) | | `orchestrator` | string | Author | | `content` | string | Diary narrative | | `highlights` | string\[] | Key events of the day | briefingNotes [#briefingnotes] Structured meeting and decision records: | Field | Type | Description | | ---------------- | --------- | --------------------- | | `title` | string | Briefing subject | | `participants` | string\[] | Orchestrators present | | `decisions` | string\[] | Decisions made | | `linkedMemories` | string\[] | Related memory IDs | components [#components] Agent capability registry: | Field | Type | Description | | --------- | ------- | ---------------------------------- | | `name` | string | Component name | | `type` | string | `agent`, `skill`, `hook`, `plugin` | | `content` | string | Full content backup | | `version` | string? | Version identifier | MCP Protocol Integration [#mcp-protocol-integration] VantagePeers exposes all capabilities as MCP tools. The MCP server runs as a local Node.js process that the Claude Code client connects to via stdio. Every tool call goes through: 1. Claude Code sends a tool call JSON to the MCP server via stdio 2. The MCP server validates inputs and calls the appropriate Convex function via HTTP 3. Convex executes the function against the database (with vector search if applicable) 4. The result is returned to Claude Code as the tool response All 82 tools are stateless from the MCP server's perspective — state lives in Convex. This means you can restart the MCP server process at any time without losing data. --- # Multi-Tenancy URL: /docs/core-concepts/multi-tenancy Multi-Tenancy [#multi-tenancy] VantagePeers runs on a single Convex deployment. When multiple companies or teams share that deployment, you need isolation between tenants. This page describes the conventions that keep each tenant's data separate without requiring separate infrastructure. Memory Namespace Isolation [#memory-namespace-isolation] Memories are scoped by the `namespace` field. VantagePeers already supports `global`, `project/`, and `orchestrator/` namespaces. For tenant isolation, use the `workspace/` prefix. Convention [#convention] Use `workspace/{workspaceId}` as the namespace for tenant-scoped memories. ```json // Store a memory for Acme Corp { "namespace": "workspace/acme-corp", "type": "project", "content": "Acme Corp uses PostgreSQL 15 with pgvector for their product catalog.", "createdBy": "tau" } // Store a memory for Globex Corp { "namespace": "workspace/globex-corp", "type": "project", "content": "Globex Corp runs on MongoDB Atlas with a strict schema validation policy.", "createdBy": "tau" } ``` Recall with Workspace Scope [#recall-with-workspace-scope] When recalling, pass the workspace namespace to restrict results to that tenant: ```json { "query": "database setup", "namespace": "workspace/acme-corp" } ``` This returns only Acme Corp memories. Globex Corp memories are excluded. Workspace vs Project [#workspace-vs-project] | Prefix | Scope | Example | | --------------- | --------------------------------------- | ---------------------- | | `project/` | A specific repo, feature, or initiative | `project/landing-page` | | `workspace/` | An entire tenant/company | `workspace/acme-corp` | | `orchestrator/` | A single agent's private state | `orchestrator/tau` | | `global` | Shared across everything | `global` | You can combine them. An agent working on Acme Corp's landing page might store memories in `workspace/acme-corp` for company-wide context and `project/acme-landing-page` for feature-specific context. Task and Mission Project Isolation [#task-and-mission-project-isolation] Tasks and missions use the `project` field for scoping. For tenant isolation, use the `studio/` prefix. Convention [#convention-1] Use `studio/{workspaceId}` as the project value for tenant-scoped tasks and missions. ```json // Create a task scoped to Acme Corp { "title": "Migrate Acme product catalog to pgvector", "assignedTo": "tau", "priority": "high", "project": "studio/acme-corp" } // Create a mission scoped to Globex Corp { "title": "Globex API v2 rollout", "pilot": "pi", "project": "studio/globex-corp" } ``` When listing tasks, filter by project to see only that tenant's work: ```json { "project": "studio/acme-corp" } ``` Message tenantId Isolation [#message-tenantid-isolation] Messages and message receipts support an optional `tenantId` field for tenant-scoped communication. Sending with tenantId [#sending-with-tenantid] Pass `tenantId` when sending a message to scope it to a tenant: ```json { "from": "tau", "channel": "pi", "content": "Acme catalog migration complete. PR #112 ready for review.", "tenantId": "acme-corp" } ``` Checking with tenantId [#checking-with-tenantid] When checking messages, pass `tenantId` to receive only that tenant's messages: ```json { "recipient": "pi", "recipientInstanceId": "pi-main", "tenantId": "acme-corp" } ``` Backward Compatibility [#backward-compatibility] When `tenantId` is omitted, all messages are visible regardless of their tenant scope. This preserves backward compatibility and serves as an admin/global view. Agents that do not operate in a multi-tenant context can ignore `tenantId` entirely. Isolation Summary [#isolation-summary] | Table | Isolation mechanism | Convention | | ----------------- | ------------------- | ------------------------- | | `memories` | `namespace` field | `workspace/{workspaceId}` | | `tasks` | `project` field | `studio/{workspaceId}` | | `missions` | `project` field | `studio/{workspaceId}` | | `messages` | `tenantId` field | Tenant identifier string | | `messageReceipts` | `tenantId` field | Tenant identifier string | Example: Two Companies, One Deployment [#example-two-companies-one-deployment] Acme Corp and Globex Corp share a single Convex deployment. Here is how their data stays separate: ``` Acme Corp agent (tau): store_memory → namespace: "workspace/acme-corp" create_task → project: "studio/acme-corp" send_message → tenantId: "acme-corp" check_messages → tenantId: "acme-corp" Globex Corp agent (tau): store_memory → namespace: "workspace/globex-corp" create_task → project: "studio/globex-corp" send_message → tenantId: "globex-corp" check_messages → tenantId: "globex-corp" Admin agent (pi, no tenantId): recall → namespace omitted → sees all memories list_tasks → project omitted → sees all tasks check_messages → tenantId omitted → sees all messages ``` Both tenants use the same orchestrator names (`tau`, `pi`) and the same Convex tables. The namespace, project, and tenantId conventions ensure complete data isolation at the application layer. --- # Ship 24/7 doctrine URL: /docs/core-concepts/ship-24-7 Ship 24/7 doctrine [#ship-247-doctrine] A fleet workflow principle adopted on Day 83 of the VantageOS build (2026-05-27). Statement [#statement] **Never defer a ready ship on temporal grounds.** Time of day, day of week, weekend, "late evening", "pair signed off", "cron cancelled", "next session" are NOT valid reasons to defer a merge / deploy / publish. If a PR is mergeable and reviewed APPROVED → merge now. If a deploy is authorized → deploy now. If a fix is ready → ship now. Why [#why] A fleet running asynchronously across orchestrators can drift into "wait for the pair to come back online" patterns. That drift compounds: * Momentum lost: the context required to ship is freshest at the moment of approval. Hours later, re-loading that context is a tax. * Pipeline risk: an open mergeable PR sitting overnight is one merge conflict, one upstream change, or one CI break away from re-work. * Asymmetry: deferring is rarely reversible without cost; shipping is reversible (revert is a one-liner). Re-route, don't defer [#re-route-dont-defer] If the orchestrator scheduled to execute is offline, re-route the execution. Options: 1. **Pi (or any active orchestrator) executes directly** from their workspace using the canonical override tokens. 2. **Auto-task system + pre-created Pi authorization** for pickup by the target orchestrator at their next session start. 3. **Background subagent dispatch** if the work is bounded and the canonical tooling is available. The absence of a pair is not a reason to wait. It is a reason to choose a different execution path. What counts as a legitimate defer [#what-counts-as-a-legitimate-defer] There is one and only one category of legitimate defer: **client-constraint**. * Awaiting client confirmation (e.g. "post-RDV Marie", "after Anthony confirms repo source"). * Bound to an external deliverable (e.g. "after the Yousign signature is collected"). * Coordinated with a human review window (e.g. "after Laurent visual ack"). These defer the work because the external input is missing, not because the fleet is tired. Enforcement [#enforcement] Each workspace in the fleet runs a PreToolUse hook that scans the content of VantagePeers tool calls (`send_message`, `create_task`, `update_task`, `complete_task`) for temporal-defer language. Banned phrases include: * "defer to tomorrow / next session / weekend / monday-sunday" * "tard le soir → defer", "fin de journée → defer" * "sigma signed off → defer", "pair offline → defer" * "overnight risk → defer", "divergence main/prod → defer" * "wait until weekend / next session / next morning" * "ship tomorrow / tonight / this evening / next week" Allowed (client-constraint markers): * "RDV Marie ce soir", "post-RDV client" * "awaiting Marie confirm repo", "attente confirmation Anthony" Opt-out (rare emergencies only): `# allow-temporal-defer: ` in the content. Use sparingly — the default is ship now. For self-hosted VantagePeers users [#for-self-hosted-vantagepeers-users] This doctrine is opt-in. If you self-host VantagePeers and your team adopts a similar 24/7 ship cadence (or wants to), you can install the canonical hook in your Claude Code workspace: 1. Download `enforce-ship-24-7.py` from the VantageOS fleet hooks reference (see Tools section). 2. Place it in `.claude/hooks/enforce-ship-24-7.py` and `chmod +x`. 3. Register it in `.claude/settings.json` under PreToolUse matchers for the four VantagePeers tool calls. 4. Test with a banned phrase: `echo '{"tool_name":"mcp__vantage-peers__send_message","tool_input":{"content":"defer to tomorrow"}}' | python3 .claude/hooks/enforce-ship-24-7.py` should exit 2. The hook is fail-open: any internal exception passes through without blocking. It will never break your workflow. Related [#related] * [Fix Patterns](/docs/capabilities/fix-patterns) — capitalizing recurring fleet patterns. * [Tasks](/docs/capabilities/tasks) — the unit of fleet work this doctrine governs. --- # Add an Orchestrator URL: /docs/getting-started/add-orchestrator Add an Orchestrator [#add-an-orchestrator] Adding a new orchestrator to VantagePeers requires no code changes. Orchestrator names are open strings — use any name you want. Step 1: Choose a name [#step-1-choose-a-name] Pick a short, lowercase identifier for your orchestrator. Examples: `delta`, `gamma`, `atlas`, `nova`. Convention: Greek letters (`pi`, `tau`, `phi`, `sigma`, `omega`, `zeta`, `eta`) are used by the VantageOS team, but any string works. Step 2: Configure the MCP server [#step-2-configure-the-mcp-server] On the new orchestrator's machine, add VantagePeers to Claude Code with the same `CONVEX_URL`: ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` All orchestrators share one Convex backend. No per-agent deployment needed. Step 3: Create a profile [#step-3-create-a-profile] From the new orchestrator's Claude Code session: ``` update_profile( orchestratorId: "delta", name: "Delta", static: { role: "Data pipeline specialist", workspace: "/home/user/projects", capabilities: ["etl", "sql", "python"] }, dynamic: { currentTask: "Initial setup", lastSeen: Date.now(), sessionCount: 1 } ) ``` Step 4: Verify connectivity [#step-4-verify-connectivity] Test that the new orchestrator can communicate: ``` send_message( from: "delta", channel: "broadcast", content: "Delta online — connected to VantagePeers." ) ``` Other orchestrators will receive this on their next `check_messages`. Broadcast list [#broadcast-list] Any orchestrator with a profile receives broadcasts automatically. No code changes needed. The `broadcast` channel dynamically queries the `profiles` table, so as soon as Step 3 is complete your new orchestrator is included. For direct messaging, use the orchestrator name as the channel. Instance IDs [#instance-ids] If you run multiple instances of the same orchestrator (e.g., `delta-laptop` and `delta-server`), use `fromInstanceId` and `recipientInstanceId` to target specific instances: ``` send_message( from: "delta", fromInstanceId: "delta-laptop", channel: "delta", content: "Message to any delta instance" ) ``` --- # Deploy Keys URL: /docs/getting-started/deploy-keys Deploy Keys [#deploy-keys] Deploy keys allow external services to call Convex functions directly, without going through the MCP server. Use them for server-to-server integrations such as CI/CD pipelines, cron jobs, webhooks, and custom dashboards. What are deploy keys? [#what-are-deploy-keys] A deploy key is a credential that authenticates server-side code against your Convex deployment. Unlike MCP tools (which are designed for AI agents), deploy keys let any backend service call `fetchQuery` and `fetchMutation` with full type safety via the `vantage-peers-mcp` package. Generate a deploy key [#generate-a-deploy-key] 1. Open the [Convex dashboard](https://dashboard.convex.dev) 2. Select your VantagePeers deployment 3. Go to **Settings > Deploy Keys** 4. Click **Generate Deploy Key** 5. Copy the key immediately -- it will not be shown again Environment variable setup [#environment-variable-setup] Store the deploy key as an environment variable. Never hardcode it in source files. ```bash # Production CONVEX_DEPLOY_KEY=prod:your-deploy-key-here # Development (if using a separate dev deployment) CONVEX_DEPLOY_KEY=dev:your-dev-deploy-key-here ``` For hosted environments, add it through your platform's secrets manager (Vercel Environment Variables, AWS Secrets Manager, GitHub Actions secrets, etc.). Usage with ConvexHttpClient [#usage-with-convexhttpclient] Use `ConvexHttpClient` from the `convex/browser` package for general-purpose server-to-server calls: ```typescript import { ConvexHttpClient } from "convex/browser"; import { api } from "vantage-peers-mcp/api"; const client = new ConvexHttpClient(process.env.CONVEX_URL!); // Query memories with full type safety const memories = await client.query(api.memories.listMemories, { namespace: "global", limit: 10, }); // Send a message await client.mutation(api.messages.sendMessage, { from: "studio", channel: "sigma", content: "Deployment complete", }); ``` Usage with fetchQuery (Next.js) [#usage-with-fetchquery-nextjs] For Next.js server components and route handlers, use `fetchQuery` and `fetchMutation` from `convex/nextjs`: ```typescript import { fetchQuery, fetchMutation } from "convex/nextjs"; import { api } from "vantage-peers-mcp/api"; // In a Server Component or Route Handler const tasks = await fetchQuery( api.tasks.listTasks, { status: "in_progress" }, { url: process.env.CONVEX_URL } ); // Mutate from a server action await fetchMutation( api.tasks.completeTask, { taskId: "k17..." }, { url: process.env.CONVEX_URL } ); ``` Both `fetchQuery` and `fetchMutation` read `CONVEX_DEPLOY_KEY` from the environment automatically when running server-side. Security best practices [#security-best-practices] * **Never commit deploy keys to git.** Add `CONVEX_DEPLOY_KEY` to your `.gitignore` and `.env` files, not to source code. * **Use separate keys for dev and prod.** Generate distinct deploy keys for each environment so revoking one does not affect the other. * **Rotate keys regularly.** Generate a new key, update your environment, verify the new key works, then revoke the old one. * **Restrict access.** Only give deploy keys to services that need direct Convex access. For AI agents, use the MCP server instead. * **Audit usage.** Monitor your Convex dashboard logs to verify that deploy key traffic matches expected patterns. --- # Getting Started URL: /docs/getting-started Getting Started [#getting-started] VantagePeers deploys in five steps: clone, authenticate, deploy, configure environment variables, and set up the MCP server. No infrastructure to manage beyond a Convex account. Prerequisites [#prerequisites] Before you begin, you need: * **Node.js 18+** — for running the Convex CLI * **A Convex account** — free tier at [convex.dev](https://convex.dev). No credit card required. * **Claude Code** — the primary MCP client VantagePeers is built for * **An OpenAI API key** — used exclusively for generating vector embeddings (`text-embedding-3-small`). Cost is approximately $0.02 per 1M tokens. Installation [#installation] Step 1: Clone the repository [#step-1-clone-the-repository] ```bash git clone https://github.com/vantageos-agency/vantage-peers.git cd vantage-peers npm install ``` Step 2: Log in to Convex [#step-2-log-in-to-convex] ```bash npx convex login ``` This opens a browser window to authenticate with your Convex account. If you don't have an account yet, create one at [convex.dev](https://convex.dev) — the free tier is sufficient. Step 3: Deploy to Convex [#step-3-deploy-to-convex] ```bash npx convex deploy ``` This deploys all 20 database tables, serverless functions, and vector indexes to your Convex account. Convex will output your deployment URL — copy it. Step 4: Set environment variables [#step-4-set-environment-variables] Set the following in the **Convex dashboard** (Settings → Environment Variables): | Variable | Required | Description | | ---------------------- | -------- | -------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | Yes | OpenAI API key for vector embeddings (`text-embedding-3-small`) | | `BEARER_SECRET_MASTER` | Yes | Auth token for the MCP server — all calls return "Unauthorized" without it | | `VP_LICENSE_KEY` | Yes | License key for VantagePeers — all tool calls return 403 without it | **Generating `BEARER_SECRET_MASTER`:** This must be a random string of 32+ characters. Generate one with: ```bash openssl rand -hex 32 ``` > **About the OpenAI API key:** VantagePeers uses `text-embedding-3-small` to generate vector embeddings for semantic search. Without this key, memories will store correctly but `recall` will return empty results. The cost is approximately $0.02 per 1M tokens — typical usage is under $1/month. Optionally, if you need a local `.env.local` file for development: ```bash cp .env.example .env.local ``` Open `.env.local` and set: ```bash # Your Convex deployment URL (from Step 3 output) CONVEX_URL=https://your-deployment.convex.cloud # API key for vector embeddings (required for recall/search) AI_GATEWAY_API_KEY=sk-... ``` > **Note:** The `.env.local` file is optional for most setups. The MCP server configuration (Step 5) passes `CONVEX_URL` directly, and `AI_GATEWAY_API_KEY` is set in the Convex dashboard. Step 5: Configure the MCP server [#step-5-configure-the-mcp-server] Add VantagePeers to your Claude Code MCP configuration. Open `~/.claude.json` (global) or your project's `.claude/settings.json` and add: ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud", "VP_LICENSE_KEY": "" } } } } ``` Restart Claude Code. VantagePeers tools will appear in the tool list. Claude Code Web [#claude-code-web] VantagePeers also works with [Claude Code Web](https://claude.ai/code) (formerly claude.ai). To configure: 1. Open Claude Code Web at [claude.ai/code](https://claude.ai/code) 2. Go to **Settings → MCP Servers** 3. Click **Add Server** 4. Enter the following: * **Name:** `vantage-peers` * **Command:** `npx` * **Arguments:** `-y vantage-peers-mcp` * **Environment Variables:** `CONVEX_URL=https://your-deployment.convex.cloud` and `VP_LICENSE_KEY=` 5. Save and verify tools appear in the tool list The same MCP server works in Claude Code CLI, Claude Code Web, and the VS Code / JetBrains extensions. Quick Start [#quick-start] Once connected, verify everything works by running these two operations from within Claude Code. Store your first memory [#store-your-first-memory] Call `store_memory` with: ```json { "namespace": "global", "type": "project", "content": "VantagePeers is now connected and operational.", "createdBy": "my-agent" } ``` You should receive a memory ID in response. Recall it back [#recall-it-back] Call `recall` with: ```json { "query": "VantagePeers connected", "namespace": "global", "limit": 5 } ``` You should see the memory you just stored returned as the top result. Send your first message [#send-your-first-message] Call `send_message` with: ```json { "from": "my-agent", "channel": "broadcast", "content": "Agent online and ready." } ``` Check for messages [#check-for-messages] Call `check_messages` with: ```json { "recipient": "my-agent" } ``` You should see the message listed with its receipt ID and read status. Verification [#verification] To confirm your full deployment is healthy, check the Convex dashboard at [dashboard.convex.dev](https://dashboard.convex.dev). You should see: * 20 tables in the Data section: `memories`, `messages`, `messageReceipts`, `tasks`, `missions`, `recurringTasks`, `profiles`, `diary`, `briefingNotes`, `components`, `fixPatterns`, `fixAttempts`, `issues`, `issueStats`, `mandates`, `businessUnits`, `missionTemplates`, `githubRepoMapping`, `monitoredDeployments`, `errorLogs` * Your recent function calls in the Functions section * Vector indexes active on the `memories` table If any table is missing, re-run `npx convex deploy` to apply the full schema. Next Steps [#next-steps] * Read [Architecture](/docs/core-concepts/architecture) to understand how orchestrators, instances, and namespaces work * Read [Memory](/docs/capabilities/memory) to learn how to organize knowledge across agents * Read [Tasks](/docs/capabilities/tasks) to set up task coordination between agents --- # Quickstart: 15 Minutes to First Message URL: /docs/getting-started/quickstart Quickstart: 15 Minutes to First Message [#quickstart-15-minutes-to-first-message] Two agents. Shared memory. Real messages. Fifteen minutes. Step 1: Deploy the backend [#step-1-deploy-the-backend] ```bash git clone https://github.com/vantageos-agency/vantage-peers.git cd vantage-peers npm install ``` Authenticate with Convex (opens a browser window — press Ctrl+C after the login completes): ```bash npx convex dev ``` Once authenticated, deploy the backend: ```bash npx convex deploy ``` Convex outputs your deployment URL. Copy it — you'll need it next. Set the required environment variables: ```bash # API key for vector embeddings npx convex env set AI_GATEWAY_API_KEY sk-your-key-here # Auth token for MCP server (generate with: openssl rand -hex 32) npx convex env set BEARER_SECRET_MASTER your-random-secret-here ``` Step 2: Configure Agent A (Alice) [#step-2-configure-agent-a-alice] Open Claude Code settings (`~/.claude.json` or your project's `.claude/settings.json`) and add: ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud", "VP_LICENSE_KEY": "" } } } } ``` Restart Claude Code. You should see VantagePeers tools in the tool list. Step 3: Agent A (Alice) stores a memory [#step-3-agent-a-alice-stores-a-memory] From Agent A (Alice)'s Claude Code session: ```json { "namespace": "global", "type": "project", "content": "Project kickoff: building a REST API with FastAPI. Target: MVP by Friday.", "createdBy": "alice" } ``` Response: `{ "memoryId": "k17..." }` Step 4: Agent A (Alice) sends a message [#step-4-agent-a-alice-sends-a-message] ```json { "from": "alice", "channel": "bob", "content": "Hey Bob — I stored the project brief in global memory. Start on the database schema." } ``` Response: `{ "messageId": "jn7..." }` Step 5: Configure Agent B (Bob) [#step-5-configure-agent-b-bob] Open a second terminal window (or a second VS Code instance) and start a new Claude Code session. Use the same `CONVEX_URL` — both sessions share one backend. Add the same MCP config from Step 2. Step 6: Agent B (Bob) checks messages [#step-6-agent-b-bob-checks-messages] From Agent B (Bob)'s Claude Code session: ```json { "recipient": "bob" } ``` Response: ```json [ { "from": "alice", "content": "Hey Bob — I stored the project brief in global memory. Start on the database schema.", "receiptId": "k97..." } ] ``` Step 7: Agent B (Bob) recalls the memory [#step-7-agent-b-bob-recalls-the-memory] ```json { "query": "project brief MVP", "namespace": "global", "limit": 3 } ``` Response includes the memory Agent A (Alice) stored — with semantic search ranking. Step 8: Agent B (Bob) marks the message as read [#step-8-agent-b-bob-marks-the-message-as-read] ```json { "receiptIds": ["k97..."] } ``` Done. Two agents, shared memory, real messaging, read receipts. No file hacks. No polling. No duct tape. What just happened [#what-just-happened] 1. **One Convex deployment** serves as the shared backend for both agents 2. **store\_memory** persisted a vector-embedded memory that any agent can recall 3. **send\_message** delivered a message from Alice to Bob with a receipt 4. **recall** used semantic search to find relevant memories — not keyword matching 5. **mark\_as\_read** confirmed Bob processed the message Iterating large list results [#iterating-large-list-results] Every `list_*` tool (including `list_tasks`, `list_memories`, `list_messages`) returns a cursor envelope when there are more results beyond the current page: ```json { "items": [...], "nextCursor": "eyJjcmVhdGVkQmVmb3JlIjoxNzUxMDIwODAwMDAwfQ" } ``` Pass `nextCursor` as the `cursor` argument on the next call. When `nextCursor` is absent, there are no more pages. TypeScript drain loop: ```typescript let cursor: string | undefined = undefined; const allTasks: unknown[] = []; do { const result = await client.callTool({ name: "list_tasks", arguments: { assignedTo: "alice", status: "active", fields: "lite", limit: 200, ...(cursor !== undefined ? { cursor } : {}), }, }); const envelope = JSON.parse(result.content[0].text); allTasks.push(...envelope.items); cursor = envelope.nextCursor; } while (cursor !== undefined); ``` Default page size is 20 rows. Hard cap is 200. Pass `fields: "lite"` for efficient drain loops. See [Cursor Pagination](/docs/pagination) for full documentation and the 18-tool coverage matrix. Next steps [#next-steps] * Add [tasks](/docs/capabilities/tasks) so agents can assign work to each other * Set up [recurring tasks](/docs/capabilities/recurring-tasks) for cron-based automation * Read the full [architecture](/docs/core-concepts/architecture) to understand orchestrators, instances, and namespaces * Browse the full [tools catalogue](/docs/tools-catalogue) — 120 tools across 19 domains * Review [envelope safety](/docs/envelope-safety) before building drain loops in production --- # Supported Tools URL: /docs/getting-started/supported-tools Supported Tools [#supported-tools] VantagePeers is an MCP server. It works with any tool that supports the [Model Context Protocol](https://modelcontextprotocol.io). No vendor lock-in. Full MCP Support [#full-mcp-support] These tools have native MCP client support — add VantagePeers as a server and all 82 tools are immediately available. Claude Code [#claude-code] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: `~/.claude.json` or `.claude/settings.json` Cursor [#cursor] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: `.cursor/mcp.json` Codex (OpenAI) [#codex-openai] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: `~/.codex/config.json` Windsurf [#windsurf] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: `~/.codeium/windsurf/mcp_config.json` Cline [#cline] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: VS Code settings → Cline MCP Servers Roo Code [#roo-code] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: VS Code settings → Roo Code MCP Servers OpenCode [#opencode] ```toml [mcp.vantage-peers] command = "npx" args = ["-y", "vantage-peers-mcp"] [mcp.vantage-peers.env] CONVEX_URL = "https://your-deployment.convex.cloud" ``` Config file: `opencode.toml` Amazon Q Developer [#amazon-q-developer] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: `~/.aws/amazonq/mcp.json` Augment Code [#augment-code] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: VS Code settings → Augment MCP Servers Void [#void] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Config file: Void MCP settings Agent-Mode Only [#agent-mode-only] These tools support MCP in agent mode but not in inline/chat mode. Continue.dev [#continuedev] ```json { "experimental": { "modelContextProtocolServers": [ { "transport": { "type": "stdio", "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } ] } } ``` Config file: `~/.continue/config.json` GitHub Copilot [#github-copilot] ```json { "mcp": { "servers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } } ``` Config file: `.github/copilot-mcp.json` — requires agent mode Environment Variable [#environment-variable] All configurations require one environment variable: | Variable | Value | Description | | ------------ | -------------------------------------- | ----------------------------------------------------- | | `CONVEX_URL` | `https://your-deployment.convex.cloud` | Your Convex deployment URL (from `npx convex deploy`) | The MCP server resolves this at startup. No other configuration is needed — the server connects to your Convex backend and exposes all 82 tools automatically. --- # Business Units URL: /docs/infrastructure/business-units Business Units [#business-units] The business units table tracks organizational entities with their strategy, services, pricing, revenue projections, and KPIs. Schema [#schema] | Field | Type | Description | | -------------------- | ------------------------------------------- | ------------------------------ | | `name` | string | BU name (e.g., "VantagePeers") | | `description` | string | What it does | | `purpose` | string | Why it exists | | `domain` | string? | Website domain | | `orchestratorId` | string | Lead orchestrator | | `status` | `idea` \| `building` \| `live` \| `revenue` | Current stage | | `businessModel` | string | How it makes money | | `targetCustomers` | string | Who it serves | | `services` | string\[] | What it offers | | `pricing` | string | Pricing strategy | | `revenueProjections` | object | Y1, Y2, Y3 revenue targets | | `coreTeam` | object | Agents, skills, hooks, plugins | | `managementFee` | number | Percentage cut (default 10%) | MCP Tools [#mcp-tools] | Tool | Description | | ----------- | ----------------------------------------- | | `create_bu` | Create a business unit with full strategy | | `update_bu` | Update business unit fields | | `get_bu` | Fetch a business unit by ID | | `list_bus` | List all BUs with optional filters | | `delete_bu` | Delete a business unit | --- # Component Registry URL: /docs/infrastructure/components Component Registry [#component-registry] The component registry stores a versioned backup of every agent, skill, hook, and plugin you ship. Each entry holds the full file content, so the registry doubles as both an inventory (what exists, where, owned by whom) and a recovery surface (rebuild any component byte-for-byte after a disk loss or accidental deletion). Why use it [#why-use-it] * **Survives filesystem loss.** If a workspace gets wiped or a developer machine fails, the registry has the canonical copy. * **Single source of truth across the fleet.** Multiple orchestrators on multiple machines reference the same components by name — versioned, scoped per project, attributable to a creator. * **Team-scoped permissions.** Entries carry a `team` field so you can ship a `development` library separate from a `marketing` library and grant access accordingly. When to register [#when-to-register] Register a component whenever you ship a new agent, skill, hook, or plugin that other agents or workspaces will consume. Typical triggers: a new orchestrator joins the fleet and needs the team's skill library; a hook gets battle-tested and graduates from one workspace to the shared baseline; a plugin reaches v1 and needs distribution. Component Types [#component-types] | Type | Description | | -------- | ---------------------------- | | `agent` | Autonomous agent definitions | | `skill` | Slash-command skills | | `hook` | Event-driven hooks | | `plugin` | Plugin bundles | MCP Tools [#mcp-tools] register_component [#register_component] ```json { "name": "dev-convex-expert", "type": "agent", "team": "development", "content": "Full agent file content here...", "version": "1.0.0", "project": "vantage-peers", "createdBy": "carol" } ``` list_components [#list_components] ```json { "type": "agent", "team": "development" } ``` get_component [#get_component] ```json { "name": "dev-convex-expert", "type": "agent" } ``` --- # Error Monitoring URL: /docs/infrastructure/error-monitoring Error Monitoring [#error-monitoring] VantagePeers proactively monitors your Convex deployments for errors. When an error is detected, a GitHub issue is automatically created and the Issue Resolution Protocol takes over. How It Works [#how-it-works] A cron job runs every 5 minutes, polling each monitored deployment's error logs via the Convex REST API. New errors are deduplicated by function name + error message, and unique errors trigger automatic GitHub issue creation. ``` Cron (every 5 min) | v Poll each deployment's error logs | v New error detected? ──No──> Skip (dedup by hash) | Yes v Create GitHub issue with stack trace | v IRP webhook triggers (auto-comment + 14-task mission) ``` Adding a Deployment [#adding-a-deployment] Register a deployment to monitor via MCP: ```json // add_deployment { "name": "myreeldream", "deploymentUrl": "https://calm-gerbil-63.convex.cloud", "deployKeyEnvVar": "DEPLOY_KEY_MYREELDREAM", "githubRepo": "myreeldream-ai/MyShortReel-beta", "orchestrator": "dave" } ``` Then set the deploy key as a Convex environment variable: ```bash npx convex env set DEPLOY_KEY_MYREELDREAM=your-admin-deploy-key ``` Deduplication [#deduplication] Errors are deduplicated using a hash of `functionName + errorMessage`. If the same error is seen again within an existing record, the count and `lastSeen` timestamp are updated without creating a duplicate issue. MCP Tools [#mcp-tools] | Tool | Description | | ------------------- | ------------------------------------------------------- | | `add_deployment` | Register a Convex deployment to monitor | | `remove_deployment` | Stop monitoring a deployment | | `list_errors` | List detected errors, optionally filtered by deployment | | `get_error` | Get full error details including stack trace | Integration with IRP [#integration-with-irp] When the error monitor creates a GitHub issue, the existing webhook pipeline handles the rest: 1. Issue created with `[Auto]` prefix and `bug` + `auto-detected` labels 2. Webhook triggers IRP: auto-comment + 14-task mission 3. Assigned orchestrator receives the mission and begins resolution This means errors are detected and assigned before users report them. --- # External Issue Tracking URL: /docs/infrastructure/external-tracking External Issue Tracking [#external-issue-tracking] VantagePeers tracks issues and PRs on external GitHub repos. This enables coordinated open-source contributions — an orchestrator (Zeta) fixes bugs on third-party projects while Pi monitors PR status. Workflow [#workflow] ``` Pi identifies issue on external repo | v /track-external-issue {repo} {number} | v Issue created in VantagePeers (with external fields) | v Mission created from repo-fix-v1 template (10 tasks) | v Zeta receives notification + starts working | v Zeta submits PR → prStatus updated | v PR Monitor cron polls hourly → notifies Pi on merge/close ``` External Issue Fields [#external-issue-fields] | Field | Type | Description | | --------------------- | ----------------------------------------- | ------------------------------------------------- | | `externalRepo` | string | Third-party repo (e.g., `get-convex/better-auth`) | | `externalIssueNumber` | number | Issue number on the external repo | | `externalIssueUrl` | string | Full URL to the issue | | `prUrl` | string | URL of the submitted PR | | `prStatus` | `draft` \| `open` \| `merged` \| `closed` | Current PR state | | `forkRepo` | string | Our fork (e.g., `elpiarthera/better-auth`) | PR Monitor Cron [#pr-monitor-cron] A cron runs every hour and checks all external issues with `prStatus = open` or `draft`. For each: 1. Fetches PR state from GitHub API 2. If merged → updates `prStatus` to `merged`, notifies Pi 3. If closed without merge → updates to `closed`, notifies Pi No manual checking needed — Pi gets a message when any PR changes state. Tools [#tools] External issue tracking uses the standard VantagePeers tools: `create_task`, `update_task`, and `list_tasks` with appropriate tags. There are no dedicated external-tracking MCP tools — the `/track-external-issue` skill below handles the full workflow. Skill: /track-external-issue [#skill-track-external-issue] Usage: `/track-external-issue {owner/repo} {issue_number}` The skill automates the full workflow: fetches the issue from GitHub, creates it in VantagePeers, creates a mission from the repo-fix-v1 template, and notifies Zeta. --- # Issue Resolution Protocol URL: /docs/infrastructure/issue-resolution Issue Resolution Protocol [#issue-resolution-protocol] When a GitHub issue is opened on a mapped repository, VantagePeers automatically creates a mission with 14 tasks following the Issue Resolution Protocol (IRP). The assigned orchestrator works through each step, with progress comments posted back to GitHub. How It Works [#how-it-works] ``` GitHub Issue Opened | v Webhook receives event | v Auto-comment: "Investigating - assigned to {orchestrator}" | v Mission created with 14 tasks (from template) | v Orchestrator executes steps T0-T13 | v Auto-comments at T6, T8, T11 | v Issue closed with fix deployed ``` The 14 Steps (T0-T13) [#the-14-steps-t0-t13] | Step | Title | Description | Auto-Comment | | ---- | -------------------- | --------------------------------------------------- | ---------------------------------------------- | | T0 | Acknowledge | Auto-posted GitHub comment | "Investigating - assigned to `{orchestrator}`" | | T1 | KB Search | Search fix patterns and episodes for similar issues | | | T2 | Verify Config | Verify environment and configuration | | | T3 | Identify Tests | Find test suites related to the component | | | T4 | Run Existing Tests | Run tests, document PASS/FAIL | | | T5 | Evaluate Coverage | Do tests cover the bug? | | | T6 | Write Missing Tests | Write test that reproduces the bug | "Bug reproduced in test suite" | | T7 | Fix | Delegate fix to specialist agent | | | T8 | Run ALL Tests | Full suite, 0 regressions | "Fix ready. All tests pass" | | T9 | Code Review | Review the diff | | | T10 | Deploy Dev + Push | Deploy to dev, push branch | | | T11 | Verification Preview | Test on preview, human confirmation | "Fixed and deployed to production" | | T12 | Update KB | Store fix pattern in VantagePeers | | | T13 | Close Issue | Close the GitHub issue | | GitHub Auto-Comments [#github-auto-comments] VantagePeers posts 4 comments on the GitHub issue automatically: 1. **On open**: "Investigating - assigned to `{orchestrator}`" 2. **After T6**: "Bug reproduced in test suite. Root cause identified." 3. **After T8**: "Fix ready. All tests pass including new regression test." 4. **After T11**: "Fixed and deployed to production. Regression test added." Customizing the Template [#customizing-the-template] The IRP template is stored in the `missionTemplates` table and can be modified via MCP tools: View current template [#view-current-template] ```json // get_mission_template { "name": "issue-resolution-v2" } ``` Update steps [#update-steps] ```json // update_mission_template { "name": "issue-resolution-v2", "steps": [ { "title": "Acknowledge", "description": "Auto-posted GitHub comment" }, { "title": "KB Search", "description": "Search fixPatterns for similar issues" } ], "createdBy": "carol" } ``` You can add, remove, or reorder steps. Changes take effect on the next issue opened. GitHub Webhook Setup [#github-webhook-setup] 1\. Configure webhook on GitHub [#1-configure-webhook-on-github] In your repo settings, add a webhook: * **URL**: `https://your-deployment.convex.site/github/webhook` * **Content type**: `application/json` * **Events**: Issues, Issue comments, Pull requests, Pull request reviews * **Secret**: Match your `GITHUB_WEBHOOK_SECRET` env var 2\. Map repo to orchestrator [#2-map-repo-to-orchestrator] ```json // add_repo_mapping { "repo": "your-org/your-repo", "orchestrator": "dave", "project": "your-project" } ``` 3\. Set environment variables [#3-set-environment-variables] ```bash npx convex env set GITHUB_TOKEN=ghp_your_token npx convex env set GITHUB_WEBHOOK_SECRET=your_secret ``` The `GITHUB_TOKEN` needs `repo` scope to post comments. The webhook secret validates incoming requests. --- # Issue Resolution Stats URL: /docs/infrastructure/issue-stats Issue Resolution Stats [#issue-resolution-stats] VantagePeers calculates issue resolution metrics daily via a cron job. The stats power the sales page and track Mean Time To Resolution (MTTR) across all monitored repos. How It Works [#how-it-works] A daily cron (6am UTC) fetches issues from the GitHub API for each mapped repo, calculates time-to-first-response and time-to-fix, and stores the results in the `issueStats` table. Key Metrics [#key-metrics] | Metric | Description | | --------------------------- | ------------------------------------------ | | `medianTimeToFirstResponse` | Minutes from issue opened to first comment | | `medianTimeToFix` | Minutes from issue opened to issue closed | | `fastestResolution` | Fastest fix across all issues (minutes) | | `slowestResolution` | Slowest fix (minutes) | | `avgTimeToFix` | Average fix time (minutes) | Before/After VantageOS Era [#beforeafter-vantageos-era] Stats are split at the pivot date (April 1, 2026) to show the impact of the VantageOS Team: ```json { "beforeVantageOS": { "totalIssues": 19, "resolvedIssues": 15, "medianTimeToFix": 5792 }, "afterVantageOS": { "totalIssues": 27, "resolvedIssues": 25, "medianTimeToFix": 28 } } ``` Before: median 4 days. After: median 28 minutes. 207x improvement. Querying Stats [#querying-stats] ```json { "project": "vantage-peers" } ``` Returns daily snapshots with all metrics. Use for dashboards, sales pages, or internal monitoring. Cron Schedule [#cron-schedule] The cron runs daily at 6am UTC. It iterates all active repo mappings and calculates stats for each. Results are upserted — running manually updates the same day's entry. --- # GitHub Issues URL: /docs/infrastructure/issues GitHub Issues [#github-issues] VantagePeers tracks GitHub issues with a full lifecycle from open to verified. Issues are synced via webhooks and can be auto-linked to tasks when they are completed. Issue Lifecycle [#issue-lifecycle] ``` open → in_progress → fixed → verified → closed ``` | Status | Description | | ------------- | ---------------------------------------------- | | `open` | Issue reported, not yet being worked on | | `in_progress` | An agent is actively working on it | | `fixed` | A fix has been applied (with commit reference) | | `verified` | Fix confirmed working | | `closed` | Issue resolved and closed | Repo Mappings [#repo-mappings] Before issues can be tracked, map GitHub repos to orchestrators: ```json // add_repo_mapping { "repo": "myreeldream-ai/MyShortReel-beta", "orchestrator": "dave", "project": "myreeldream" } ``` This tells VantagePeers which agent handles issues from which repo. Auto-Link: Tasks to Issues [#auto-link-tasks-to-issues] When a task title contains `#NNN` (e.g., `Fix #282 — credit race condition`), completing that task automatically: 1. **Links the task** to issue #NNN via `linkedTaskIds` 2. **Extracts commit SHAs** from the completion note 3. **Updates issue status** to `fixed` if the note contains "fix", "fixed", or a commit hash This means agents can close issues just by completing tasks with the right title format. MCP Tools [#mcp-tools] list_issues [#list_issues] ```json { "project": "myreeldream", "status": "open", "limit": 20 } ``` get_issue [#get_issue] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282 } ``` update_issue_status [#update_issue_status] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282, "status": "in_progress" } ``` link_commit_to_issue [#link_commit_to_issue] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282, "commitSha": "abc1234", "fixedBy": "dave" } ``` verify_issue [#verify_issue] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282, "verifiedBy": "carol" } ``` issue_stats [#issue_stats] Get counts grouped by status: ```json { "project": "myreeldream" } ``` Returns: `{ "open": 23, "in_progress": 5, "fixed": 12, "verified": 8, "closed": 47 }` Repo Management [#repo-management] | Tool | Description | | --------------------- | ------------------------------------------------ | | `add_repo_mapping` | Map a GitHub repo to an orchestrator and project | | `list_repo_mappings` | List all active repo mappings | | `remove_repo_mapping` | Remove a repo mapping | --- # Mission Templates URL: /docs/infrastructure/mission-templates Mission Templates [#mission-templates] Mission templates define standardized workflows that auto-create missions with predefined tasks. When an event triggers (GitHub issue opened, external issue tracked), VantagePeers creates a full mission with all steps pre-populated. Available Templates [#available-templates] issue-resolution-v2 [#issue-resolution-v2] The Issue Resolution Protocol. Auto-created when a GitHub issue is opened on a mapped repo. **14 steps (T0-T13):** Acknowledge → KB Search → Verify Config → Identify Tests → Run Existing Tests → Evaluate Coverage → Write Missing Tests → Fix → Run ALL Tests → Code Review → Deploy + Push → Verification Preview → Update KB → Close Issue Auto-comments posted to GitHub at steps T1 (acknowledge), T6 (bug reproduced), T8 (fix ready), T11 (deployed). repo-fix-v1 [#repo-fix-v1] For fixing issues on external third-party repos. Used by Zeta for open-source contributions. **10 steps:** Search KB → Codebase Analysis → Issue Diagnosis → Impact Analysis → Write Fix + Tests → Run Tests → Code Review → Create PR + Comment Issue → QA Verification → Store Fix Pattern Includes mandatory Impact Analysis (grep all downstream consumers of changed data) and PRE-FIX protocol (read CONTRIBUTING.md, 5 recent PRs, identify conventions). new-feature-v1 [#new-feature-v1] For building new features with specialist delegation. Each step has an assigned specialist agent. **10 steps:** Search KB → Requirements Analysis → Schema + Backend (dev-convex-expert) → API/External Services (dev-fal-expert) → Frontend UI (dev-frontend) → i18n (translator) → Tests + QA (dev-qa) → Code Review (code-reviewer) → PR + Deploy Preview → Store Pattern KB MCP Tools [#mcp-tools] get_mission_template [#get_mission_template] ```json { "name": "issue-resolution-v2" } ``` Returns the full template with all steps, tags, and metadata. update_mission_template [#update_mission_template] ```json { "name": "repo-fix-v1", "steps": [ { "title": "Search KB", "description": "...", "tags": ["kb"] }, { "title": "Codebase Analysis", "description": "...", "tags": ["research"] } ], "createdBy": "carol" } ``` Creating Custom Templates [#creating-custom-templates] Templates are stored in the `missionTemplates` table. Each template has: | Field | Type | Description | | ------------- | ------- | --------------------------------------------- | | `name` | string | Unique template name | | `description` | string | What this template is for | | `steps` | array | Ordered list of task definitions | | `isDefault` | boolean | Whether this is the default for auto-creation | | `createdBy` | string | Who created/updated it | Each step has `title`, `description`, and optional `tags` array. --- # Orchestrator Signatures URL: /docs/infrastructure/signatures Orchestrator Signatures [#orchestrator-signatures] Every commit, PR, and GitHub comment from the VantageOS Team includes a standardized signature. This is enforced mechanically via git hooks and Claude Code hooks. Signature Format [#signature-format] ``` Orchestrator: Sigma — VantageOS Team Infra | 2026-04-06 14:32 ``` | Component | Description | | ----------------------- | -------------------------------------- | | `Orchestrator: {Name}` | Capitalized orchestrator name | | `VantageOS Team {Role}` | Team suffix based on orchestrator role | | `YYYY-MM-DD HH:MM` | Date and time of the commit/action | Team Roles [#team-roles] | Orchestrator | Team Suffix | | ------------ | ----------------------- | | Pi | VantageOS Team Lead | | Sigma | VantageOS Team Infra | | Omega | VantageOS Team Dev | | Tau | VantageOS Team Frontend | | Phi | VantageOS Team Product | | Zeta | VantageOS Team Dev | Commit Hook [#commit-hook] A `commit-msg` git hook automatically: 1. Replaces `Co-Authored-By: Claude...` with the VantageOS signature 2. Removes `Generated with Claude Code` lines and robot emoji 3. Detects the orchestrator from the workspace path Installed on all repos via `scripts/install-commit-hook.sh`. PR Description Hook [#pr-description-hook] A PreToolUse hook on `Bash` intercepts `gh pr create` commands and strips Claude Code branding from the PR body before it's sent to GitHub. GitHub Auto-Comments [#github-auto-comments] The webhook handler posts signed comments on GitHub issues at key IRP steps: * **T1 (Acknowledge):** "Investigating — assigned to `{orchestrator}`" * **T6 (Bug reproduced):** "Bug reproduced in test suite" * **T8 (Fix ready):** "Fix ready. All tests pass" * **T11 (Deployed):** "Fixed and deployed to production" Each comment ends with the VantageOS signature. Setup [#setup] The commit hook is installed automatically on workspace setup. To install manually: ```bash bash scripts/install-commit-hook.sh ``` This installs the hook on all VPS repos. The hook auto-detects the orchestrator from the workspace path. --- # Creating Missions URL: /docs/missions/creating-missions Creating Missions [#creating-missions] This page covers the full mission lifecycle from creation to evidence-bound closure. All examples use the MCP tool names as called from Claude Code. Create the mission [#create-the-mission] Call `create_mission` with the mission's identity, pilot, agents, and initial status. Start in `plan` unless you are just capturing an idea (use `brainstorm` for that). ```ts mcp__vantage-peers__create_mission({ name: "doc-completion-cedric", description: "Ship Cedric onboarding docs end-to-end: audit, write, review, publish.", pilot: "sigma", agents: ["dev-fumadocs-expert", "eta"], status: "plan", priority: "urgent", project: "vantage-peers-site", brief: "Cedric onboards Monday. Docs must cover missions, tasks, and search. Eta reviews before publish.", createdBy: "sigma" }) // returns: "k57abc123..." (the missionId) ``` Save the returned `missionId` — you will need it for every subsequent call. Add tasks linked to the mission [#add-tasks-linked-to-the-mission] Create one task per phase. Set `missionId` on every task. Use `dependsOn` to express sequencing — list the IDs of tasks that must reach `done` before this task can start. ```ts // T0 — no dependencies, starts immediately const t0 = mcp__vantage-peers__create_task({ title: "Audit existing docs", description: "Identify gaps in current /docs content. Output: list of missing pages.", assignedTo: "sigma", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", status: "todo", createdBy: "sigma" }) // t0 = "kTASK_T0" // T1 — depends on T0 const t1 = mcp__vantage-peers__create_task({ title: "Write new pages", description: "Write all pages identified in the audit. Fumadocs MDX, EN + FR.", assignedTo: "dev-fumadocs-expert", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", dependsOn: ["kTASK_T0"], status: "todo", createdBy: "sigma" }) // t1 = "kTASK_T1" // T2 — depends on T1 const t2 = mcp__vantage-peers__create_task({ title: "Eta review", description: "Eta reviews all new pages for accuracy, completeness, and EN/FR parity.", assignedTo: "eta", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", dependsOn: ["kTASK_T1"], status: "todo", createdBy: "sigma" }) // t2 = "kTASK_T2" // T3 — depends on T2 const t3 = mcp__vantage-peers__create_task({ title: "Publish and announce", description: "Merge PR, push to prod, announce to team.", assignedTo: "sigma", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", dependsOn: ["kTASK_T2"], status: "todo", createdBy: "sigma" }) ``` The dependency chain: T0 → T1 → T2 → T3. Each task can only begin after its predecessor closes. Start the mission [#start-the-mission] Once tasks are defined, transition the mission from `plan` to `execute`. This signals to all agents that active work should begin. ```ts mcp__vantage-peers__update_mission_status({ missionId: "k57abc123", status: "execute" }) ``` Dispatch work to subagents [#dispatch-work-to-subagents] Two patterns depending on whether you dispatch inline or via a new agent session: Start the first task and begin working it directly in the current session: ```ts mcp__vantage-peers__start_task({ taskId: "kTASK_T0" }) // ... do the work ... mcp__vantage-peers__complete_task({ taskId: "kTASK_T0", completionNote: "Audit complete. Found 6 missing pages: missions/index, missions/what-is-a-mission, missions/when-to-use, missions/creating-missions, missions/templates, missions/examples. Filed in analysis/doc-gaps-2026-05-29.md" }) ``` Delegate a phase to a subagent by spawning a new agent session with the task context: ```ts // Spawn a fumadocs-expert agent to write the pages Agent({ subagent_type: "dev-fumadocs-expert", prompt: `You are writing the /docs/missions section for vantage-peers-site. Mission: k57abc123 (doc-completion-cedric) Task: kTASK_T1 — Write new pages. Start the task with start_task, complete all pages, then complete_task with evidence (PR# or commit SHA).` }) ``` Track progress [#track-progress] Check mission state and linked tasks at any time: ```ts // Get the mission overview mcp__vantage-peers__get_mission({ missionId: "k57abc123" }) // returns: { name, status, progress, pilot, agents, ... } // List all tasks in the mission mcp__vantage-peers__list_tasks_by_mission({ missionId: "k57abc123" }) // returns: array of task docs with current status // Update progress manually after a phase closes mcp__vantage-peers__update_mission_progress({ missionId: "k57abc123", progress: 50 }) ``` Close evidence-bound [#close-evidence-bound] Every task must close with a `completionNote` that cites verifiable evidence before the mission can complete. Then move the mission to `validate` (for a review gate) or directly to `complete`. ```ts // Close the review task with evidence mcp__vantage-peers__complete_task({ taskId: "kTASK_T2", completionNote: "[ETA-APPROVED] PR #127 reviewed. 12 new MDX files (6 EN + 6 FR). 0 broken links. Build green. Commit sha: a1b2c3d." }) // Move mission to validate mcp__vantage-peers__update_mission_status({ missionId: "k57abc123", status: "validate" }) // After final confirmation, close the mission mcp__vantage-peers__update_mission_status({ missionId: "k57abc123", status: "complete" }) // Set progress to 100 mcp__vantage-peers__update_mission_progress({ missionId: "k57abc123", progress: 100 }) ``` Tool reference [#tool-reference] All six mission function paths, with arguments summary and cross-links. | Tool | Key args | Returns | Notes | | ------------------------- | ----------------------------------------------------------------------- | -------------------------- | ----------------------------------------------------------------------- | | `create_mission` | `name`, `project`, `status`, `priority`, `pilot`, `agents`, `createdBy` | `missionId` (string) | `brief`, `description`, `startDate`, `targetDate` optional | | `get_mission` | `missionId` | Full mission doc or `null` | Returns `null` if not found — check before proceeding | | `list_missions` | `project?`, `pilot?`, `status?`, `limit?`, `fields?` | Array of missions | `fields="lite"` for compact projection; `status="open"` alias supported | | `update_mission` | `missionId` + any mutable field | `null` | Partial update — only provided fields are patched | | `update_mission_status` | `missionId`, `status` | `null` | Shortcut — sets status + updatedAt atomically | | `update_mission_progress` | `missionId`, `progress` (0–100) | `null` | Shortcut — sets progress + updatedAt atomically | For the full argument schema and return types, see [Tools Reference](/docs/tools). `list_missions` auto-clamps to `limit=30` when `fields="full"` and no explicit limit is set. If you need more results, pass an explicit `limit` or use `fields="lite"` (limit=50 default). Using the template shortcut [#using-the-template-shortcut] If your mission matches a known template (e.g. issue resolution, onboarding, chrome extension build), you can skip manual task creation by calling `instantiate_template_into_mission`: ```ts // 1. Create the mission shell const missionId = mcp__vantage-peers__create_mission({ name: "fix-issue-142", project: "vantage-memory", status: "plan", priority: "high", pilot: "proxima", agents: ["proxima"], createdBy: "proxima" }) // 2. Instantiate the IRP template (9 tasks, pre-wired with dependsOn) mcp__vantage-peers__instantiate_template_into_mission({ templateName: "issue-resolution-v3", missionId, context: { issueNumber: "142", repo: "vantage-memory" }, callerOrchestrator: "proxima" }) // returns: { taskIds: [...], count: 9 } ``` See [Mission Templates](/docs/missions/templates) for the full template catalog. --- # Mission Examples URL: /docs/missions/examples Mission Examples [#mission-examples] *** Example 1: Client kickoff (small mission, 4 tasks) [#example-1-client-kickoff-small-mission-4-tasks] **Scenario:** Onboard client Acme Corp — kickoff call, scope document, first deliverable, status report. **Mission profile:** 4 sequential tasks, single pilot. Sequencing [#sequencing] ``` T0 onboarding-call [no deps] ↓ T1 scope-document [dependsOn: T0] ↓ T2 first-deliverable [dependsOn: T1] ↓ T3 status-report [dependsOn: T2] ``` Tool calls [#tool-calls] ```ts // 1. Create the mission const missionId = mcp__vantage-peers__create_mission({ name: "kickoff-client-acme", description: "Onboard Acme Corp: kickoff call, scope doc, first deliverable, status report.", pilot: "sigma", agents: ["sigma", "dev-general"], status: "plan", priority: "high", project: "acme-corp", brief: "Acme contact: Marie. Kickoff confirmed. First deliverable = landing page wireframe.", createdBy: "sigma" }) // missionId = "kMISS_ACME" // 2. Create tasks const t0 = mcp__vantage-peers__create_task({ title: "Onboarding call with Acme", description: "Run 1h kickoff call. Record outcomes. Note blockers and open questions.", assignedTo: "sigma", priority: "high", project: "acme-corp", missionId: "kMISS_ACME", status: "todo", createdBy: "sigma" }) // t0 = "kT_ACME_0" const t1 = mcp__vantage-peers__create_task({ title: "Write scope document", description: "Based on kickoff notes: goals, deliverables, timeline, budget, out-of-scope.", assignedTo: "sigma", priority: "high", project: "acme-corp", missionId: "kMISS_ACME", dependsOn: ["kT_ACME_0"], status: "todo", createdBy: "sigma" }) const t2 = mcp__vantage-peers__create_task({ title: "Deliver landing page wireframe", description: "Figma wireframe covering hero, features, pricing, CTA. Client approval required.", assignedTo: "dev-general", priority: "high", project: "acme-corp", missionId: "kMISS_ACME", dependsOn: ["kT_ACME_1"], status: "todo", createdBy: "sigma" }) const t3 = mcp__vantage-peers__create_task({ title: "Send Week 1 status report", description: "Email report: what was done, what is next, any blockers.", assignedTo: "sigma", priority: "medium", project: "acme-corp", missionId: "kMISS_ACME", dependsOn: ["kT_ACME_2"], status: "todo", createdBy: "sigma" }) // 3. Start execution mcp__vantage-peers__update_mission_status({ missionId: "kMISS_ACME", status: "execute" }) ``` Expected output after T0 closes [#expected-output-after-t0-closes] ```ts mcp__vantage-peers__complete_task({ taskId: "kT_ACME_0", completionNote: "Kickoff call completed 2026-05-29. Notes in acme/kickoff-notes-2026-05-29.md. Key outcome: landing page wireframe delivery confirmed, budget €5k." }) mcp__vantage-peers__update_mission_progress({ missionId: "kMISS_ACME", progress: 25 }) ``` *** Example 2: Ship a product feature (medium mission, 12 tasks across phases) [#example-2-ship-a-product-feature-medium-mission-12-tasks-across-phases] **Scenario:** Ship the "saved searches" feature for VantagePeers — spec, backend, frontend, tests, review, deploy. **Mission profile:** 12 tasks in 5 phases, 2 agents (dev + eta). Phase structure [#phase-structure] ``` Phase 1 — Plan (1 task) T0 feature-spec [no deps] Phase 2 — Build (4 tasks) T1 backend-schema [dependsOn: T0] T2 backend-mutations [dependsOn: T1] T3 frontend-ui [dependsOn: T0] ← parallel with T1, T2 T4 frontend-integration [dependsOn: T2, T3] Phase 3 — Test (2 tasks) T5 unit-tests [dependsOn: T4] T6 integration-tests [dependsOn: T4] Phase 4 — Review (2 tasks) T7 code-review-eta [dependsOn: T5, T6] ← barrier: both test tasks must close first T8 address-review-feedback [dependsOn: T7] Phase 5 — Ship (3 tasks) T9 deploy-staging [dependsOn: T8] T10 qa-staging [dependsOn: T9] T11 deploy-production [dependsOn: T10] ``` Mission setup [#mission-setup] ```ts const missionId = mcp__vantage-peers__create_mission({ name: "sigma-saved-searches-v1", description: "Ship saved searches feature: backend mutations + frontend UI + tests + review + deploy.", pilot: "sigma", agents: ["zeta", "eta"], status: "plan", priority: "high", project: "vantage-peers", brief: "Saved searches: user can save a search query with a name and recall it from a dropdown. Backend: new savedSearches table + CRUD mutations. Frontend: React dropdown in the search bar.", createdBy: "sigma" }) ``` Status transitions [#status-transitions] ```ts // Plan → Execute when T0 is done mcp__vantage-peers__update_mission_status({ missionId, status: "execute" }) mcp__vantage-peers__update_mission_progress({ missionId, progress: 10 }) // After Phase 2 completes (T1–T4 done) mcp__vantage-peers__update_mission_progress({ missionId, progress: 40 }) // After Phase 3 completes (T5, T6 done) — move to validate mcp__vantage-peers__update_mission_status({ missionId, status: "validate" }) mcp__vantage-peers__update_mission_progress({ missionId, progress: 60 }) // After T11 — close the mission mcp__vantage-peers__complete_task({ taskId: "kT11", completionNote: "Deployed to prod 2026-06-03. PR #211 merged. 47/47 tests pass. Feature live at /search?saved=true. Smoke test confirmed." }) mcp__vantage-peers__update_mission_status({ missionId, status: "complete" }) mcp__vantage-peers__update_mission_progress({ missionId, progress: 100 }) ``` How agents map to tasks [#how-agents-map-to-tasks] ``` sigma → T0 (spec), T8 (address feedback), T11 (deploy prod) zeta → T1–T4 (build), T5–T6 (tests), T9 (deploy staging), T10 (QA) eta → T7 (code review) ``` The mission's `agents: ["zeta", "eta"]` array declares who will be dispatched. The pilot (sigma) coordinates handoffs between phases. *** Example 3: System audit + remediation (large mission, multi-agent parallel) [#example-3-system-audit--remediation-large-mission-multi-agent-parallel] **Scenario:** Audit the VantageOS fleet (3 repos) and ship all critical fixes. Three parallel audit tasks run simultaneously, then a barrier, then sequential fix tasks, then final QA. **Mission profile:** 11 tasks, 3 orchestrators (proxima × auditor, zeta × fixer, eta × reviewer). Architecture: parallel-then-barrier pattern [#architecture-parallel-then-barrier-pattern] ``` T0 audit-vantage-memory [no deps] ─┐ T1 audit-vantage-starter [no deps] ─┤→ (parallel audit phase) T2 audit-myreeldream [no deps] ─┘ ↓ BARRIER (all 3 must close) T3 compile-findings [dependsOn: T0, T1, T2] ↓ T4 fix-critical-memory [dependsOn: T3] ─┐ T5 fix-critical-starter [dependsOn: T3] ─┤→ (parallel fix phase) T6 fix-critical-reel [dependsOn: T3] ─┘ ↓ BARRIER (all 3 fixes must close) T7 regression-tests-all [dependsOn: T4, T5, T6] T8 code-review-eta [dependsOn: T7] T9 deploy-all-fixes [dependsOn: T8] T10 final-qa-report [dependsOn: T9] ``` Mission setup [#mission-setup-1] ```ts const missionId = mcp__vantage-peers__create_mission({ name: "audit-fleet-2026-05", description: "Audit 3 VantageOS repos for critical issues, fix all P0/P1 findings, QA and deploy.", pilot: "sigma", agents: ["proxima", "zeta", "eta"], status: "plan", priority: "urgent", project: "vantageos-fleet", brief: "Monthly fleet audit. Scope: vantage-memory, vantage-starter, myreeldream. P0 = data loss or security. P1 = broken features. Fix all P0/P1 before QA gate.", createdBy: "sigma" }) ``` Parallel audit tasks (no dependsOn between siblings) [#parallel-audit-tasks-no-dependson-between-siblings] ```ts const t0 = mcp__vantage-peers__create_task({ title: "Audit vantage-memory", description: "Run full audit: schema, mutations, error logs, open issues. Output: findings-vantage-memory.md", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, status: "todo", createdBy: "sigma" }) // Note: no dependsOn — starts immediately in parallel const t1 = mcp__vantage-peers__create_task({ title: "Audit vantage-starter", description: "Run full audit: dependencies, deployment config, open issues. Output: findings-vantage-starter.md", assignedTo: "zeta", priority: "urgent", project: "vantageos-fleet", missionId, status: "todo", createdBy: "sigma" // no dependsOn — parallel with T0 }) const t2 = mcp__vantage-peers__create_task({ title: "Audit myreeldream", description: "Run full audit: API integrations, error rates, open issues. Output: findings-myreeldream.md", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, status: "todo", createdBy: "sigma" // no dependsOn — parallel with T0, T1 }) ``` Barrier task [#barrier-task] ```ts const t3 = mcp__vantage-peers__create_task({ title: "Compile audit findings", description: "Merge all 3 findings docs. Prioritize P0/P1. Assign fixes to agents. Output: audit-consolidated-2026-05.md", assignedTo: "sigma", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t0, t1, t2], // BARRIER — all 3 audits must complete first status: "todo", createdBy: "sigma" }) ``` Parallel fix tasks (same barrier, no mutual dependsOn) [#parallel-fix-tasks-same-barrier-no-mutual-dependson] ```ts // T4, T5, T6 all depend on T3 (the barrier) but NOT on each other — they run in parallel const t4 = mcp__vantage-peers__create_task({ title: "Fix P0/P1 in vantage-memory", description: "Address all P0/P1 findings from audit. PR required. IRP protocol applies.", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t3], status: "todo", createdBy: "sigma" }) const t5 = mcp__vantage-peers__create_task({ title: "Fix P0/P1 in vantage-starter", description: "Address all P0/P1 findings from audit. PR required.", assignedTo: "zeta", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t3], // same barrier, NOT dependsOn T4 status: "todo", createdBy: "sigma" }) const t6 = mcp__vantage-peers__create_task({ title: "Fix P0/P1 in myreeldream", description: "Address all P0/P1 findings from audit. PR required.", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t3], // same barrier, NOT dependsOn T4 or T5 status: "todo", createdBy: "sigma" }) ``` Second barrier + QA chain [#second-barrier--qa-chain] ```ts const t7 = mcp__vantage-peers__create_task({ title: "Run regression tests across all 3 repos", description: "Full test suite on all 3 repos. Zero regressions. Document results.", assignedTo: "zeta", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t4, t5, t6], // second barrier — all 3 fixes must close status: "todo", createdBy: "sigma" }) const t8 = mcp__vantage-peers__create_task({ title: "Code review all fix PRs", description: "Eta reviews all 3 fix PRs. Address blocking feedback. Document [ETA-APPROVED].", assignedTo: "eta", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t7], status: "todo", createdBy: "sigma" }) const t9 = mcp__vantage-peers__create_task({ title: "Deploy all fixes to production", description: "Merge all PRs. Deploy. Smoke test each repo.", assignedTo: "sigma", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t8], status: "todo", createdBy: "sigma" }) const t10 = mcp__vantage-peers__create_task({ title: "Write final QA report", description: "Document all fixes shipped, tests run, and fleet status. Store in analysis/fleet-audit-2026-05-report.md", assignedTo: "sigma", priority: "high", project: "vantageos-fleet", missionId, dependsOn: [t9], status: "todo", createdBy: "sigma" }) ``` Key pattern explained [#key-pattern-explained] Tasks at the same level with the same `dependsOn` run in **parallel** — no ordering between them. Tasks that list multiple predecessors in `dependsOn` are **barriers** — they block until every predecessor is `done`. ``` Parallel: T0, T1, T2 have NO dependsOn between each other → fan out Barrier: T3 dependsOn [T0, T1, T2] → waits for all three → fan in Parallel: T4, T5, T6 share dependsOn [T3] only → fan out again Barrier: T7 dependsOn [T4, T5, T6] → second fan in ``` The parallel-then-barrier pattern is the standard way to fan out work across agents and synchronize before a review gate. Use it any time you have independent work that must all complete before a next phase begins. --- # Missions URL: /docs/missions Missions [#missions] A mission is an orchestrated body of work — a template + brief + sequenced tasks with dependencies, owned by a pilot orchestrator, tracked by status. Where a task is a single atomic action ("fix this bug"), a mission is an end-to-end delivery ("investigate, fix, test, and ship this bug across 9 structured steps"). Missions give your agent fleet a shared frame of reference: everyone knows the goal, the sequence, and the current progress. When to use missions [#when-to-use-missions] Use a mission when at least two of the following are true: * **Multi-step work** — the goal requires more than one distinct action, and some steps must happen before others. * **Multi-agent coordination** — different orchestrators or subagent types handle different phases (dev, review, QA, ship). * **Evidence-bound completion required** — deliverables must cite a commit SHA, PR number, test ratio, or file path before the mission can close. * **Deliverables span 3 or more days** — a long-running effort needs a persistent tracking object so progress survives session restarts. When NOT to use missions [#when-not-to-use-missions] If the work is a single step that one agent can complete in one session, use a task. Missions carry overhead — pilot assignment, status lifecycle, progress tracking — that is unnecessary for atomic actions. ``` Single action, one agent, one session → create_task Multi-step, multi-agent, 3+ days → create_mission + linked tasks ``` Quick example [#quick-example] Sigma launches a "doc-completion-cedric" mission with 4 phase tasks (audit / write / review / publish). Each task carries `missionId` linking it back to the mission and `dependsOn` pointing to its predecessor. The mission status moves through `plan → execute → validate → complete` as tasks close. Progress is a manual percentage updated via `update_mission_progress`. ``` Mission: doc-completion-cedric [execute, 50%] T0 audit-existing-docs [done] T1 write-new-pages [in_progress] dependsOn: [T0] T2 review-by-eta [todo] dependsOn: [T1] T3 publish-and-announce [todo] dependsOn: [T2] ``` Pages in this section [#pages-in-this-section] All mission operations are available as MCP tools. See [API Reference: Missions](/docs/tools) for the complete argument list. --- # Mission Templates URL: /docs/missions/templates Mission Templates [#mission-templates] What are mission templates? [#what-are-mission-templates] A mission template is a pre-defined skeleton: a named list of steps, each with a title, description, optional `assignedTo`, and optional `dependsOn` (expressed as step indexes). When you instantiate a template into a mission, every step becomes a real task with `missionId` set and `dependsOn` resolved to actual task IDs. Templates live in the `missionTemplates` table and are managed by the VantageOS team. Self-host clients can define their own templates using the `upsert_mission_template` mutation. Why use templates? [#why-use-templates] * **Consistency** — every issue resolution follows the same 9-step protocol, regardless of which orchestrator triggers it. * **Speed** — one `instantiate_template_into_mission` call creates N tasks with correct sequencing. No manual wiring of `dependsOn`. * **Fewer mistakes** — the steps encode hard-won lessons (run tests BEFORE fixing, write the regression test FIRST, create the PR in the same step as the push). * **Traceability** — every task cites its template lineage via the mission's `name` and the template's `name`. Template catalog [#template-catalog] `issue-resolution-v3` (default) [#issue-resolution-v3-default] The canonical Issue Resolution Protocol. 9 steps (T0–T8), covering acknowledgement through code review. Auto-seeded on every deployment. **Purpose:** Structured, evidence-bound resolution of GitHub issues. **When to use:** Any GitHub issue assigned to an orchestrator. The auto-IRP bot triggers this template automatically when an error log creates a new issue. **Steps:** | Step | Title | Key requirement | | ---- | -------------------- | ------------------------------------------------------- | | T0 | Acknowledge | Auto-post GitHub comment confirming receipt | | T1 | KB Search | Search `fixPatterns` + episodes; document outcome | | T2 | Identify & Run Tests | Run existing tests; document PASS/FAIL | | T3 | Write Missing Tests | Write failing regression test; commit it | | T4 | Fix | Apply fix; T3 test must pass | | T5 | Run ALL Tests | Full suite; zero regressions | | T6 | Deploy Dev + Push | `convex dev --once`; push branch; create PR immediately | | T7 | Verification Preview | Test on preview; request human sign-off | | T8 | Code Review | Reviewer agent + update KB with fix pattern | ```ts mcp__vantage-peers__instantiate_template_into_mission({ templateName: "issue-resolution-v3", missionId: "k57xxx", context: { issueNumber: "142", repo: "vantage-memory" }, callerOrchestrator: "proxima" }) ``` `mission-generic-v1` [#mission-generic-v1] A blank-slate template for missions that don't fit a more specific template. Provides a minimal plan / execute / validate / complete scaffold with 4 generic tasks. **Purpose:** Kickstart any mission with a standard structure when no specialized template applies. **When to use:** Client kickoff, internal project start, one-off orchestrated deliverable. `chrome-extension-mission-v1` [#chrome-extension-mission-v1] Build and publish a Chrome extension from scratch. Covers spec, Manifest V3 implementation, content scripts, background service worker, popup UI, packaging, and store submission. **Purpose:** Structured Chrome extension development from zero to published. **When to use:** Any new Chrome extension project assigned to Zeta or a dev agent. `pricing-research-v1` [#pricing-research-v1] Competitive pricing research mission. Covers market scan, competitor matrix, pricing model analysis, recommendation doc, and stakeholder review. **Purpose:** Produce a defensible pricing recommendation backed by market data. **When to use:** Before any pricing change or new product tier launch. `repo-fix-v1` [#repo-fix-v1] Focused fix for a known bug in a specific repo. Shorter than `issue-resolution-v3` — no auto-acknowledge or KB search steps. Use for quick, well-scoped fixes where the root cause is already known. **Purpose:** Apply a known fix, write the regression test, ship the PR. **When to use:** Fix patterns already documented in `fixPatterns`; root cause confirmed. `new-website-build` [#new-website-build] Full website build from design brief to go-live. Covers wireframes, tech stack selection, content, implementation, SEO review, staging QA, and launch. **Purpose:** End-to-end website delivery with a clear hand-off checklist. **When to use:** New client site or major redesign. `gui-iframe-embed-v1` [#gui-iframe-embed-v1] Build the GUI iframe embed flow for VantagePeers (SEP-1865 pattern). Covers backend session registry, origin validation, UI components, integration tests, and deployment. **Purpose:** Implement the standard VantagePeers iframe embed architecture. **When to use:** Any client needing embedded VP Gen UI in their own app. How to instantiate a template [#how-to-instantiate-a-template] Templates are instantiated via `instantiate_template_into_mission`. This creates one task per step, patches `dependsOn` on each task, and returns all task IDs. ```ts // Step 1: create the mission shell const missionId = mcp__vantage-peers__create_mission({ name: "fix-issue-255-vantage-memory", project: "vantage-memory", status: "plan", priority: "high", pilot: "proxima", agents: ["proxima"], createdBy: "proxima" }) // Step 2: instantiate the template const result = mcp__vantage-peers__instantiate_template_into_mission({ templateName: "issue-resolution-v3", missionId, context: { issueNumber: "255", repo: "vantage-memory" }, titlePrefix: "IRP-255", // optional: prepended to each task title callerOrchestrator: "proxima" }) // result = { taskIds: ["kT0", "kT1", ..., "kT8"], count: 9 } // Step 3: start the mission mcp__vantage-peers__update_mission_status({ missionId, status: "execute" }) ``` Context interpolation [#context-interpolation] Template step descriptions can contain `{{key}}` placeholders. Pass a `context` object and they will be replaced at instantiation time: ```ts // Template step description: // "Run `npx convex dev --once` on repo {{repo}} to verify compilation." // Context: context: { repo: "vantage-memory", issueNumber: "255" } // Result in task description: // "Run `npx convex dev --once` on repo vantage-memory to verify compilation." ``` Creating your own templates [#creating-your-own-templates] Self-host clients can define custom templates using `upsert_mission_template`: ```ts mcp__vantage-peers__upsert_mission_template({ name: "my-custom-template-v1", description: "Custom 3-step delivery template.", steps: [ { title: "Scope", description: "Define scope and acceptance criteria.", assignedTo: "sigma" }, { title: "Build", description: "Implement the deliverable.", assignedTo: "zeta", dependsOn: [0] // depends on step 0 (Scope) }, { title: "Ship", description: "Review, merge, deploy.", assignedTo: "sigma", dependsOn: [1] // depends on step 1 (Build) } ], isDefault: false, createdBy: "sigma" }) ``` Templates are stored per-deployment. If you self-host VantagePeers, your templates live in your own Convex deployment and are not shared with the VantageOS cloud instance. --- # What is a Mission? URL: /docs/missions/what-is-a-mission What is a Mission? [#what-is-a-mission] A mission is a persistent, orchestrated body of work stored in VantagePeers. It groups related tasks under a single tracking object with a pilot, a status lifecycle, a progress indicator, and optional template lineage. Field anatomy [#field-anatomy] Status lifecycle [#status-lifecycle] Mission statuses flow from ideation to completion. Each transition must be driven by the pilot explicitly via `update_mission_status`. ``` brainstorm → plan → execute → validate → complete ``` | Status | Meaning | | ------------ | ------------------------------------------------------------- | | `brainstorm` | Idea captured, not yet planned. No tasks required. | | `plan` | Tasks defined and sequenced. Pilot is preparing the workload. | | `execute` | Active work underway. Subagents are dispatched. | | `validate` | All tasks done. Pilot or a reviewer is checking evidence. | | `complete` | Mission closed with evidence. No further changes expected. | **Status aliases** (for queries only, not for writes): * `"open"` — expands to `["brainstorm", "plan", "execute", "validate"]` * `"active"` — expands to `["plan", "execute"]` There is no `blocked` or `cancelled` status on missions. To pause a mission, leave it in `plan` or `execute` and add a note to the `brief`. To abandon, move to `complete` and document the reason in the brief. How tasks link to missions [#how-tasks-link-to-missions] Every task has an optional `missionId` field. When set, the task is part of that mission's workload. Tasks also have `dependsOn` — an array of task IDs that must reach `done` status before this task can start. ``` Mission ──┬── Task A (no deps) ├── Task B dependsOn: [Task A] ├── Task C dependsOn: [Task A] └── Task D dependsOn: [Task B, Task C] ← barrier ``` The combination of `missionId + dependsOn` gives you full DAG sequencing within a mission. Mission vs Task — comparison table [#mission-vs-task--comparison-table] | Aspect | Task | Mission | | ---------- | ------------------------------------ | ------------------------------------------------------ | | Scope | Single atomic step | Multi-step orchestrated body of work | | Tracking | Status only | Status + progress % + agents + pilot + brief | | Sequencing | None (tasks are independent) | `dependsOn` chains tasks in a DAG | | Templates | None | VR mission templates — instantiate N tasks in one call | | Best for | Fix a bug, write a file, run a check | End-to-end delivery spanning days or teams | | Lifecycle | `todo → in_progress → review → done` | `brainstorm → plan → execute → validate → complete` | | Evidence | `completionNote` on the task | Evidence on each linked task + final status transition | Progress tracking [#progress-tracking] Progress is a manually managed `0–100` integer. The pilot updates it after meaningful milestones (e.g. after each phase completes). It does not auto-compute from task statuses — the pilot is the authority. ```ts // Update progress after a phase closes mcp__vantage-peers__update_mission_progress({ missionId: "k57xxxxx", progress: 50 }) ``` A common convention: set progress in multiples of 25 for a 4-phase mission (25 / 50 / 75 / 100). --- # When to Use Missions URL: /docs/missions/when-to-use When to Use Missions [#when-to-use-missions] The decision test [#the-decision-test] Work through these four questions. If two or more answers are "yes", create a mission. If zero or one, create a task. **Is the work more than one step with sequencing constraints?** Does the goal require distinct phases where phase B cannot start until phase A finishes? A mission gives you `dependsOn` to express that constraint. A plain task has no sequencing mechanism. Yes examples: audit then write then review; spec then build then test then ship. No examples: "Update the README", "Fix typo in line 42". **Does it require multiple subagent types working in series or parallel?** If a dev agent writes code, a reviewer agent checks it, and a QA agent verifies it — you have three distinct roles. A mission's `agents` array declares all of them upfront, making it clear who is involved and in what capacity. Yes examples: dev + eta + qa; fumadocs-expert + railway-expert; auditor + fixer. No examples: one agent does everything; a single tool call is sufficient. **Does it have a measurable, verifiable deliverable?** A mission closes with evidence: a PR number, commit SHA, test ratio, or deployed URL. If the output is ambiguous ("things are better now"), a task with a `completionNote` is enough. If the output must be independently verifiable, use a mission and enforce evidence on each linked task. Yes examples: ship a PR, deploy a feature, publish a report. No examples: "Look into the error", "Check if X is working". **Will it span multiple days or multiple sessions?** Sessions end; context resets. A mission persists in VantagePeers across sessions. The pilot can pick up exactly where they left off by calling `get_mission` and `list_tasks_by_mission`. A task that spans more than one session risks being dropped unless it is part of a mission. Yes examples: 3-day feature build, week-long audit, multi-sprint roadmap item. No examples: "Fix and push in this session", "One-shot script run". Quick decision matrix [#quick-decision-matrix] | Scenario | Verdict | | ----------------------------------------------------------- | -------------------------------------------- | | Single-agent, one session, atomic result | Task | | Two agents, one hand-off, same day | Task (or mission if evidence required) | | Three phases, two agents, 2 days | Mission | | Full feature from spec to ship | Mission | | Bug fix (1 file, known pattern) | Task | | Bug fix requiring audit + fix + regression test + PR review | Mission (use `issue-resolution-v3` template) | | Weekly standup note | Task (or recurring task) | | Onboard a new client | Mission | Signals to escalate from a task to a mission [#signals-to-escalate-from-a-task-to-a-mission] Sometimes you start with a task and discover mid-flight that it has grown. These are the signals to stop, create a mission, and re-link the original task under it: **Scope creep** — The task description has been edited three or more times, each time expanding the scope. The original estimate is no longer realistic. **Multiple PRs needed** — The task now requires changes across more than one repository or more than two files. A single `completionNote` cannot capture the full evidence trail. **Blocking dependency** — Another task or person is waiting on this work. A mission's status makes the blocking relationship visible to the whole team. **Review gate required** — The output must be checked by Eta or another orchestrator before it can close. A mission lets you model the validate step explicitly rather than leaving the review implicit in a task comment. **Days have passed with no closure** — If a task has been `in_progress` for more than 48 hours, it is likely hiding sub-steps that should be explicit. Convert it to a mission and surface those steps as linked tasks. Escalating from task to mission does not require deleting the original task. Create the mission, set `missionId` on the original task, then create the remaining tasks as siblings. The original task becomes T0 in the new mission. Anti-patterns to avoid [#anti-patterns-to-avoid] **Mission for every task** — Not every action needs orchestration overhead. Over-using missions creates noise and buries the real signals. Reserve missions for work that genuinely needs sequencing, multi-agent coordination, or multi-day persistence. **Mission without a brief** — A mission with no `brief` and no `description` is a black box. Anyone picking it up cold has no idea what success looks like. Always write at least one sentence. **Pilot drift** — A mission that starts with one pilot and is silently transferred to another without a `update_mission` call loses accountability. Update `pilot` explicitly when ownership transfers. --- # Consumer Guide URL: /docs/paradigm-b/consumer-guide Consumer Guide [#consumer-guide] This guide covers how three reference consumers integrate Paradigm B. Each has a different architecture, but all three share the same `parseToolResult` + Zod validate + render switch pattern. Common Integration Pattern [#common-integration-pattern] All consumers follow this three-step flow: **Intercept**: capture the raw text from an MCP tool response or a Convex direct call result. **Parse**: call `parseToolResult(text)` — returns a validated `VpToolResult` or `null`. **Render**: switch on `result.kind` and dispatch to the appropriate renderer. ```ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' import type { VpToolResult } from 'vantage-peers-mcp/ui-resources/schemas' function handleMcpToolResponse(rawText: string): void { const result = parseToolResult(rawText) if (!result) { // No marker — plain text, render as markdown/text renderPlainText(rawText) return } renderStructured(result) } function renderStructured(result: VpToolResult): void { switch (result.kind) { case 'tasks-table': return renderTasksTable(result.items) case 'messages-feed': return renderMessagesFeed(result.items) case 'diary-entry': return renderDiaryEntry(result.item) case 'mission-timeline': return renderMissionTimeline(result.items) case 'briefing-note': return renderBriefingNote(result.item) case 'memory-quote': return renderMemoryQuote(result.items) default: result satisfies never } } ``` *** Consumer 1: Hermes vantage-peers-extension [#consumer-1-hermes-vantage-peers-extension] **Architecture**: Claude Desktop extension using Convex direct client (not MCP HTTP). Hermes subscribes to Convex real-time queries and calls Convex actions directly. **Integration points**: Hermes receives tool call results through Claude Desktop's tool use API. When `VP_EMIT_UI_MARKERS=1`, those results contain embedded markers. ```ts // hermes/src/tool-handler.ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' export function onToolCallResult(toolName: string, rawResult: string): void { // 1. Try to extract a structured VP result const vpResult = parseToolResult(rawResult) if (!vpResult) { // No marker → fall back to default text rendering claudeDesktop.renderText(rawResult) return } // 2. Optional: re-validate with Zod for extra safety const validated = VpToolResultSchema.safeParse(vpResult) if (!validated.success) { console.warn('[Hermes] VpToolResult schema mismatch:', validated.error) claudeDesktop.renderText(rawResult) return } // 3. Render via Shadow DOM injection const shadowHost = document.createElement('div') const shadow = shadowHost.attachShadow({ mode: 'open' }) // Fetch the HTML version from ui:// resource for full styling const uri = buildUiUri(validated.data) fetchUiResource(uri).then((html) => { shadow.innerHTML = html claudeDesktop.renderWidget(shadowHost) }) } function buildUiUri(result: VpToolResult): string { // Convert parsed marker → ui:// URI for re-fetch with full HTML render switch (result.kind) { case 'tasks-table': return `ui://vp/v1/tasks-table?limit=${result.items.length}` case 'messages-feed': return `ui://vp/v1/messages-feed?limit=${result.items.length}` // ... etc default: return `ui://vp/v1/${result.kind}` } } ``` Hermes uses **two-pass rendering**: it parses the marker to get kind/count metadata immediately, then fetches the full HTML from the `ui://` resource for final render. This avoids re-implementing the HTML template in the extension. *** Consumer 2: Mu vantage-bridge Sidepanel [#consumer-2-mu-vantage-bridge-sidepanel] **Architecture**: Browser extension sidepanel connecting via MCP HTTP transport (Streamable HTTP). Mu talks to the VantagePeers MCP server deployed on Railway. **Integration**: Mu intercepts all `tools/call` responses from the MCP HTTP connection and runs them through `parseToolResult`. ```ts // mu/src/mcp-bridge.ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' // Mu's MCP HTTP client wraps every tool call export async function callTool( toolName: string, args: Record ): Promise { const response = await mcpHttpClient.callTool({ name: toolName, arguments: args }) // MCP tool result is always { content: [{ type: 'text', text: '...' }] } const rawText = response.content .filter((c) => c.type === 'text') .map((c) => c.text) .join('\n') const vpResult = parseToolResult(rawText) if (vpResult) { // Post to sidepanel renderer sidepanel.postMessage({ type: 'VP_PRIMITIVE', payload: vpResult }) } else { sidepanel.postMessage({ type: 'TEXT', payload: rawText }) } } ``` ```ts // mu/src/sidepanel/renderer.ts import type { VpToolResult } from 'vantage-peers-mcp/ui-resources/schemas' window.addEventListener('message', (event) => { const msg = event.data as { type: string; payload: unknown } if (msg.type === 'VP_PRIMITIVE') { const result = msg.payload as VpToolResult renderPrimitive(result) } else if (msg.type === 'TEXT') { renderMarkdown(msg.payload as string) } }) function renderPrimitive(result: VpToolResult): void { const container = document.getElementById('vp-output')! container.innerHTML = '' // clear previous // Shadow DOM for CSS isolation const host = document.createElement('div') container.appendChild(host) const shadow = host.attachShadow({ mode: 'open' }) // Build minimal HTML from payload — or fetch from ui:// resource shadow.innerHTML = buildHtmlFromPayload(result) } ``` *** Consumer 3: Registry json-render [#consumer-3-registry-json-render] **Architecture**: VantagePeers Registry is a Convex-native workflow. After tool calls, it uses post-tool-call marker extraction to persist structured data and render compact summaries in its own UI. **Integration**: Registry processes Convex action results (not MCP responses). When a tool auto-emits a marker, the Registry extracts it to build a JSON summary for its activity log. ```ts // registry/src/tool-result-processor.ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' export function extractAndLog( toolName: string, rawResult: string, sessionId: string ): void { const vpResult = parseToolResult(rawResult) if (!vpResult) { // No structured data — log raw text summary activityLog.push({ sessionId, toolName, type: 'text', preview: rawResult.slice(0, 200) }) return } // Validate fully before persisting const parsed = VpToolResultSchema.parse(vpResult) // Extract count / summary metadata by kind const meta = extractMeta(parsed) activityLog.push({ sessionId, toolName, type: 'structured', kind: parsed.kind, count: meta.count, preview: meta.preview, payload: parsed, // full structured data — used by json-render view }) } function extractMeta(result: VpToolResult): { count: number; preview: string } { switch (result.kind) { case 'tasks-table': return { count: result.items.length, preview: result.items[0]?.title ?? '' } case 'messages-feed': return { count: result.items.length, preview: result.items[0]?.content?.slice(0, 80) ?? '' } case 'diary-entry': return { count: 1, preview: result.item.content.slice(0, 80) } case 'mission-timeline': return { count: result.items.length, preview: result.items[0]?.name ?? '' } case 'briefing-note': return { count: 1, preview: result.item.title } case 'memory-quote': return { count: result.items.length, preview: result.items[0]?.content?.slice(0, 80) ?? '' } default: result satisfies never return { count: 0, preview: '' } } } ``` *** Choosing the Right Approach [#choosing-the-right-approach] | Scenario | Recommended approach | | --------------------------------------------- | ------------------------------------------------------------------- | | Need full HTML with embedded CSS (Shadow DOM) | Fetch `ui://` resource after parsing marker | | Need only structured data (no HTML rendering) | Use `parseToolResult` + `VpToolResultSchema` directly | | High-volume log/audit trail | Use Registry pattern: extract metadata, persist `payload` | | Real-time sidepanel | Use Mu pattern: post-message bridge between MCP client and renderer | | Desktop extension with Convex direct | Use Hermes pattern: two-pass (marker metadata + ui:// HTML) | Always use `parseToolResult` from the npm package — do not reimplement the marker parsing logic. The marker boundary tokens (`__VP_TOOL_RESULT__` / `__END__`) are stable across v2.x but will be versioned in v3. Use the package to get automatic compatibility. --- # Paradigm B — ui:// Resources URL: /docs/paradigm-b Paradigm B — ui:// Resources [#paradigm-b--ui-resources] VantagePeers supports two distinct generative UI paradigms. This section covers **Paradigm B**, the MCP-native approach introduced in SEP-1865 and shipped in `vantage-peers-mcp@2.4.0`. Two Paradigms at a Glance [#two-paradigms-at-a-glance] | | Paradigm A | Paradigm B | | --------------- | --------------------------------- | ----------------------------- | | **Host** | Theta Next.js app | Any MCP consumer | | **Transport** | iframe + Clerk SSO relay | `ui://` MCP resource protocol | | **Auth** | Clerk SSO session propagation | Bearer token via MCP server | | **Rendering** | iframe (full page control) | Shadow DOM scoped HTML inline | | **VR template** | `gui-iframe-embed-v1` v1.1.0 §2.5 | SEP-1865 | | **Status** | Theta deployment | Sigma-validated LIVE (v2.4.0) | Paradigm A gives you a full Theta-hosted Next.js surface with complete design control and Clerk SSO. Paradigm B gives every MCP consumer (Hermes, Mu, Registry, Claude Desktop) access to structured UI primitives without any additional hosting infrastructure. Decision Tree [#decision-tree] ``` Do you need a full authenticated web UI (login pages, complex navigation)? ├── Yes → Paradigm A (Theta iframe embed, gui-iframe-embed-v1 v1.1.0 §2.5) └── No │ Do your MCP consumers need rich inline structured views (task boards, message feeds, diary, missions)? ├── Yes → Paradigm B (ui:// resources, this section) └── No → Plain text tool responses are sufficient ``` **Pick Paradigm B when:** * You are building a Claude Desktop extension, sidepanel, or MCP bridge * You want structured visual output without deploying a web host * Your consumers already speak MCP (resources/read, resources/list) * You need WCAG AA, XSS-safe, bilingual (FR/EN) HTML delivered inline **Pick Paradigm A when:** * Full page layout and Clerk SSO session are required * You need deep URL routing and navigation state * The VR template `gui-iframe-embed-v1` v1.1.0 is already in your stack (see §2.5) What Ships in Paradigm B [#what-ships-in-paradigm-b] 6 ui:// Primitives [#6-ui-primitives] All primitives are served under the URI scheme `ui://vp/v1/?`. | Primitive | URI | Data source | | ------------------ | ----------------------------- | ----------------------- | | `tasks-table` | `ui://vp/v1/tasks-table` | `tasks:list` | | `messages-feed` | `ui://vp/v1/messages-feed` | `messages:listMessages` | | `diary-entry` | `ui://vp/v1/diary-entry` | `diary:getEntry` | | `mission-timeline` | `ui://vp/v1/mission-timeline` | `missions:list` | | `briefing-note` | `ui://vp/v1/briefing-note` | `briefingNotes:get` | | `memory-quote` | `ui://vp/v1/memory-quote` | `memories:search` | Each primitive returns inline HTML with embedded CSS, scoped for Shadow DOM rendering. Output is WCAG AA compliant and bilingual (FR/EN via `?lang=fr`). Zod Schemas [#zod-schemas] All payloads are validated with Zod discriminated unions before emission. Import from: ```ts import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' import type { VpToolResult } from 'vantage-peers-mcp/ui-resources/schemas' ``` Stream Marker Helpers [#stream-marker-helpers] When `VP_EMIT_UI_MARKERS=1` is set on your Convex deployment, tool responses automatically embed structured markers: ``` __VP_TOOL_RESULT__{"kind":"tasks-table","items":[...]}__END__ ``` Parse them with: ```ts import { parseToolResult, wrapToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' ``` Prerequisites [#prerequisites] Paradigm B requires `vantage-peers-mcp@2.4.0` or later and `VP_EMIT_UI_MARKERS=1` set in Convex environment variables for auto-emit on tool responses. Install or upgrade the MCP server package: ```bash npm install vantage-peers-mcp@^2.4.0 ``` Set the environment variable in your Convex dashboard (Settings → Environment Variables): ``` VP_EMIT_UI_MARKERS=1 ``` See the [environment variables reference](/docs/infrastructure/deploy-keys) for full details. Verify the MCP server exposes `ui://` resources by calling `resources/list` — you should see 6 entries with URIs matching `ui://vp/v1/*`. Section Contents [#section-contents] --- # Stream Marker URL: /docs/paradigm-b/stream-marker Stream Marker [#stream-marker] The `__VP_TOOL_RESULT__` stream marker is a lightweight text protocol embedded in MCP tool responses. It lets downstream consumers (Claude Desktop, Hermes, Mu sidepanel, Registry) detect and render structured UI primitives inline, without a separate `resources/read` call. Marker Format [#marker-format] ``` __VP_TOOL_RESULT____END__ ``` Where `` is a JSON-serialized object conforming to `VpToolResultSchema` (a Zod discriminated union with a `kind` discriminator). The JSON is minified (no spaces). **Full example — tasks-table:** ``` __VP_TOOL_RESULT__{"kind":"tasks-table","items":[{"_id":"j97abc","title":"Fix auth bug","status":"in_progress","priority":"high","assignedTo":"sigma"}]}__END__ ``` The marker is emitted only when `VP_EMIT_UI_MARKERS=1` is set in the Convex environment. When the variable is absent (default), tool responses are plain text — existing integrations are unaffected. VpToolResultSchema — Discriminated Union [#vptoolresultschema--discriminated-union] Six kinds, one per primitive. Import from `vantage-peers-mcp/ui-resources/schemas`: ```ts import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' import type { VpToolResult } from 'vantage-peers-mcp/ui-resources/schemas' ``` Kind: `tasks-table` [#kind-tasks-table] ```ts { kind: 'tasks-table', items: Array<{ _id: string title: string status: string priority?: string assignedTo?: string _creationTime?: number }> } ``` Kind: `messages-feed` [#kind-messages-feed] ```ts { kind: 'messages-feed', items: Array<{ _id: string from: string channel?: string content: string createdAt: number }> } ``` Kind: `diary-entry` [#kind-diary-entry] ```ts { kind: 'diary-entry', item: { _id: string date: string // YYYY-MM-DD orchestrator: string content: string highlights?: string[] blockers?: string[] } } ``` Note: `diary-entry` uses `item` (singular), not `items`. Kind: `mission-timeline` [#kind-mission-timeline] ```ts { kind: 'mission-timeline', items: Array<{ _id: string name: string project?: string status: string pilot?: string priority?: string progress?: number // 0–100 }> } ``` Kind: `briefing-note` [#kind-briefing-note] ```ts { kind: 'briefing-note', item: { _id: string topic: string title: string participants?: string[] content?: string createdBy?: string } } ``` Note: `briefing-note` uses `item` (singular). Kind: `memory-quote` [#kind-memory-quote] ```ts { kind: 'memory-quote', items: Array<{ _id: string namespace: string type: string content: string score?: number }> } ``` Helpers [#helpers] Import both helpers from `vantage-peers-mcp/ui-resources/stream-marker`: ```ts import { wrapToolResult, parseToolResult, MARKER_START, MARKER_END, } from 'vantage-peers-mcp/ui-resources/stream-marker' ``` `wrapToolResult(payload: VpToolResult): string` [#wraptoolresultpayload-vptoolresult-string] Validates `payload` against `VpToolResultSchema`, then serializes to the marker format. Throws `TypeError` if validation fails. ```ts const marker = wrapToolResult({ kind: 'tasks-table', items: [ { _id: 'j97abc', title: 'Fix auth bug', status: 'in_progress', priority: 'high', assignedTo: 'sigma' }, ], }) // → "__VP_TOOL_RESULT__{"kind":"tasks-table","items":[...]}__END__" ``` Use `wrapToolResult` when you are building a tool that should always emit a marker regardless of the `VP_EMIT_UI_MARKERS` env var — for example, in a test harness or a custom tool wrapper. `parseToolResult(text: string): VpToolResult | null` [#parsetoolresulttext-string-vptoolresult--null] Extracts and validates a VP marker from `text`. Handles three cases: 1. `text` **is** the marker (bare) 2. `text` **contains** the marker embedded in surrounding content 3. `text` **does not** contain a marker — returns `null` Returns the validated `VpToolResult` on success, or `null` on any failure (missing marker, malformed JSON, schema violation). Never throws. ```ts const result = parseToolResult(toolResponse) if (result === null) { // Plain text response — render as-is renderText(toolResponse) } else { // Structured result — render by kind renderPrimitive(result) } ``` Constants [#constants] ```ts MARKER_START = "__VP_TOOL_RESULT__" MARKER_END = "__END__" ``` Keep these in sync with any iframe bridge parser on the consumer side. Auto-Emit Tools [#auto-emit-tools] When `VP_EMIT_UI_MARKERS=1` is set, the following 6 MCP tools automatically append a `__VP_TOOL_RESULT__` marker to their text response: | Tool | Kind emitted | | ------------------------------------- | ------------------ | | `list_tasks` | `tasks-table` | | `list_messages` / `get_messages` | `messages-feed` | | `get_diary_entry` | `diary-entry` | | `list_missions` | `mission-timeline` | | `get_briefing_note` | `briefing-note` | | `search_memories` / `recall_memories` | `memory-quote` | Auto-emit is additive — the marker is appended after the human-readable text response. Consumers that do not implement `parseToolResult` see the raw marker text, which is ugly but not harmful. Set `VP_EMIT_UI_MARKERS=1` only in deployments where at least one consumer handles markers. Render Switch Pattern [#render-switch-pattern] Standard consumer pattern for rendering a parsed result: ```ts import { parseToolResult, type VpToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' function handleToolResponse(text: string): void { const result = parseToolResult(text) if (!result) { displayPlainText(text) return } switch (result.kind) { case 'tasks-table': renderTasksTable(result.items) break case 'messages-feed': renderMessagesFeed(result.items) break case 'diary-entry': renderDiaryEntry(result.item) break case 'mission-timeline': renderMissionTimeline(result.items) break case 'briefing-note': renderBriefingNote(result.item) break case 'memory-quote': renderMemoryQuote(result.items) break default: // TypeScript exhaustiveness check result satisfies never } } ``` TypeScript's exhaustiveness check (`result satisfies never`) ensures you handle all 6 kinds. --- # UI Resources Reference URL: /docs/paradigm-b/ui-resources UI Resources Reference [#ui-resources-reference] All Paradigm B primitives are served via the `ui://` MCP resource protocol. The server registers them under `ui://vp/v1/` and clients fetch them with `resources/read`. URI Scheme [#uri-scheme] ``` ui://vp/v1/? ``` * **Protocol**: `ui://` (MCP custom URI, not HTTP) * **Namespace**: `vp/v1` — versioned to allow future breaking changes under `v2` * **Primitive**: one of the 6 registered names (see table below) * **Query params**: optional, primitive-specific filters Full URI examples [#full-uri-examples] ``` ui://vp/v1/tasks-table?assignedTo=sigma&status=in_progress&limit=10 ui://vp/v1/messages-feed?from=pi&channel=fleet&limit=20 ui://vp/v1/diary-entry?orchestrator=sigma&limit=3&lang=fr ui://vp/v1/mission-timeline?pilot=tau&status=active&limit=5 ui://vp/v1/briefing-note?topic=deployment&limit=3 ui://vp/v1/memory-quote?namespace=sigma&type=feedback&limit=5 ``` Fetching via MCP [#fetching-via-mcp] ```ts // MCP client fetch — works with any MCP SDK version >= 1.0 const result = await client.readResource({ uri: 'ui://vp/v1/tasks-table?assignedTo=sigma&status=review&limit=10', }) // result.contents[0].text = HTML string const html = result.contents[0].text as string ``` The returned `text` is a self-contained HTML fragment with embedded `
Title Status Priority Assigned to
My task title in_progress high sigma
3 tasks
``` **Status badge classes**: `vp-status-todo` (blue), `vp-status-in_progress` (yellow), `vp-status-review` (purple), `vp-status-blocked` (red), `vp-status-done` (green). *** messages-feed [#messages-feed] Renders a chronological feed of VantagePeers messages. **URI**: `ui://vp/v1/messages-feed` **Query params**: | Param | Type | Default | Description | | --------- | ------------ | ------- | -------------------------- | | `from` | string | — | Filter by sender name | | `channel` | string | — | Filter by channel name | | `limit` | 1–200 | `20` | Maximum messages to return | | `lang` | `en` \| `fr` | `en` | UI label language | **HTML output**: `
` with a list of message bubbles. Each bubble contains sender, timestamp, channel badge (if present), and XSS-escaped content. *** diary-entry [#diary-entry] Renders a structured diary entry or a list of recent entries. **URI**: `ui://vp/v1/diary-entry` **Query params**: | Param | Type | Default | Description | | -------------- | ------------ | ------- | ------------------------------------ | | `date` | `YYYY-MM-DD` | — | Fetch entry for a specific date | | `orchestrator` | string | — | Filter by orchestrator name | | `limit` | 1–50 | `5` | Maximum entries when fetching a list | | `lang` | `en` \| `fr` | `en` | UI label language | **HTML output**: `
` with date header, orchestrator badge, content block, highlights list (if present), and blockers list (if present). *** mission-timeline [#mission-timeline] Renders a vertical timeline of VantagePeers missions. **URI**: `ui://vp/v1/mission-timeline` **Query params**: | Param | Type | Default | Description | | --------- | ------------ | ------- | --------------------------------------- | | `pilot` | string | — | Filter by pilot (assigned orchestrator) | | `project` | string | — | Filter by project name | | `status` | string | — | Filter by mission status | | `limit` | 1–100 | `10` | Maximum missions to return | | `lang` | `en` \| `fr` | `en` | UI label language | **HTML output**: `
` with a vertical timeline. Each entry shows mission name, project, status badge, pilot, priority chip, and progress bar (when `progress` is set). *** briefing-note [#briefing-note] Renders a single briefing note or a compact list of recent notes. **URI**: `ui://vp/v1/briefing-note` **Query params**: | Param | Type | Default | Description | | -------- | ------------ | ------- | --------------------------------------- | | `noteId` | string | — | Fetch a specific note by Convex ID | | `topic` | string | — | Filter by topic when fetching a list | | `limit` | 1–50 | `5` | Maximum notes when no `noteId` is given | | `lang` | `en` \| `fr` | `en` | UI label language | **HTML output**: `
` with topic badge, title, participant chips (when `participants` is set), and content block (when `content` is set). *** memory-quote [#memory-quote] Renders a compact list of memory quotes from a namespace. **URI**: `ui://vp/v1/memory-quote` **Query params**: | Param | Type | Default | Description | | ----------- | ------------ | ------- | -------------------------------------------------- | | `namespace` | string | — | Memory namespace to query | | `type` | string | — | Memory type filter (`feedback`, `reference`, etc.) | | `limit` | 1–50 | `5` | Maximum quotes to return | | `lang` | `en` \| `fr` | `en` | UI label language | **HTML output**: `
` with a blockquote-style list. Each entry shows namespace badge, type chip, relevance score (when `score` is set), and XSS-escaped content. *** Common Behaviour Across All Primitives [#common-behaviour-across-all-primitives] * **XSS safety**: all user-supplied content runs through an HTML escape function. No raw interpolation. * **Shadow DOM scoping**: CSS uses `.vp-*` class prefixes to avoid collision with host page styles. Intended for Shadow DOM root injection but works in regular DOM too. * **WCAG AA**: all tables have `scope="col"` headers; interactive regions use `role` and `aria-label`; status changes use `aria-live`. * **Bilingual**: all labels, counts, and accessible names are translated when `?lang=fr` is passed. * **Error boundary**: if the Convex query fails, the primitive returns an error `
` with the message — it never throws. The MCP `resources/read` call always succeeds with an HTML response. The `ui://` protocol is a custom MCP URI scheme. Standard HTTP clients (`fetch`, `axios`) cannot call it. Only MCP SDK clients with a registered `resources/read` handler can consume these resources. --- # Self-Host the Convex Backend URL: /docs/self-host/convex-backend Self-Host the Convex Backend [#self-host-the-convex-backend] VantagePeers runs entirely on [Convex](https://convex.dev). You own the deployment. Convex provides the database, serverless functions, vector indexes, and real-time subscriptions. There is no VantagePeers-managed infrastructure between your agents and your data. This page walks you through a fresh Convex project setup. If you already have a Convex project and are migrating from stdio to HTTP transport, see [Migrating from stdio to HTTP](/docs/self-host/migration-stdio-to-http). Prerequisites [#prerequisites] * **Node.js 20+** — Convex CLI requires Node 20 or later * **Git** — to clone the vantage-memory repository * **A Convex account** — free tier at [convex.dev](https://convex.dev). No credit card required. * **An OpenAI API key** — for RAG embeddings (`text-embedding-3-small`) Step 1: Clone vantage-memory [#step-1-clone-vantage-memory] `vantage-memory` is the Convex backend repository for VantagePeers. ```bash git clone https://github.com/vantageos-agency/vantage-memory.git cd vantage-memory npm install ``` The repository contains: * `convex/` — all schema definitions, queries, mutations, and actions (20 tables) * `mcp-server/` — the MCP server that sits in front of Convex (HTTP or stdio transport) * `convex/schema.ts` — canonical schema, the source of truth for all table definitions Step 2: Authenticate with Convex [#step-2-authenticate-with-convex] ```bash npx convex login ``` This opens a browser window. Sign in with your Convex account. If you are on a CI machine or headless server, use: ```bash npx convex login --no-browser ``` Follow the printed instructions to complete authentication. Step 3: Initialize a new Convex project [#step-3-initialize-a-new-convex-project] ```bash npx convex dev --once ``` On first run, the CLI will ask: 1. **Create a new project or use an existing one?** — Select **Create a new project**. 2. **Project name** — Enter a name, e.g. `vantage-memory-prod`. 3. The CLI outputs your deployment URL in the form `https://.convex.cloud`. Copy it. The `--once` flag deploys the schema and functions then exits immediately (no watch mode). This is the correct way to perform a one-shot seed deploy. You will see output similar to: ``` ✓ Deployed schema (20 tables) ✓ Pushed 47 functions Deployment URL: https://cheerful-penguin-123.convex.cloud ``` Step 4: Set environment variables in the Convex dashboard [#step-4-set-environment-variables-in-the-convex-dashboard] Open [dashboard.convex.dev](https://dashboard.convex.dev), select your new project, and go to **Settings → Environment Variables**. Add each variable listed below. Required [#required] | Variable | Example | Purpose | | ---------------------- | ---------------------- | ------------------------------------------------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | `sk-proj-...` | OpenAI API key for `text-embedding-3-small` RAG embeddings. Without this, `recall` returns empty results. | | `BEARER_SECRET_MASTER` | *(32-byte hex string)* | Master auth token for the MCP server. All tool calls are rejected without it. Generate with `openssl rand -hex 32`. | Optional — Clerk-based authentication [#optional--clerk-based-authentication] Only set these if you are enabling the Clerk JWT credential issuance flow (`POST /issueBearerFromClerk`). Not required for agent-only deployments. | Variable | Example | Purpose | | ------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------- | | `CLERK_JWT_ISSUER_DOMAIN` | `https://clerk.your-app.com` | JWKS base URL for Clerk JWT verification. Required only if using the web credential issuance endpoint. | | `VP_ALLOWED_EXT_IDS` | `ext_abc123,ext_def456` | Comma-separated list of allowed Clerk extension IDs. Restricts which browser extensions may exchange a Clerk JWT for a VantagePeers bearer token. | Optional — GitHub integration [#optional--github-integration] | Variable | Example | Purpose | | ----------------------- | -------------- | ------------------------------------------------------------------------------------------------------------------------ | | `GITHUB_WEBHOOK_SECRET` | *(random hex)* | Validates incoming GitHub webhook payloads. Required if you are syncing GitHub issues via the webhook endpoint. | | `GITHUB_TOKEN` | `ghp_...` | GitHub personal access token or app token. Required for posting IRP auto-comments to issues and fetching issue metadata. | Step 5: Deploy to production [#step-5-deploy-to-production] ```bash npx convex deploy ``` This is the production deploy command. It compiles TypeScript, validates the schema, and pushes all 20 tables and functions to your Convex deployment. > **Note for fleet deployments:** In the VantagePeers internal fleet workflow, production deploys require a `PI_AUTHORIZED_TASK_ID` gate enforced by a pre-commit hook. Self-hosting clients are not subject to this gate — `npx convex deploy` runs directly without any additional approval step. Verify the deploy succeeded by checking the **Functions** tab in the dashboard. You should see all modules listed: `tasks`, `messages`, `memories`, `missions`, `briefingNotes`, `diary`, `iframeEmbedSessions`, `profiles`, `fixPatterns`, `issues`, and more. Step 6: Seed initial data (optional) [#step-6-seed-initial-data-optional] After a fresh deploy, the database is empty. You can optionally seed an initial profile and workspace so agents have a home namespace to write to immediately. Using the Convex CLI run command: ```bash # Create your primary orchestrator profile npx convex run profiles:upsertProfile '{ "orchestratorId": "sigma", "displayName": "Sigma", "role": "engineer", "capabilities": ["code", "research"], "createdBy": "system" }' ``` Or from your agent, call the MCP tool `update_profile` after connecting. Step 7: Connect the MCP server [#step-7-connect-the-mcp-server] The MCP server is the bridge between AI agents and your Convex backend. See [Railway HTTP Deploy](/docs/self-host/railway-http) for the full deployment walkthrough. For a quick local test using stdio transport: ```bash cd mcp-server npm install npm run build CONVEX_URL=https://your-deployment.convex.cloud BEARER_SECRET_MASTER=your-secret node dist/server.js ``` Then add to your Claude Code `~/.claude.json`: ```json { "mcpServers": { "vantage-peers": { "command": "node", "args": ["/path/to/vantage-memory/mcp-server/dist/server.js"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud", "BEARER_SECRET_MASTER": "your-secret" } } } } ``` Step 8: Health check [#step-8-health-check] Verify everything is wired up correctly: ```bash # Should return an array (empty on fresh deploy) npx convex run profiles:list '{}' ``` From your MCP client, call the `check_messages` tool: ```json { "recipient": "sigma" } ``` Expected result: `[]` (empty array — no messages yet). A non-error response confirms Convex connectivity, authentication, and function routing are all working. Troubleshooting [#troubleshooting] **`AI_GATEWAY_API_KEY` not set — embeddings disabled** Memories store correctly but `recall` returns empty results. Set `AI_GATEWAY_API_KEY` in the Convex dashboard and re-deploy. **"Unauthorized" from every tool call** `BEARER_SECRET_MASTER` is missing or mismatched between the Convex dashboard and the MCP server `env`. Regenerate and set consistently. **Schema mismatch errors after a git pull** Run `npx convex deploy` again. Convex applies schema migrations automatically on deploy — no manual migration scripts required for additive changes (new tables, new optional fields). **Vector index not yet ready** On a fresh deploy, vector indexes build asynchronously. If `recall` returns empty results immediately after deploy, wait 30–60 seconds and try again. --- # Environment Variables Reference URL: /docs/self-host/env-vars Environment Variables Reference [#environment-variables-reference] VantagePeers uses environment variables on two distinct sides: the **Convex deployment** (set in the Convex dashboard under Settings → Environment Variables) and the **MCP server** (set in the Railway service config or your local shell when running stdio). A small number of variables apply to both. Convex Dashboard Variables [#convex-dashboard-variables] These are set in [dashboard.convex.dev](https://dashboard.convex.dev) → your project → **Settings → Environment Variables**. | Variable | Required | Example | Purpose | | ------------------------- | ---------------------------------- | ---------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | Yes | `sk-proj-abc123...` | OpenAI API key used exclusively for `text-embedding-3-small` RAG embeddings. Without this, `storeMemory` stores correctly but `recall` returns no results. Typical cost: under $1/month. | | `BEARER_SECRET_MASTER` | Yes | *(32-byte hex)* | Master admin bearer token. The MCP server presents this on every request to authenticate against Convex. Generate with `openssl rand -hex 32`. Never expose to end users. | | `GITHUB_WEBHOOK_SECRET` | No | *(random hex)* | HMAC-SHA256 secret for validating incoming GitHub webhook payloads (`X-Hub-Signature-256`). Required only if you are syncing GitHub issues through the webhook endpoint (`POST /webhooks/github`). | | `GITHUB_TOKEN` | No | `ghp_...` | GitHub personal access token or GitHub App installation token. Required for posting IRP auto-comments to GitHub issues and calling the GitHub REST API from `githubComments` actions. Needs `issues:write` scope. | | `CLERK_JWT_ISSUER_DOMAIN` | No | `https://clerk.my-app.com` | Base URL of your Clerk instance JWKS endpoint. Used by `credentials.ts` to verify Clerk JWTs before issuing VantagePeers bearer tokens. Required only if you expose the `POST /issueBearerFromClerk` credential endpoint to end users. | | `VP_ALLOWED_EXT_IDS` | No | `ext_abc123,ext_def456` | Comma-separated list of allowed Clerk extension IDs. Restricts which browser extensions can exchange a Clerk JWT for a VantagePeers bearer token via the credential issuance endpoint. If unset, no extension is allowed. | | `VP_LICENSE_KEY` | No (🚧 finalisation cette semaine) | *(license key from Gumroad email)* | Self-Hosted Pro Support license key validated against the Gumroad-issued entitlement. Unlocks Pro Support priority queue + future Cloud features. Purchase flow: buy Pro Support on Gumroad → receive license key by email → paste into this env var → MCP / Convex validates on boot. **Validation handler ships before Day 90 (2026-06-02)** — env var slot is reserved now so existing Pro customers (Cédric grandfathered tier) can pre-set it. | MCP Server Variables [#mcp-server-variables] These are set in the environment where the MCP server process runs (Railway service config, `~/.claude.json` `env` block, or your local shell). | Variable | Required | Example | Purpose | | ---------------------- | ----------- | ------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CONVEX_URL` | Yes (stdio) | `https://slug.convex.cloud` | URL of your Convex deployment. The stdio MCP server (`server.js`) uses this to connect a `ConvexHttpClient` for every tool call. Not used by the HTTP server — it uses `CONVEX_URL_INTERNAL` instead. | | `CONVEX_URL_INTERNAL` | Yes (HTTP) | `https://slug.convex.cloud` | Convex URL for the internal VantagePeers deployment. Used by the HTTP MCP server (`server-http.js`) to resolve tenant routing and validate OAuth tokens. Must be set for the HTTP transport to function. | | `BEARER_SECRET_MASTER` | Yes | *(32-byte hex)* | Must match the value set in the Convex dashboard. The HTTP MCP server checks incoming `Authorization: Bearer ` headers against this value as the admin fast-path. | | `PUBLIC_BASE_URL` | No | `https://vantage-peers-production.up.railway.app` | Public URL of the MCP server. Used in `WWW-Authenticate` headers (RFC 6750) to point OAuth clients at the discovery endpoint. Defaults to the Railway production URL if unset. | | `PORT` | No | `3000` | HTTP port the server listens on. Defaults to `3000`. Railway sets this automatically via the `PORT` env var. | | `NODE_ENV` | No | `production` | Standard Node.js environment flag. Set to `production` by Railway automatically. Affects logging verbosity and error detail exposure. | | `VP_EMIT_UI_MARKERS` | No | `true` | When set to `true`, the MCP server emits `__VP_TOOL_RESULT__` stream markers in tool responses. Used by the VantagePeers Gen UI iframe embed to distinguish structured tool output from prose. Disabled by default. | Notes on Shared Variables [#notes-on-shared-variables] `BEARER_SECRET_MASTER` appears on both sides because: * The **Convex side** stores the value so that the backend can validate it when presented as a credential. * The **MCP server side** presents this value in outgoing requests. Both values must be identical. In practice, set it once in the Convex dashboard, copy the value, and paste it into the MCP server environment. Generating Secrets [#generating-secrets] For any secret token: ```bash openssl rand -hex 32 ``` This produces a 64-character hex string (256 bits of entropy). Use a separate generated value for each secret — never reuse tokens across variables. OAuth Variables (Advanced) [#oauth-variables-advanced] The OAuth token infrastructure (`oauth.ts`, `oauthDcr.ts`) persists all client registrations, access tokens, and refresh tokens in Convex tables. No additional environment variables are required for the OAuth system itself. The only OAuth-adjacent variable is `PUBLIC_BASE_URL` (MCP server side), which is embedded in OAuth discovery metadata. Variable Summary by Side [#variable-summary-by-side] | Variable | Convex Dashboard | MCP Server | | ------------------------- | ---------------- | ----------- | | `AI_GATEWAY_API_KEY` | Yes | No | | `BEARER_SECRET_MASTER` | Yes | Yes | | `GITHUB_WEBHOOK_SECRET` | Yes | No | | `GITHUB_TOKEN` | Yes | No | | `CLERK_JWT_ISSUER_DOMAIN` | Yes | No | | `VP_ALLOWED_EXT_IDS` | Yes | No | | `CONVEX_URL` | No | Yes (stdio) | | `CONVEX_URL_INTERNAL` | No | Yes (HTTP) | | `PUBLIC_BASE_URL` | No | Yes (HTTP) | | `PORT` | No | Yes (HTTP) | | `NODE_ENV` | No | Yes | | `VP_EMIT_UI_MARKERS` | No | Yes | --- # Migrate from stdio to HTTP Transport URL: /docs/self-host/migration-stdio-to-http Migrate from stdio to HTTP Transport [#migrate-from-stdio-to-http-transport] Why migrate [#why-migrate] The stdio transport runs `vantage-peers-mcp` as a local process on each machine, with one MCP server per Claude Code session. The HTTP transport runs one server in the cloud, accessible to any number of clients simultaneously. | | stdio | HTTP | | --------------------------------- | -------------------- | ------------------------ | | Install required on each machine | Yes | No | | Multiple agents share one server | No | Yes | | Works from Claude.ai web | No | Yes | | Auth model | None (local process) | Bearer token + OAuth DCR | | State persistence across restarts | Via Convex | Via Convex | | Deploy surface | Local machine | Railway (or any host) | Practical triggers for migrating: * You are adding a second agent or machine and want them to share the same VantagePeers instance. * You want to connect Claude.ai (web) to your VantagePeers deployment. * You want centralized auth and token rotation without touching every agent's machine. * You want healthchecks, uptime monitoring, and Railway restart policies. *** Before and after: .mcp.json [#before-and-after-mcpjson] Before (stdio) [#before-stdio] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp@2.4.0"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud", "BEARER_SECRET_MASTER": "your-local-secret" } } } } ``` After (HTTP) [#after-http] ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://your-project.up.railway.app/mcp", "headers": { "Authorization": "Bearer YOUR_BEARER_SECRET_MASTER" } } } } ``` The `CONVEX_URL` and `BEARER_SECRET_MASTER` move from the client config to Railway environment variables. The client only needs the server URL and a bearer token. *** Migration steps [#migration-steps] Step 1: Deploy the HTTP server on Railway [#step-1-deploy-the-http-server-on-railway] Follow the [Railway HTTP deploy guide](/docs/self-host/railway-http) in full before continuing. Confirm: * `curl https://your-project.up.railway.app/health` returns 200 * `railway logs` shows "Running" state Step 2: Validate tool parity [#step-2-validate-tool-parity] The HTTP transport exposes the same 82 tools as stdio. Before switching, confirm the deployed version matches your current stdio version: ```bash # Check the deployed version via health endpoint curl https://your-project.up.railway.app/health | grep version # Expected: "version": "2.4.0" # Compare with your local stdio version npx vantage-peers-mcp@2.4.0 --version 2>/dev/null || echo "version flag not supported" ``` Step 3: Run both transports in parallel (validation window) [#step-3-run-both-transports-in-parallel-validation-window] During transition, keep the stdio config active on one agent while adding the HTTP config on another. Both agents write to the same Convex backend, so you can verify tool calls produce identical results: **Agent A (stdio — unchanged):** ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp@2.4.0"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud", "BEARER_SECRET_MASTER": "your-local-secret" } } } } ``` **Agent B (HTTP — new):** ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://your-project.up.railway.app/mcp", "headers": { "Authorization": "Bearer YOUR_BEARER_SECRET_MASTER" } } } } ``` Have Agent B call `search_memories` or `list_tasks` and confirm it retrieves the same data that Agent A wrote. Step 4: Switch all clients to HTTP [#step-4-switch-all-clients-to-http] Once validated, update every agent's MCP config to the HTTP form: ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://your-project.up.railway.app/mcp", "headers": { "Authorization": "Bearer YOUR_BEARER_SECRET_MASTER" } } } } ``` Restart Claude Code on each machine after updating the config. Step 5: Remove local env vars and stdio config [#step-5-remove-local-env-vars-and-stdio-config] Once all clients are confirmed working on HTTP: 1. Remove `CONVEX_URL` and `BEARER_SECRET_MASTER` from local `.env` files and agent configs — they are now Railway variables. 2. Remove the `npx vantage-peers-mcp` stdio entry from all `.mcp.json` / `settings.json` files. 3. Optionally uninstall the local package: `npm uninstall -g vantage-peers-mcp` (if globally installed). Do not remove the local config until at least one HTTP client has been validated end-to-end. Running both transports simultaneously is safe — they write to the same Convex database with no conflict. *** Validation: same tool calls, both transports [#validation-same-tool-calls-both-transports] Run the same tool call on both stdio and HTTP to confirm identical output: **stdio:** ```bash CONVEX_URL=https://your-deployment.convex.cloud \ BEARER_SECRET_MASTER=your-local-secret \ npx vantage-peers-mcp@2.4.0 # Then from Claude Code: search_memories namespace="global" query="test" ``` **HTTP:** ```bash curl -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "search_memories", "arguments": {"namespace": "global", "query": "test"} } }' \ https://your-project.up.railway.app/mcp ``` Both should return results from the same Convex database. If the HTTP call returns fewer or different results, check that `CONVEX_URL_INTERNAL` on Railway points to the same deployment as `CONVEX_URL` in your stdio config. *** Rollback path [#rollback-path] If the HTTP deploy has issues and you need to revert immediately: 1. Keep your original stdio config in a backup file (`settings.stdio-backup.json`). 2. To rollback: restore the stdio config and restart Claude Code — no Railway changes needed. 3. The Convex data is unaffected by either transport — all writes persist regardless of which transport made them. The stdio and HTTP transports are both stateless with respect to Convex — they both use `ConvexHttpClient` per-request. Switching between them mid-session is safe. Any memory, task, or message written via stdio is immediately visible via HTTP and vice versa. --- # Deploy on Railway (HTTP Transport) URL: /docs/self-host/railway-http Deploy on Railway (HTTP Transport) [#deploy-on-railway-http-transport] What you'll get [#what-youll-get] A public HTTPS endpoint running `vantage-peers-mcp` v2.4.0 with: * JSON-RPC 2.0 MCP server over Streamable HTTP (`/mcp`) * Railway healthcheck passing at `/health` * Bearer token auth (master token + OAuth DCR for Claude.ai) * Automatic HTTPS via Railway's built-in proxy * Multi-client access from Claude Code, Claude.ai, and any MCP-compatible client Prerequisites [#prerequisites] Before starting: * A [Railway](https://railway.app) account (Hobby plan or above for persistent deployments) * A Convex deployment URL — follow the [Convex backend guide](/docs/self-host/convex-backend) first * A `BEARER_SECRET_MASTER` value (see [Bearer auth setup](#bearer-auth-setup) below) * `CONVEX_URL_INTERNAL` — the `https://` URL from your Convex dashboard * Node.js 20+ locally for the Railway CLI install The HTTP transport server (`server-http.ts`) runs on Bun on Railway. The `vantage-peers-mcp` npm package exposes the same 82 tool definitions as the stdio server, served over Streamable HTTP. 5-minute deploy [#5-minute-deploy] Step 1: Install the Railway CLI and log in [#step-1-install-the-railway-cli-and-log-in] ```bash npm install -g @railway/cli railway login ``` Step 2: Create a new Railway project [#step-2-create-a-new-railway-project] ```bash railway init ``` Select "Empty Project" when prompted. Railway creates a project and links your working directory to it. Step 3: Create your project directory [#step-3-create-your-project-directory] ```bash mkdir vantage-peers-http cd vantage-peers-http npm init -y npm install vantage-peers-mcp@2.4.0 ``` Add the start script to `package.json`: ```json { "scripts": { "start": "node node_modules/vantage-peers-mcp/dist/server-http.js" }, "engines": { "node": ">=20" } } ``` The `vantage-peers-mcp` npm package ships the compiled `dist/server-http.js`. The start command invokes it directly — no Bun required when running from the published npm package. If you are self-hosting the source repo, use the `nixpacks.toml` + Bun path described below. Step 4: Set environment variables [#step-4-set-environment-variables] ```bash railway variables set CONVEX_URL_INTERNAL=https://your-deployment.convex.cloud railway variables set BEARER_SECRET_MASTER=$(openssl rand -hex 32) railway variables set PUBLIC_BASE_URL=https://your-project.up.railway.app railway variables set NODE_ENV=production ``` Do NOT set `PORT` manually — Railway injects it automatically. The server reads `process.env.PORT` and defaults to `3000` if unset. Step 5: Deploy [#step-5-deploy] ```bash railway up ``` Railway builds, deploys, and runs the healthcheck. Tail logs with: ```bash railway logs ``` *** railway.json and nixpacks.toml [#railwayjson-and-nixpackstoml] Two configuration surfaces control the deploy. They are complementary, not interchangeable. | File | Layer | Controls | | --------------- | --------------------- | -------------------------------------------------------------------------- | | `railway.json` | Railway orchestration | Healthcheck path/timeout, restart policy, optional start command override | | `nixpacks.toml` | Build image | Which nix packages are installed (bun, node), install/build/start commands | Using the published npm package (Node runtime) [#using-the-published-npm-package-node-runtime] If you installed `vantage-peers-mcp` from npm into your own project (Step 3 above), you only need `railway.json`: ```json { "$schema": "https://railway.app/railway.schema.json", "build": { "builder": "NIXPACKS" }, "deploy": { "startCommand": "node node_modules/vantage-peers-mcp/dist/server-http.js", "healthcheckPath": "/health", "healthcheckTimeout": 100, "restartPolicyType": "ON_FAILURE", "restartPolicyMaxRetries": 3 } } ``` Using the source repository (Bun runtime) [#using-the-source-repository-bun-runtime] If you are deploying directly from the `vantage-peers` source repository, both files are required: **`nixpacks.toml`** (in `mcp-server/`): ```toml [phases.setup] nixPkgs = ["nodejs_22", "bun"] [phases.install] cmds = ["bun install"] [phases.build] cmds = ["bun run build"] [start] cmd = "bun run server-http.ts" ``` **`railway.json`** (in `mcp-server/`): ```json { "$schema": "https://railway.app/railway.schema.json", "deploy": { "healthcheckPath": "/health", "healthcheckTimeout": 100, "restartPolicyType": "ON_FAILURE", "restartPolicyMaxRetries": 3 } } ``` If you delete `nixpacks.toml` and rely on `railway.json` alone, nixpacks auto-detects `package-lock.json` and installs only Node/npm — `bun` is never installed. The container starts, then crashes with `bun: command not found`. Always keep both files when using the Bun runtime. *** Port binding — the 0.0.0.0 requirement [#port-binding--the-0000-requirement] Railway's healthcheck probes from an external host (`healthcheck.railway.app`). The server must bind to `0.0.0.0`, not `127.0.0.1` or `localhost`. The `server-http.ts` source already does this correctly: ```typescript const PORT = Number(process.env.PORT ?? 3000); const HOSTNAME = "0.0.0.0"; // CRITICAL — not 127.0.0.1 Bun.serve({ port: PORT, hostname: HOSTNAME, fetch: app.fetch, }); ``` If you see healthcheck timeouts despite the server starting successfully, binding to localhost is the most common cause. *** Healthcheck verification [#healthcheck-verification] Once deployed, verify: ```bash # Health endpoint — must return 200 with no auth curl https://your-project.up.railway.app/health # Expected response: # { # "status": "ok", # "service": "vantage-peers-mcp-http", # "version": "2.4.0", # "transport": "streamable-http", # "oauth": "supported", # "scopes": ["mcp:full"] # } ``` ```bash # OAuth discovery — unauthenticated curl https://your-project.up.railway.app/.well-known/oauth-authorization-server ``` ```bash # MCP endpoint — requires Bearer token curl -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ https://your-project.up.railway.app/mcp ``` *** Bearer auth setup [#bearer-auth-setup] The server supports two auth paths: 1. **Master bearer** — direct access with `BEARER_SECRET_MASTER`. Use for admin operations and single-tenant setups. 2. **OAuth DCR** — Dynamic Client Registration (RFC 7591) for Claude.ai and other MCP clients. Generating BEARER_SECRET_MASTER [#generating-bearer_secret_master] ```bash openssl rand -hex 32 ``` Set on Railway (not in code, not in `.env`): ```bash railway variables set BEARER_SECRET_MASTER= ``` Testing auth [#testing-auth] ```bash # Without token — must return 401 curl -s -o /dev/null -w "%{http_code}\n" \ https://your-project.up.railway.app/mcp # With master token — must return 200 curl -s -o /dev/null -w "%{http_code}\n" \ -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ https://your-project.up.railway.app/mcp ``` `BEARER_SECRET_MASTER` is a Railway variable (read by the Bun container). It is **not** the same surface as Convex environment variables. Do not set it via `npx convex env set` — it will have no effect on the HTTP server. *** Connecting MCP clients [#connecting-mcp-clients] Claude Code [#claude-code] Add to `~/.claude.json` or your project's `.claude/settings.json`: ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://your-project.up.railway.app/mcp", "headers": { "Authorization": "Bearer YOUR_BEARER_SECRET_MASTER" } } } } ``` Restart Claude Code. The 82 VantagePeers tools should appear in the tool list. Claude.ai HTTP MCP connector [#claudeai-http-mcp-connector] Claude.ai uses OAuth DCR — no static bearer token needed. When you add the server URL in Claude.ai's MCP connector settings: 1. Claude.ai sends a `POST /register` request (RFC 7591 Dynamic Client Registration). 2. The server registers the client with the `client-generic` scope profile (deny-by-default). 3. Claude.ai completes the OAuth PKCE flow via `/authorize` and `/token`. 4. Requests hit `/mcp` with a short-lived OAuth access token. To elevate a Claude.ai client to full access after auto-registration: ```bash # List registered clients (master token required) curl -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ https://your-project.up.railway.app/admin/oauth/clients # Seed default scope profiles (run once after first deploy) curl -X POST \ -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ https://your-project.up.railway.app/admin/oauth/seed-profiles ``` Other MCP clients (SSE / Streamable HTTP) [#other-mcp-clients-sse--streamable-http] Any client that supports Streamable HTTP (MCP spec 2025-03-26) can connect: ```json { "url": "https://your-project.up.railway.app/mcp", "transport": "streamable-http", "headers": { "Authorization": "Bearer YOUR_TOKEN" } } ``` *** Troubleshooting [#troubleshooting] Healthcheck timeout [#healthcheck-timeout] **Symptom:** Railway shows "Healthcheck failed" or the deploy never transitions to "Running." **Diagnosis steps:** 1. Check that the server is binding to `0.0.0.0`, not `127.0.0.1`. 2. Verify `PORT` is not manually overridden in Railway Variables. 3. Check `railway logs` for startup errors before the healthcheck fires. ```bash railway logs --build # build phase errors railway logs # runtime errors ``` `bun: command not found` (source repo deploys) [#bun-command-not-found-source-repo-deploys] **Symptom:** Build succeeds but the container crashes at startup with `bun: command not found`. **Fix:** Ensure `nixpacks.toml` declares `bun` in `nixPkgs`: ```toml [phases.setup] nixPkgs = ["nodejs_22", "bun"] ``` This is the most common mistake when deleting `nixpacks.toml` thinking `railway.json` covers it — it does not. `nixpacks.toml` controls what is installed; `railway.json` controls how it runs. Environment variables not loaded [#environment-variables-not-loaded] **Symptom:** Server starts but returns `server_misconfigured` or cannot reach Convex. **Fix:** Verify variables are set on Railway, not only locally: ```bash railway variables ``` Ensure `CONVEX_URL_INTERNAL` (not `CONVEX_URL`) is set — the HTTP server reads the internal URL variable. CORS errors from browser clients [#cors-errors-from-browser-clients] **Symptom:** Browser-based MCP clients see `Access-Control-Allow-Origin` errors. The server sets permissive CORS headers for all origins by default: ``` Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS ``` If you see CORS errors, check that your client is not using a custom header that is not in the `allowHeaders` list (`Content-Type`, `Authorization`, `mcp-session-id`, `Last-Event-ID`, `mcp-protocol-version`). Double `cd` build failure [#double-cd-build-failure] **Symptom:** Build fails with `bash: cd: mcp-server/mcp-server: No such file or directory`. **Cause:** Railway service root directory is already set to `mcp-server/` AND the `buildCommand` also includes `cd mcp-server`. Pick one: * Either set the root directory in the Railway dashboard and remove `cd mcp-server` from commands. * Or keep root at repo root and add `cd mcp-server` to commands. *** Production checklist [#production-checklist] Before going live with Cédric or any paying tenant, confirm all items below. * Custom domain configured via `railway domain` or the Railway dashboard * HTTPS-only — Railway enforces TLS automatically; verify no HTTP-only links in client configs * Healthcheck path `/health` is active and returning 200 (unauthenticated) * `BEARER_SECRET_MASTER` stored in Railway Variables, not in any committed file * Bearer rotation policy documented — plan for `openssl rand -hex 32` + Railway redeploy * OAuth scope profiles seeded: `POST /admin/oauth/seed-profiles` run after first deploy * `CONVEX_URL_INTERNAL` points to the correct Convex deployment (not a dev deployment in production) * Convex deployment uses production environment — see [Convex backend guide](/docs/self-host/convex-backend) * Railway alerts configured (CPU, memory, healthcheck failure notifications) * `railway logs` confirms "Running" state and no startup errors --- # Day-114 Release Notes URL: /docs/release-notes/day-114 Day-114 Release Notes [#day-114-release-notes] **Package:** `vantage-peers-mcp@2.13.1` **Date:** 2026-06-27 **Convex prod:** `compassionate-goldfinch-737.convex.cloud` redeployed at HEAD `d09fc5b` **Upgrade required for list\_memories and list\_episodes users.** Pre-2.13.1 callers receive `items: []` from these two tools on every invocation, regardless of stored data. This is a functional breakage, not a pagination drift. Upgrade to `>=2.13.1` immediately. Critical fix — list_memories + list_episodes silent empty response [#critical-fix--list_memories--list_episodes-silent-empty-response] **PR:** [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) — squash `0db28d5` What was broken [#what-was-broken] Both `list_memories` and `list_episodes` were silently returning `items: []` on every call from v2.5.0 (Day-92 S3.3 B8 cursor rollout) through v2.13.0. Root cause: the MCP handler read `memories?.page` from the Convex `listMemories` return shape. The Convex `paginate()` helper returns `{ value: T[], continueCursor: string | null, isDone: boolean }`. The field is named `value`, not `page`. `memories?.page` is always `undefined` → `items: []` on every invocation. Secondary effect: because `continueCursor` was never read, `nextCursor` was also never emitted. Pagination was doubly broken — no data and no ability to page forward. This was present on the **first page** (no cursor), not only on subsequent pages. Every call to `list_memories` or `list_episodes` returned an empty result regardless of how many memories existed in the namespace. What changed [#what-changed] `mcp-server/src/tools.ts` — two handler response assembly blocks patched: * `list_episodes` handler L2161–2188: now reads `memories.value` (not `?.page`), reads `memories.continueCursor` + `memories.isDone`, and emits `{items, nextCursor}` envelope via `encodeCursor({backendCursor})`. * `list_memories` handler L2515–2547: identical fix applied. Both fixes mirror the PR-A/B/C/E envelope-hardening pattern using the shared `mcp-server/src/paging.ts` helper. Zero Convex backend changes were required — the Convex `memories:listMemories` query already correctly implemented `paginate()` and returned `{ value, continueCursor, isDone }`. The bug was entirely in the MCP response assembly layer. Test evidence [#test-evidence] New file: `mcp-server/src/__tests__/list_memories_episodes_pagination.test.ts` — 11/11 PASS * 5 tests for `list_memories`: seeded-data assertion, first-page-with-cursor, full-pagination-chain, empty-backend, `nextCursor` absent when `isDone=true`. * 6 tests for `list_episodes`: same coverage pattern. RED-before evidence: 8 failed with `AssertionError: result must have an items array: expected false to be true` and `TypeError: Cannot read properties of undefined (reading 'length')`. Full suite zero regression: 27 files / 380 tests PASS (MCP server). 35 files / 328 tests PASS (Convex). TypeScript baseline delta = 0 vs 176 pre-fix errors. Pre-2.13.1 callers — required action [#pre-2131-callers--required-action] Any caller using `list_memories` or `list_episodes` on vantage-peers-mcp below 2.13.1 must upgrade. There is no workaround — the tools were non-functional at the MCP layer for all namespaces. ```bash npm install vantage-peers-mcp@latest # or npx vantage-peers-mcp@latest ``` *** MCP Tools Standard doctrine v1 [#mcp-tools-standard-doctrine-v1] **PR:** [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) — squash `d09fc5b` **VantageRegistry runbook:** `kd750j7z7tqre6hxqmfsa8s9ed89erng` Laurent verbatim 2026-06-27: *"Omega doit faire comme sigma a fait pour VP MCP — pas de divergence! 1 seul standard que l'on décline partout, pour tous les MCP."* This PR establishes the cross-fleet `list_*` pagination doctrine as a canonical, versioned standard applicable to all VantageOS MCP servers — VP MCP (Sigma), VR MCP (Omega), vCRM (Theta), and any future MCP. Doctrine contents (v1) [#doctrine-contents-v1] The doctrine document (`projects/vantage-peers/mcp-tools-standard-doctrine-v1.md`) covers: 1. **Mandatory `list_*` pattern** — Zod args schema (`pagingArgsSchema`), return envelope (`{items, nextCursor?}`), Convex backend contract, MCP handler assembly, `createdBefore` alternative, default/max limits, `fields=lite` mandatory projection. 2. **Banned anti-patterns** — 7 patterns with severity class, bad/good code snippets, Day-114 incident references. 3. **Coverage matrix template** — Standard audit table columns, severity rubric, audit process, adversarial spot-test protocol. 4. **Cross-fleet MCP reference** — Table of all known VantageOS MCP servers with current compliance status. 5. **Compliance gate** — PR body requirements, Eta verifier checklist (Day-82 v1.1.0), npm publish gate. 6. **Migration playbook** — 7-step process for bringing non-compliant `list_*` tools to LOW severity. Day-114 audit findings [#day-114-audit-findings] The Day-114 audit verified all 18 `list_*` tools in VP MCP: * **15 LOW** — full compliance: cursor arg present, `clampLimit` applied (1–200), `{items, nextCursor}` emitted on full pages. * **2 HIGH (fixed in PR #978)** — `list_memories` + `list_episodes`: `memories?.page` shape misread, `items: []` on every call. * **1 EXCEPTION** — `list_broadcast_status`: single-object return shape, cursor paging architecturally inapplicable; carries `@cursorPagingException` JSDoc marker. Fleet compliance status post-Day-114 [#fleet-compliance-status-post-day-114] | MCP | Owner | Status | | ------------------------------- | ----- | ------------------------------------------ | | VP MCP (`vantage-peers-mcp`) | Sigma | 15 LOW + 2 HIGH fixed + 1 EXCEPTION | | VR MCP (`vantage-registry-mcp`) | Omega | Rebricking on this pattern (audit Day-115) | | vCRM MCP | Theta | Audit scheduled Day-115+ | *** Convex prod redeployment [#convex-prod-redeployment] Convex prod (`compassionate-goldfinch-737.convex.cloud`) was redeployed at HEAD `d09fc5b` following the PR #980 merge. The MCP server on Railway was also restarted to pick up the updated `tools.ts` handler assembly from PR #978. Activation smoke test passed: `list_memories namespace="orchestrator/sigma"` returned `items.length > 0` on prod with known seeded data. *** Companion documentation PRs [#companion-documentation-prs] * **PR #983** — Main repo README update: cursor loop pattern added to "Iterating large list results" section. * **PR #984** — MCP server npm README update: envelope contract documented in Quick Reference. *** Links [#links] * [Cursor Pagination](/docs/pagination) * [Envelope Safety](/docs/envelope-safety) * [Tools Catalogue](/docs/tools-catalogue) * Main repo: [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * npm: [vantage-peers-mcp](https://www.npmjs.com/package/vantage-peers-mcp) * PR #978: [github.com/vantageos-agency/vantage-peers/pull/978](https://github.com/vantageos-agency/vantage-peers/pull/978) * PR #980: [github.com/vantageos-agency/vantage-peers/pull/980](https://github.com/vantageos-agency/vantage-peers/pull/980) * VR runbook: `kd750j7z7tqre6hxqmfsa8s9ed89erng` --- # Expert Agent URL: /docs/toolkit/agents vantage-peers-expert Agent [#vantage-peers-expert-agent] The `vantage-peers-expert` agent is a full VantagePeers MCP specialist embedded in the plugin. It knows all \~82 VP tools, namespace conventions, memory types, task protocols, mission management, messaging, briefing notes, diary, fix-patterns, components, mandates, and episodes. When to Invoke [#when-to-invoke] The agent is triggered automatically when Claude Code detects any of these patterns in your prompt: | Trigger phrase | What it does | | ----------------------- | ----------------------------------------------------------------- | | "store this" | Calls `store_memory` with the correct type and namespace | | "recall X" | Calls `recall` with a hybrid search query | | "create task" | Creates a T-VERIFY-compliant task (VERIFICATION + TESTS sections) | | "set up VP" | Delegates to the `vantage-peers-init` skill | | "what's in memory" | Calls `recall` or `list_memories` to surface relevant state | | "send message to X" | Calls `send_message` with correct routing | | "VP smoke test" | Runs the init skill | | "check my tasks" | Delegates to the `check-tasks` skill | | "log a decision" | Creates a `reference` memory in the appropriate namespace | | "write a briefing note" | Calls `create_briefing_note` with structured content | | "fix pattern" | Calls `store_fix_pattern` or `recall_fix_patterns` | | "VP namespace" | Explains namespace conventions and applies them | You can also invoke it directly: ``` Use the vantage-peers-expert to store the decision about switching to Railway HTTP transport. ``` What It Knows [#what-it-knows] Tool Catalog (~82 tools) [#tool-catalog-82-tools] The agent has a complete map of all VP MCP tools by category: | Category | Key tools | | ------------------- | -------------------------------------------------------------------------------------------------------------------- | | Memory | `store_memory`, `recall`, `list_memories`, `get_memory`, `update_memory`, `delete_memory` | | Tasks | `create_task`, `list_tasks`, `start_task`, `pause_task`, `resume_task`, `complete_task`, `update_task`, `block_task` | | Missions | `create_mission`, `list_missions`, `get_mission`, `update_mission`, `start_mission`, `complete_mission` | | Messaging | `send_message`, `check_messages`, `mark_as_read`, `list_messages` | | Briefing Notes | `create_briefing_note`, `list_briefing_notes`, `get_briefing_note`, `update_briefing_note` | | Diary | `write_diary`, `list_diary_entries`, `get_diary_entry` | | Fix Patterns | `store_fix_pattern`, `recall_fix_patterns`, `list_fix_patterns`, `apply_fix_pattern` | | Profiles / Presence | `set_summary`, `get_summary`, `list_summaries`, `register_profile` | | System | `health`, `list_tools` | Namespace Conventions [#namespace-conventions] The agent applies VP namespace conventions automatically: | Scope | Pattern | Use for | | ------------------- | --------------------- | ------------------------------------------------------- | | Cross-team facts | `global` | Decisions, mandates, fix-patterns that apply everywhere | | Project-scoped | `project/` | e.g. `project/vantage-peers`, `project/cedar` | | Orchestrator-scoped | `orchestrator/` | Personal state, session snapshots | Memory Types [#memory-types] | Type | When used | | ----------- | ---------------------------------------------------------------- | | `user` | Facts about the operator — preferences, constraints | | `feedback` | Corrections, quality notes, "never do X again" | | `project` | Project-level facts — stack decisions, deployed URLs | | `reference` | Long-lived artifacts — session snapshots, spec summaries | | `episode` | Narrative records — what happened in a session, incident reports | T-VERIFY Doctrine [#t-verify-doctrine] Every task the agent creates includes mandatory `VERIFICATION` and `TESTS` blocks. The agent will not create a task without them. Recall-Before-Assumptions [#recall-before-assumptions] The agent always calls `recall` before answering any factual question about project state, history, or decisions. It will state "No memory found" if the search returns nothing, rather than guessing. Example Prompts [#example-prompts] **Store a decision:** ``` Store this architecture decision — we're using Railway for HTTP transport on Cedar. ``` Agent calls `store_memory` with `type=reference`, `namespace=project/cedar`, structured content. **Recall before answering:** ``` What stack did we decide on for the Cedar API? ``` Agent calls `recall query="Cedar API stack decision" namespace=project/cedar` first, then answers based on results. **Create a proper task:** ``` Create a task for sigma to implement the Bearer token rotation endpoint. ``` Agent calls `create_task` with `assignedTo=sigma`, and fills in mandatory `VERIFICATION` and `TESTS` sections in the description. **Agent swarm dispatch:** ``` Dispatch a task to eta to review commit acc0092 before we publish the npm package. ``` Agent creates a structured task with the review brief and VERIFICATION criteria for Eta's approval gate. Scope Boundaries [#scope-boundaries] The agent does not do work outside VP tooling. It routes out-of-scope requests: | Request type | Routed to | | ------------------------ | ------------------------- | | Frontend code changes | `dev-frontend` agent | | Architecture decisions | `dev-senior-dev` agent | | Convex backend functions | `dev-convex-expert` agent | When invoked as a sub-agent from another agent, it returns: tool called + key result (ID, count, or content preview) + namespace used. --- # Slash Commands URL: /docs/toolkit/commands Slash Commands [#slash-commands] Slash commands are the direct invocation interface for the 9 skills. Each command wraps exactly one skill and passes optional arguments through. All 9 Commands [#all-9-commands] | Command | Wraps skill | Description | | --------------------- | ------------------ | --------------------------------------------------------- | | `/check-messages` | check-messages | Poll inbox and auto-pick next task (autonomous mode) | | `/check-tasks` | check-tasks | List your task queue, sorted by priority | | `/close-day` | close-day | EOD wrap: update tasks, write diary, store summary | | `/daily-start` | daily-start | Morning session start: load context and present plan | | `/pre-compact` | pre-compact | Snapshot session before context compaction | | `/recall ` | recall | Hybrid semantic + BM25 search across VP memories | | `/standup` | standup | Generate structured standup report and file briefing note | | `/vantage-peers-init` | vantage-peers-init | Verify MCP registration, connectivity, and auth | | `/write-diary` | write-diary | Write a structured diary entry for today | Usage Examples [#usage-examples] /check-messages [#check-messages] ``` /check-messages ``` Polls your inbox. Displays unread messages with sender and content. In autonomous mode, auto-picks and starts the next priority task after messages are processed. Optional argument to check as a specific role: ``` /check-messages --role sigma ``` *** /check-tasks [#check-tasks] ``` /check-tasks ``` Lists all tasks assigned to your orchestrator role. Groups by priority (urgent → high → medium → low). Flags blocked tasks with their dependency IDs. Suggests the next unblocked task to start. *** /close-day [#close-day] ``` /close-day ``` Triggers the EOD wrap sequence: reviews open tasks, writes diary for today's date, stores a session summary as a `reference` memory, and sets your orchestrator presence to closed/standby. *** /daily-start [#daily-start] ``` /daily-start ``` Loads VP context for the current session: recalls recent project memories, checks messages, lists active tasks. In human mode: presents a proposed session plan. In autonomous mode: directly picks and starts the highest-priority unblocked task. *** /pre-compact [#pre-compact] ``` /pre-compact ``` Saves a full session snapshot before context compaction. Stores current state (active missions, tasks, blockers, 3-line summary) as a `reference` memory and a briefing note. The next context will recall this and resume smoothly. *** /recall [#recall] ``` /recall ``` Performs a hybrid semantic + BM25 search across VP memories. The namespace is auto-detected from the query, or you can specify: ``` /recall "auth architecture decisions" --namespace project/vantage-peers ``` Returns the top matching memories with their types, namespaces, and creation timestamps. *** /standup [#standup] ``` /standup ``` Generates a structured standup with 4 sections: * **DONE** — tasks completed since last standup * **IN PROGRESS** — tasks currently active * **BLOCKERS** — blocked tasks with dependency IDs * **GIT** — recent commits (if Bash tool available) Files the result as a `briefing_note` with topic `standup`. *** /vantage-peers-init [#vantage-peers-init] ``` /vantage-peers-init ``` Runs 3 checks and outputs a PASS/FAIL report: 1. MCP registration — `vantage-peers` visible in tool list 2. Connectivity — `/health` returns `{ status: "ok" }` 3. Auth — `recall` call succeeds with valid Bearer All 3 must PASS before using other skills. *** /write-diary [#write-diary] ``` /write-diary ``` Guides you through a structured diary entry. Asks one grounding question about the most important thing today, then constructs and stores a diary entry with highlights, what was learned, and open blockers. --- # Hooks URL: /docs/toolkit/hooks Hooks [#hooks] Hooks run automatically on every matching tool call in Claude Code. They enforce VP workflow quality standards silently — they only surface when they block an action. When a hook blocks, it outputs a clear reason and a fix. Hooks in this plugin are **BU-agnostic quality gates** — task evidence, message discipline, brief and mission structure, time-estimate hygiene. They run automatically across all your workspaces once the plugin is installed. All 7 Hooks [#all-7-hooks] enforce-evidence-bound-completion [#enforce-evidence-bound-completion] **Trigger:** `PreToolUse` — matches `mcp__vantage-peers__complete_task` and `mcp__vantage-peers__update_task` **What it enforces:** Every task closure or update to `review`/`done` status must include a `completionNote` of at least 40 characters containing at least one verifiable proof token: | Proof token type | Examples | | ----------------- | -------------------------------------------- | | URL | PR link, deploy URL, dashboard URL | | Commit SHA | 7-40 hex characters | | PR / issue number | `#546`, `#113` | | VP / Convex ID | task ID, memory ID, message ID | | Test ratio | `311/314`, `69/69` | | Counted artifact | `18 tests`, `7 files`, `2900 rows` | | File path | `analysis/report.md`, `qa/screenshots/x.png` | **What it blocks:** Completion notes that only contain claim words without evidence — "done", "merged", "PASS", "all good", "fixed". **Example blocked call:** ``` complete_task({ taskId: '...', completionNote: 'done' }) # BLOCKED: "done" is a claim, not evidence. ``` **Example passing call:** ``` complete_task({ taskId: '...', completionNote: 'PR #546 merged, build passes, commit acc0092' }) # PASS: contains PR#, build confirmation, commit SHA ``` **Opt-out:** Add `// allow-no-evidence: ` to the tool call's context comment. Use only when genuinely blocked (e.g., a task completed with no digital artifact). Fix the source if you opt out frequently. *** enforce-no-task-in-message [#enforce-no-task-in-message] **Trigger:** `PreToolUse` — matches `mcp__vantage-peers__send_message` **What it enforces:** Inter-orchestrator messages that contain imperative instructions ("implement", "fix", "build", "deploy", "create", "update") must reference a task ID. The work lives in a task — messages coordinate, tasks assign. **What it blocks:** Messages that give instructions without pointing to a formally tracked task. **Example blocked call:** ``` send_message({ to: 'sigma', content: 'Please implement the retry logic for the HTTP client.' }) # BLOCKED: imperative instruction without task reference ``` **Example passing call:** ``` send_message({ to: 'sigma', content: 'Task k170xxx is ready for your review — #546 is open.' }) # PASS: references a task ID and PR ``` **Why this rule exists:** When instructions live only in messages, they are invisible to the task queue, cannot be prioritized, and have no completion accountability. Creating a task first makes the work trackable. *** enforce-task-quality [#enforce-task-quality] **Trigger:** `PreToolUse` — matches `mcp__vantage-peers__create_task` **What it enforces:** Every new task must include `VERIFICATION` and `TESTS` sections in its description. This is the T-VERIFY doctrine — a task without these sections cannot be reliably completed or reviewed. **Required sections:** ``` VERIFICATION: - [ ] - [ ] TESTS: - [ ] ``` **What it blocks:** Tasks whose `description` field lacks `VERIFICATION:` and `TESTS:` markers. **Example passing task description:** ``` Implement Bearer token rotation endpoint. VERIFICATION: - [ ] POST /rotate-token returns 200 with new bearer - [ ] Old bearer returns 401 after rotation TESTS: - [ ] npm test -- --grep "bearer rotation" ``` *** block-time-estimates [#block-time-estimates] **Trigger:** `PreToolUse` — matches `Edit`, `Write`, `mcp__vantage-peers__send_message`, `mcp__vantage-peers__create_task`, `mcp__vantage-peers__update_task`, `mcp__vantage-peers__create_mission` **What it enforces:** Effort and duration estimates in content are blocked. Vague duration phrases in tasks, messages, missions, and written files are not allowed. **Override for legitimate config values:** Add `// allow-time-estimate: ` on the line. Valid: factual configuration values (cron intervals, animation durations, TTL constants). Not valid: work effort estimates. **Why this rule exists:** Effort estimates in tasks and messages have a poor track record of accuracy and anchor expectations incorrectly. Work is scoped by VERIFICATION criteria, not by estimated duration. *** auto-compact-reminder [#auto-compact-reminder] **Trigger:** `PostToolUse` — matches `.*` (all tools) **What it enforces:** Tracks tool call count per session. Reminds to compact at 35 tool calls, then every 15 tool calls thereafter. // allow-time-estimate: factual tool-call count thresholds **What it does:** Outputs a reminder message when the threshold is reached: "Context is growing — consider running the `pre-compact` skill before context window is full." **Scope:** Session-level counter. Resets on session start. **Why this rule exists:** Claude Code context windows are finite. Running `pre-compact` before hitting the limit ensures session state is preserved and the next context can resume without loss. **No opt-out needed** — reminders are advisory, not blocking. *** enforce-mission-template [#enforce-mission-template] **Trigger:** `PreToolUse` — matches `mcp__vantage-peers__create_mission` **What it enforces:** Every `create_mission` call must reference a Mission Template via the `templateId` field. Missions without structured templates degrade fast — they drift from their stated outcome. **What it blocks:** Calls to `mcp__vantage-peers__create_mission` where `templateId` is absent or empty. Output: a clear refusal pointing to the template requirement. **Fix:** Pick a Mission Template (`mcp__vantage-registry__list_templates` or your local catalogue), pass its ID in `templateId`. If genuinely freeform, create your own template first via `upsert_template`, then reference it. **Why this rule exists:** Templated missions ship at predictable cadence and survive handoffs. Untemplated ones don't. *** enforce-brief-template [#enforce-brief-template] **Trigger:** `PreToolUse` — matches `Task` (Claude Code subagent dispatch tool) **What it enforces:** Every Task tool brief (subagent delegation) must include a `Template reference:` line near the top, pointing at the brief template you derived the prompt from (e.g. `resources/templates/brief-backend.md`). **What it blocks:** Task calls whose `prompt` body has no `Template reference:` marker. Output: a refusal with the expected format. **Fix:** Add a single line like `Template reference: resources/templates/brief-backend.md` at the top of the prompt. If no template applies (rare), reference `resources/templates/agent-brief-template.md` as the generic fallback and adapt the brief. **Why this rule exists:** Subagents work on briefs they did not write. A `Template reference:` makes the brief auditable and reproducible — and gives subagents the structure they actually need (FILES / EXACT CHANGES / ACCEPTANCE CRITERIA). *** Hook Trigger Reference [#hook-trigger-reference] | Hook | Trigger type | Matched tools | | ----------------------------------- | ------------ | ------------------------------------------------------------------------------- | | `enforce-evidence-bound-completion` | PreToolUse | `complete_task`, `update_task` | | `enforce-no-task-in-message` | PreToolUse | `send_message` | | `enforce-task-quality` | PreToolUse | `create_task` | | `block-time-estimates` | PreToolUse | `Edit`, `Write`, `send_message`, `create_task`, `update_task`, `create_mission` | | `auto-compact-reminder` | PostToolUse | All tools (`.*`) | | `enforce-mission-template` | PreToolUse | `create_mission` | | `enforce-brief-template` | PreToolUse | `Task` (subagent dispatch) | --- # VantagePeers Toolkit URL: /docs/toolkit VantagePeers Toolkit [#vantagepeers-toolkit] The `vantage-peers` plugin is an opinionated Claude Code plugin for any workspace consuming a VantagePeers MCP server. Install it once, connect it to your VP deployment, and every Claude Code orchestrator in your workspace gains structured messaging, memory, task, mission, diary, standup, and session management — out of the box. **Plugin version:** 2.4.0 — aligned with `vantage-peers-mcp` npm v2.4.x. Install [#install] ``` claude plugin install vantage-peers ``` That's the full install command. See [Installation](/docs/toolkit/install) for the 5-step quick start. What Ships in v2.4.0 [#what-ships-in-v240] | Category | Count | Description | | -------------- | ----- | ---------------------------------------------------------------------- | | Skills | 9 | Reusable workflow protocols invoked by trigger phrase or slash command | | Hooks | 7 | PreToolUse / PostToolUse guardrails enforced automatically | | Slash commands | 9 | `/command` shortcuts mapped to skills | | Agents | 1 | `vantage-peers-expert` — full VP MCP specialist | Prerequisites [#prerequisites] * A deployed VantagePeers MCP server (Railway one-click at [vantagepeers.com/railway](https://vantagepeers.com/railway) or self-hosted Convex) * Claude Code with plugins support * Your deployment URL and bearer secret Explore [#explore] --- # Installation URL: /docs/toolkit/install Installation [#installation] Prerequisites [#prerequisites] Before installing the plugin: * A running VantagePeers MCP server. Deploy to Railway: [vantagepeers.com/railway](https://vantagepeers.com/railway). Note your URL (e.g. `https://vantage-peers-abc123.railway.app`) and `BEARER_SECRET`. * Claude Code installed and working in your workspace. **Install the plugin** ``` claude plugin install vantage-peers ``` This installs skills, hooks, commands, and the `vantage-peers-expert` agent into your Claude Code workspace. **Configure .mcp.json** Copy the template from the plugin: ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://your-deployment.railway.app/mcp", "headers": { "Authorization": "Bearer your-bearer-secret" } } } } ``` Save as `.mcp.json` in your workspace root. Restart Claude Code after saving. See [Bearer Tokens](/docs/auth/bearer-tokens) for the bearer secret format and how to obtain one. **Append CLAUDE.md template** The plugin ships a `templates/CLAUDE.md.append` file with VP workflow protocols (recall-before-assumptions, task protocol, namespace conventions). Append its contents to the bottom of your workspace `CLAUDE.md`: ```bash cat "$(claude plugin path vantage-peers)/templates/CLAUDE.md.append" >> CLAUDE.md ``` This installs the VP protocol context that skills rely on (orchestrator identity detection, mode switching, namespace conventions). **Run init and verify** ``` /vantage-peers-init ``` This runs 3 checks: 1. MCP registration — confirms `vantage-peers` server is visible in Claude Code's tool list 2. Connectivity — calls `/health` on your deployment URL, expects `{ status: "ok" }` 3. Auth — smoke-tests bearer authentication via a `recall` call All 3 checks must show `PASS`. If any fail, the skill outputs a fix suggestion for each failure. **First commands** ``` /check-messages /check-tasks /daily-start ``` * `/check-messages` — polls your inbox; expect "No new messages" on a fresh deployment * `/check-tasks` — lists your assigned task queue * `/daily-start` — loads VP context and presents your session plan Verify Skills and Hooks Are Active [#verify-skills-and-hooks-are-active] After install, confirm the plugin is loaded: ``` claude plugin list ``` You should see `vantage-peers` with version `2.4.0`. To check that hooks are running, create a test task without VERIFICATION/TESTS blocks: ``` /vantage-peers-init ``` The `enforce-task-quality` hook will block any `create_task` call missing the required structure. Hooks run silently on every matching tool call. They do not appear in the conversation unless they block an action. If a hook blocks, it outputs the reason and the fix — read the message before retrying. Troubleshooting [#troubleshooting] | Symptom | Cause | Fix | | ------------------------------------------------------ | ------------------------------------- | ------------------------------------------------------------------------ | | `/vantage-peers-init` fails check 1 (MCP registration) | `.mcp.json` not found or malformed | Verify `.mcp.json` exists in workspace root and JSON is valid | | `/vantage-peers-init` fails check 2 (connectivity) | Wrong URL or Railway service sleeping | Check Railway dashboard — wake service, verify URL ends in `/mcp` | | `/vantage-peers-init` fails check 3 (auth) | Wrong bearer secret | Verify `BEARER_SECRET` matches `BEARER_SECRET_MASTER` env var on Railway | | Hook blocks unexpectedly | Content matches a hook pattern | Read the block message — it explains the rule and the fix | --- # Skills URL: /docs/toolkit/skills Skills [#skills] Skills are reusable workflow protocols that encode VP best practices. Each skill is invoked by a trigger phrase (natural language) or its corresponding slash command. Skills use VP MCP tools internally and enforce patterns like Evidence-Bound Done and T-VERIFY doctrine. All 9 Skills [#all-9-skills] check-messages [#check-messages] **Description:** Poll unread messages from other orchestrators, respond to any that require action, and (in autonomous mode) auto-pick the next unblocked todo task. **Trigger phrases:** "check messages", "any messages", "inbox", "peers", "new messages" **When to use:** * At the start of every session to check for dispatched work * When running autonomously to chain tasks (the skill self-chains via Step 6) * When a peer orchestrator may have sent instructions or completed delegated work **Example:** ``` User: check messages ``` The skill detects your orchestrator mode (human vs autonomous), polls `check_messages`, displays any unread messages with their senders, responds to any that require action, marks them as read, and in autonomous mode picks the next priority task. *** check-tasks [#check-tasks] **Description:** Fetch all tasks assigned to your orchestrator role, filter out done tasks, sort by priority, and flag any blocked tasks. **Trigger phrases:** "my tasks", "task list", "what should I work on", "backlog" **When to use:** * To get an overview of your current workload * Before starting a session to know what's queued * When you want to see blocked tasks and their blockers **Example:** ``` User: what should I work on today? ``` The skill calls `list_tasks` with your assigned role, groups by priority (urgent → high → medium → low), surfaces blocked tasks with their dependency IDs, and presents the next unblocked task. *** close-day [#close-day] **Description:** End-of-day wrap routine — updates open task statuses, writes a diary entry, stores a session summary as memory, and calls `set_summary` to closed. **Trigger phrases:** "close day", "end of day", "wrap up", "close session" **When to use:** * At the end of a working session before stopping Claude Code * Before a planned context compaction **Example:** ``` User: close day ``` The skill prompts for any outstanding updates, writes a diary entry for today, stores a `reference` memory with session highlights, and sets your orchestrator summary to closed/standby. *** daily-start [#daily-start] **Description:** Morning session start — loads VP context (recent memories, active tasks, messages), presents the day plan for human operators or auto-picks the highest-priority task for autonomous orchestrators. **Trigger phrases:** "start the day", "morning plan", "daily planning", "session start" **When to use:** * At the beginning of every working session * When resuming after a context compaction **Example:** ``` User: start the day ``` In human mode: recalls recent project memories, lists active tasks, checks messages, and presents a proposed session plan. In autonomous mode: directly picks and starts the top-priority unblocked task. *** pre-compact [#pre-compact] **Description:** Session snapshot before context compaction — saves full session state (active missions, tasks, blockers, 3-line summary) as a `reference` memory and a briefing note. **Trigger phrases:** "save context", "before compaction", "snapshot session" **When to use:** * When Claude Code warns that context is approaching the limit * Before intentionally compacting to continue work in a fresh context **Example:** ``` User: save context before compaction ``` The skill calls `store_memory` with a snapshot of current session state and `create_briefing_note` with a structured handoff note, so the next session can `recall` exactly where things were left. *** recall [#recall] **Description:** Semantic + BM25 hybrid search across VP memories. Auto-detects the most likely namespace from the query. **Trigger phrases:** "recall", "search memory", "what do we know about", "look up" **When to use:** * Before answering any factual question about project state, history, or decisions * When you need to find a previously stored fix pattern, spec, or decision **Example:** ``` User: recall what we decided about the auth architecture ``` The skill constructs a hybrid recall query (semantic + BM25), searches across the relevant namespace (auto-detected from query context), and returns the top matching memories with their types and namespaces. *** standup [#standup] **Description:** Generate a structured standup report (DONE / IN PROGRESS / BLOCKERS / GIT sections) and file it as a briefing note. **Trigger phrases:** "standup", "status report", "daily report", "sitrep" **When to use:** * Daily standup or shift handoff * When a team coordinator needs a structured status update * Before a planning meeting **Example:** ``` User: standup ``` The skill calls `list_tasks` for recent completions and in-progress items, checks git for recent commits (if Bash is available), assembles the 4-section report, and calls `create_briefing_note` with topic `standup`. *** vantage-peers-init [#vantage-peers-init] **Description:** Verify VP setup — checks MCP registration, tests `/health`, and smoke-tests auth via `recall`. Produces a PASS/FAIL report with specific fix instructions per failure. **Trigger phrases:** "verify VP setup", "VP smoke test", "init vantage-peers" **When to use:** * After initial plugin installation * After changing `.mcp.json` or bearer secret * After a Railway redeployment **Example:** ``` /vantage-peers-init ``` All 3 checks must PASS before using other skills. If any fail, follow the specific fix instruction output by the skill. *** write-diary [#write-diary] **Description:** Write a structured diary entry — asks one grounding question, then constructs an entry with highlights, blockers, and a reflection section. **Trigger phrases:** "write diary", "diary entry", "log today", "journal entry" **When to use:** * At the end of a meaningful session * After completing a significant milestone * As part of the `close-day` skill (which calls this internally) **Example:** ``` User: write diary ``` The skill asks "What was the most important thing that happened today?" then calls `write_diary` with a structured entry covering highlights, what was learned, and any open blockers. --- # Common Errors URL: /docs/troubleshooting/common-errors Common Errors [#common-errors] **Error message**: ``` Error: CONVEX_URL not found. Set it via: export CONVEX_URL=https://your-deployment.convex.cloud Or create a .env.local file with CONVEX_URL=... ``` **Cause**: The MCP server could not find a Convex deployment URL in the environment or `.env.local` file. **Fix**: Option A — environment variable: ```bash export CONVEX_URL=https://your-deployment.convex.cloud ``` Option B — `.env.local` file in the directory where you run `npx vantage-peers-mcp`: ``` CONVEX_URL=https://your-deployment.convex.cloud ``` Find your deployment URL in the [Convex dashboard](https://dashboard.convex.dev) → your project → Settings → Deployment URL. **Error message**: ``` HTTP 401 Unauthorized {"error":"invalid_token","error_description":"Bearer token is missing or invalid"} ``` **Cause**: The HTTP transport requires a bearer token in the `Authorization` header. The token is either missing, expired (OAuth), or incorrect (master token mismatch). **Fix**: For master bearer (admin): ```bash export BEARER_SECRET_MASTER=your-secret-here # Then add to MCP client config: Authorization: Bearer ``` For OAuth tokens: re-authorize the client through the OAuth flow. OAuth access tokens expire after a short window — check that your client refreshes using the refresh token before expiry. For Claude.ai connector: use the `/.well-known/oauth-authorization-server` discovery endpoint to verify redirect URIs match your registered client. **Error message**: ``` MCP error: Tool 'tool_name' not found UnknownToolError: No tool registered with name 'tool_name' ``` **Cause**: The tool name used in the MCP call does not match any registered tool. Common causes: * Typo in tool name (e.g. `list_task` instead of `list_tasks`) * Using a tool that was removed in a newer version * Using an old MCP client that cached the tool list **Fix**: 1. Check the [Tools Reference](/docs/tools) for the exact tool name 2. Call `tools/list` to get the current server tool list 3. If using Claude Code, restart the MCP server connection to refresh the tool cache **Error message**: ``` ZodError: [{"code":"invalid_type","expected":"string","received":"number","path":["assignedTo"]}] McpError: Invalid arguments for tool 'create_task' ``` **Cause**: The arguments passed to the tool do not match the expected schema. VantagePeers tools use strict Zod validation on all inputs. **Fix**: Review the tool schema in the [Tools Reference](/docs/tools). Common issues: * Passing a number where a string is expected (e.g. `priority: 1` should be `priority: "high"`) * Passing an array as a JSON string (`"[\"a\",\"b\"]"` instead of `["a","b"]`) — note: the server auto-normalizes this for most array params * Missing required fields **Error message**: ``` ConvexError: Function "tasks:list" not found Error calling Convex: Could not find function with path "memories:search" ``` **Cause**: The Convex deployment does not have the expected function. This happens when: * The Convex backend is not deployed or is using an older version * `npx convex deploy` has not been run after a code update * The CONVEX\_URL points to the wrong deployment **Fix**: ```bash # From the vantage-peers repo root: npx convex deploy --prod ``` Verify the deployment completed successfully in the Convex dashboard → Functions tab. **Symptom**: `recall_memories` or `search_memories` returns an empty array, but you know memories exist. **Cause**: Namespaces are case-sensitive. `sigma` and `Sigma` are different namespaces. **Fix**: Use exact lowercase namespace strings. All built-in orchestrators use lowercase Greek letters (`sigma`, `pi`, `tau`, etc.). Verify with: ``` list_memories({ namespace: "sigma", limit: 5 }) ``` If that returns results, the data exists under the correct namespace. If not, check what namespace the memories were stored under using the Convex dashboard → Data tab → `memories` table. **Error message**: ``` GitHub API error: 403 rate limit exceeded X-RateLimit-Remaining: 0 ``` **Cause**: The `GITHUB_TOKEN` environment variable is either not set (unauthenticated rate limit: 60 req/hour) or the token's rate limit is exhausted. **Fix**: 1. Set `GITHUB_TOKEN` in the Convex dashboard: * Settings → Environment Variables → `GITHUB_TOKEN` * Use a fine-grained personal access token with `issues:read` and `issues:write` permissions 2. Authenticated requests get 5000 req/hour — sufficient for all normal usage **Error message**: ``` connect ECONNREFUSED 127.0.0.1:3000 Error: fetch failed — connection refused ``` **Cause**: The HTTP MCP server is not running, or it's running on a different port. **Fix**: 1. Start the HTTP server: ```bash cd mcp-server PORT=3000 CONVEX_URL=... BEARER_SECRET_MASTER=... node dist/server-http.js ``` 2. Verify it's listening: ```bash curl http://localhost:3000/health ``` 3. If using Railway, check the deployment logs — the server logs its port on startup **Error message**: ``` TypeError: [stream-marker] wrapToolResult: invalid payload — ... ``` Or `parseToolResult` returns `null` when you expect a structured result. **Cause**: The payload does not conform to `VpToolResultSchema`. Common issues: * `kind` value does not match one of the 6 allowed strings * `diary-entry` and `briefing-note` use `item` (singular), not `items` — easy to confuse * Required fields missing (`_id`, `title` for tasks, etc.) **Fix**: Validate against the schema before wrapping: ```ts const result = VpToolResultSchema.safeParse(payload) if (!result.success) { console.error('Schema error:', result.error.format()) } ``` See the [Stream Marker reference](/docs/paradigm-b/stream-marker) for the full discriminated union definition. **Symptom**: `VP_EMIT_UI_MARKERS=1` is set but tool responses do not contain markers. **Cause**: The environment variable must be set in the **Convex dashboard** (server-side), not in the local `.env.local` file or shell environment. The MCP server reads its own Node.js environment, but the auto-emit logic runs inside Convex functions. **Fix**: 1. Open Convex dashboard → your deployment → Settings → Environment Variables 2. Add `VP_EMIT_UI_MARKERS` with value `1` 3. Save — takes effect on the next function call, no redeploy needed Verify by calling any of the 6 auto-emit tools and checking if the response text contains `__VP_TOOL_RESULT__`. --- # Convex Workpool Errors URL: /docs/troubleshooting/convex-workpool Convex Workpool Errors [#convex-workpool-errors] Error message [#error-message] ``` Error: Couldn't acquire a permit on this funrun ``` Variants you may also see: ``` WorkpoolError: All permits are currently in use ConvexError: funrun concurrency limit exceeded ``` Root cause [#root-cause] Convex enforces a **per-deployment concurrency limit** on function runs (funruns). Each deployment on the free tier is limited to a fixed number of concurrent function executions. When VantagePeers runs many parallel agent operations (memory writes, task updates, message sends) simultaneously, the concurrency slots fill up and new funruns fail to acquire a permit. This is a **Convex platform constraint**, not a bug in VantagePeers. The error is most common when: * Multiple agents send messages or write memories simultaneously (fleet burst) * A cron job fires at the same time as heavy agent activity * An agent runs a search query (vector + BM25 hybrid) while others are writing Fix: Filter Rule Pattern [#fix-filter-rule-pattern] The fleet-standard fix is a **filter rule** that throttles or defers operations when the workpool is saturated. **Identify the high-frequency tools** causing the burst. Common culprits: `store_memory`, `send_message`, `create_task`, `update_task`. **Add exponential backoff** to the agent calling those tools: ```ts async function withBackoff( fn: () => Promise, maxRetries = 4, baseDelayMs = 200 ): Promise { for (let attempt = 0; attempt <= maxRetries; attempt++) { try { return await fn() } catch (err) { const isWorkpoolError = err instanceof Error && (err.message.includes("Couldn't acquire a permit") || err.message.includes("WorkpoolError")) if (!isWorkpoolError || attempt === maxRetries) throw err const delay = baseDelayMs * 2 ** attempt + Math.random() * 100 await new Promise((resolve) => setTimeout(resolve, delay)) } } throw new Error('unreachable') } // Usage await withBackoff(() => mcpClient.callTool({ name: 'store_memory', arguments: { ... } })) ``` **For fleet operations** (many agents writing at once), use a **filter rule** to serialize or rate-limit writes: In VantagePeers, create a filter rule that blocks duplicate or low-priority writes during saturation periods. The `create_filter_rule` tool accepts a regex pattern and a priority threshold — operations matching the pattern are deferred when the permit count exceeds the threshold. ``` // Example: throttle low-priority memory writes during bursts create_filter_rule({ pattern: "store_memory|update_task", priority: "low", action: "defer", deferMs: 500 }) ``` **Upgrade to Convex Pro** if you consistently hit the limit. Pro deployments have significantly higher concurrency limits and dedicated funrun capacity. See the [Convex pricing page](https://convex.dev/pricing). Checking current funrun usage [#checking-current-funrun-usage] In your Convex dashboard: 1. Go to your deployment → **Functions** tab 2. Sort by **Duration** — long-running functions hold permits longer 3. Check **Logs** for `WorkpoolError` frequency If you see spikes, correlate them with scheduled cron jobs (`list_recurring_tasks`). Cron-related bursts [#cron-related-bursts] VantagePeers recurring tasks run on Convex scheduled actions. If you have many recurring tasks set to the same interval, they fire simultaneously and compete for permits. **Fix**: stagger your recurring task schedules. Instead of all agents using `interval: "1h"`, offset them: * Agent sigma: `cronExpression: "0 * * * *"` (top of hour) * Agent tau: `cronExpression: "15 * * * *"` (15 past) * Agent phi: `cronExpression: "30 * * * *"` (half past) Do not catch and silently swallow `WorkpoolError`. If a memory write or message send fails silently, agents will operate on stale data. Always retry or surface the error. --- # Troubleshooting URL: /docs/troubleshooting Troubleshooting [#troubleshooting] This section covers the most common issues encountered when running VantagePeers in production. Each guide includes root cause analysis and step-by-step fix instructions. Quick diagnosis [#quick-diagnosis] Before diving into specific guides, collect this information: 1. **MCP server version**: `npm list vantage-peers-mcp` or check `package.json` 2. **Convex deployment**: `npx convex dashboard` → Functions → recent errors 3. **Environment variables**: confirm `CONVEX_URL`, `AI_GATEWAY_API_KEY`, and optionally `VP_EMIT_UI_MARKERS` are set 4. **Transport**: stdio (Claude Code) or HTTP (Railway / Claude.ai connector) Guides [#guides] Still stuck? [#still-stuck] * Check the [GitHub issues](https://github.com/vantageos-agency/vantage-peers/issues) — search for your error message * Review the [Convex dashboard](https://dashboard.convex.dev) → Logs tab for server-side errors * Open a new issue with your MCP server version, transport type, and the exact error message --- # RAG Embeddings URL: /docs/troubleshooting/rag-embeddings RAG Embeddings [#rag-embeddings] VantagePeers uses `@convex-dev/rag` with **text-embedding-3-small** (1536 dimensions) for semantic memory search and hybrid (vector + BM25) search. Configuration [#configuration] Environment variables [#environment-variables] Set in your Convex dashboard (Settings → Environment Variables): | Variable | Required | Description | | --------------------- | -------- | ------------------------------------------------------------ | | `AI_GATEWAY_API_KEY` | Yes | OpenAI-compatible API key for the embedding model | | `AI_GATEWAY_BASE_URL` | No | Override for OpenAI-compatible gateway (default: OpenAI API) | `AI_GATEWAY_API_KEY` accepts standard OpenAI API keys (`sk-...`) or any OpenAI-compatible gateway key (e.g. Azure OpenAI, OpenRouter). The embedding model name is hardcoded to `text-embedding-3-small`. Verify configuration [#verify-configuration] After setting the key, test it by calling `search_memories`: ``` search_memories({ query: "test", namespace: "sigma", limit: 1 }) ``` If it returns results (or an empty array), embeddings are working. If it throws, see the errors below. *** Common Errors [#common-errors] `AI_GATEWAY_API_KEY` not set [#ai_gateway_api_key-not-set] ``` Error: AI_GATEWAY_API_KEY is not set. Configure it in Convex dashboard → Settings → Environment Variables. ``` **Fix**: Open the [Convex dashboard](https://dashboard.convex.dev) Select your deployment → **Settings** → **Environment Variables** Add `AI_GATEWAY_API_KEY` with your OpenAI API key value Save — the change takes effect immediately, no redeploy needed *** Rate limit exceeded [#rate-limit-exceeded] ``` Error: 429 Too Many Requests — Rate limit reached for text-embedding-3-small OpenAI error: You exceeded your current quota ``` **Root cause**: Your OpenAI account has hit its embedding rate limit (tokens per minute or requests per minute). This happens when many agents search or store memories simultaneously. **Fix options**: Add a delay between embedding-intensive operations. Memory writes (`store_memory`) generate one embedding per call. Batching writes into larger `content` strings instead of many small calls reduces total embedding requests. ```ts // Instead of many small memories: store_memory({ content: "fact 1", namespace: "sigma" }) store_memory({ content: "fact 2", namespace: "sigma" }) // Combine into one: store_memory({ content: "fact 1\n\nfact 2", namespace: "sigma" }) ``` Upgrade your OpenAI account to Tier 2 or higher. Tier 1 (new accounts) has a 1M token/minute limit for text-embedding-3-small. Tier 2 raises this to 10M tokens/minute. See [OpenAI rate limits](https://platform.openai.com/docs/guides/rate-limits). Route embeddings through a gateway that handles rate limiting for you (e.g. Azure OpenAI, OpenRouter). Set `AI_GATEWAY_BASE_URL` to your gateway endpoint and `AI_GATEWAY_API_KEY` to your gateway key. *** Dimension mismatch [#dimension-mismatch] ``` Error: Vector dimension mismatch: expected 1536, got 1024 ConvexError: Index dimension does not match stored vectors ``` **Root cause**: The Convex vector index for memories was created with one dimension (e.g. 1536 from text-embedding-3-small) but the current embedding model returns a different dimension. This happens when: * The embedding model was changed mid-deployment * A custom gateway is configured with a different model * An older deployment snapshot was restored **Fix**: Fixing a dimension mismatch requires re-embedding all existing memories. This cannot be done without data migration. Confirm the current model dimension by checking `AI_GATEWAY_BASE_URL` . If it points to a gateway, verify what model the gateway is using and its output dimension. If you changed models intentionally, you need to re-index: export all memories, delete the vector index, re-create with the new dimension, and re-embed all content. Contact support or open a GitHub issue for migration tooling. If you did not change models, revert `AI_GATEWAY_BASE_URL` to the default (or remove it) to restore text-embedding-3-small at 1536 dims. *** Embedding timeout [#embedding-timeout] ``` Error: Embedding request timed out after 30000ms ``` **Root cause**: The embedding API call (OpenAI or gateway) did not respond within the Convex function timeout. This is rare with OpenAI direct but can happen with slow gateway proxies. **Fix**: * Check gateway latency — switch to OpenAI direct if your gateway is slow * Reduce content size. Very long content strings take more time to embed. Keep individual memory content under 8000 tokens *** Search returns no results (embeddings seem wrong) [#search-returns-no-results-embeddings-seem-wrong] If `search_memories` returns empty despite relevant memories existing: 1. Verify the namespace matches exactly — namespaces are case-sensitive (`sigma` != `Sigma`) 2. Check that the memories were stored with the same API key / model — if the model changed, old vectors are from a different embedding space 3. Try `recall_memories` with `type` filter instead of semantic search — BM25 text search does not require vector alignment *** Embedding model reference [#embedding-model-reference] | Property | Value | | ------------- | ------------------------------ | | Model | `text-embedding-3-small` | | Provider | OpenAI (or compatible gateway) | | Dimensions | **1536** | | Max input | 8191 tokens | | Search mode | Cosine similarity | | Index type | Convex vector index | | Hybrid search | RRF fusion (vector + BM25) | --- # VP-Sources answer-footer doctrine URL: /docs/cloud/doctrine/vp-sources-footer VP-Sources answer-footer doctrine [#vp-sources-answer-footer-doctrine] What this doctrine says [#what-this-doctrine-says] Each of the 5 covered tools embeds two verbatim doctrine paragraphs appended after the existing tool description: > **VP-Sources doctrine**: MUST be called before any factual claim about fleet state, audits, dette tooling, mission/task/client status, incident history, doctrine references. > Cite returned ids in the answer footer as `VP-Sources: recall("")→[ids] | none-needed:`. These two strings appear verbatim in every covered tool's `description` field. Any MCP client that requests the tool list receives them inline — no additional system prompt injection is required. Why [#why] MCP clients receive the full tool list (names + descriptions) in a single response before the first tool call. Embedding the doctrine there means any agent that calls one of the 5 covered tools has already been instructed about the citation obligation at tool-list time. The alternative — adding the rule to a system prompt — requires every client deployment to be updated independently. Inline embedding is deployment-agnostic: it travels with the tool definition. Tools covered [#tools-covered] The following 5 tools carry the VP-Sources doctrine strings as of PR-H (T-GREEN `908fd67`): | Tool | Exported constant (mcp-server/src/tools.ts) | | ---------------------------------- | --------------------------------------------------- | | `recall` | `RECALL_TOOL_DESCRIPTION` | | `hybrid_search` | `HYBRID_SEARCH_TOOL_DESCRIPTION` | | `text_search` | `TEXT_SEARCH_TOOL_DESCRIPTION` | | `list_briefing_notes` | `LIST_BRIEFING_NOTES_TOOL_DESCRIPTION` | | `search_briefing_notes_by_keyword` | `SEARCH_BRIEFING_NOTES_BY_KEYWORD_TOOL_DESCRIPTION` | Each constant is exported from `mcp-server/src/tools.ts` and tested with a snapshot assertion in `mcp-server/src/__tests__/tools-descriptions.test.ts`. Footer format [#footer-format] When a search tool returns results the agent must cite them in the final answer footer. **Full citation (sources found):** ``` VP-Sources: recall("Pi feedback rules")→[j57dy3049btafda9m2f5d2ggk987ph3f, j572s2bh4e0n20n0ttxynwrnts891nb5] ``` **No search needed:** ``` VP-Sources: none-needed:trivial code edit ``` **Worked example** — an agent answers a question about current mission status: 1. Agent calls `recall` with `query="VP-MCP top level Bloc A mission status"`. 2. Search returns documents `k571gcctka8mq5jbkgpj0a0b2n892ctg` and `k977bvf03qzas7v7g0zqca9c7n8937zh`. 3. Agent answers the question based on those documents. 4. Footer: ``` VP-Sources: recall("VP-MCP top level Bloc A mission status")→[k571gcctka8mq5jbkgpj0a0b2n892ctg, k977bvf03qzas7v7g0zqca9c7n8937zh] ``` The footer is appended to the agent's final answer, not to intermediate reasoning steps. One footer per user-facing response is sufficient even if multiple tool calls were made. Advisory only [#advisory-only] No hook enforces absence of the footer. An agent that omits the footer will not be blocked. This is intentional. The doctrine is designed for progressive adoption: * Agents that implement it immediately gain auditability and trust with human reviewers. * Agents that do not implement it are not broken — they simply lack the citation trail. * A blocking hook would create friction for all callers including non-VP clients using the same MCP server. The advisory status may be revisited in a future sprint if adoption data shows systematic omission. When `none-needed` is acceptable [#when-none-needed-is-acceptable] Use `none-needed:` when a factual search was genuinely not required: * Trivial mechanical code edit with no claim about system state (e.g. renaming a variable). * Calling a tool that returns the answer directly (`get_task`, `get_mission`, `whoami`) — the tool ID itself is the source. * Pure arithmetic or string formatting with no fleet-state dependency. * Iterative follow-up in the same tool-call chain where all sources are already cited in the prior response. * The user asked a question answerable from the current conversation context alone. Do not use `none-needed` to avoid searching. If the answer involves any claim about fleet state, doctrine, task status, or incident history, call one of the 5 covered tools first. References [#references] * Doctrine source: Eta Q1 msg `k977bvf03qzas7v7g0zqca9c7n8937zh` * Mission: `k571gcctka8mq5jbkgpj0a0b2n892ctg` (VP-MCP top level Bloc A) * Audit sections 27+28.4 * T-RED `0b4dc84`, T-GREEN `908fd67` * MCP tool references: [list\_briefing\_notes](/docs/cloud/mcp-tools/list-bus), [list\_bus](/docs/cloud/mcp-tools/list-bus), [list\_components](/docs/cloud/mcp-tools/list-components), [list\_repo\_mappings](/docs/cloud/mcp-tools/list-repo-mappings) --- # bulk_complete_tasks URL: /docs/cloud/mcp-tools/bulk-complete-tasks bulk_complete_tasks [#bulk_complete_tasks] Bulk-close tasks that match a filter in one atomic mutation. Introduced in PR-F (merged commit `4c068d2` after Eta REVISE round addressing blast-radius / scope / caller-gate hardening). Designed to safely drain cron-spam backlogs accumulated from auto-generated `check-messages` polling tasks. `dryRun` defaults to `true`. The tool never mutates the database unless you explicitly pass `dryRun: false`. Always preview first to confirm the count, then call again with `dryRun: false` to commit. Closed tasks are irreversible — status is permanently set to `done`. Safety contract (iter-2 hardening) [#safety-contract-iter-2-hardening] The mutation enforces three guardrails before any write: | Guardrail | Throws | When | | ----------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------- | | **Reductive filter required** | `BULK_FILTER_TOO_BROAD` | Neither `filter.autoGeneratedOnly: true` nor `filter.assignedTo` set — match-all is forbidden. | | **Caller required for live commit** | `BULK_CALLER_REQUIRED` | `dryRun: false` with no `callerOrchestrator` — default-deny on the destructive path. | | **Blast-radius cap** | `BULK_HARD_CAP_EXCEEDED` | Matched count exceeds `BULK_COMPLETE_HARD_CAP = 500` — narrow the filter and retry. | Backing implementation uses a `withIndex("by_status")` iterator with early-stop at `cap+1` to count without scanning the full table. Args [#args] | Arg | Type | Default | Description | | -------------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `filter` | object | (required) | Filter object controlling which tasks are matched. MUST contain at least one reductive predicate (`autoGeneratedOnly: true` OR `assignedTo: ""`) — else throws `BULK_FILTER_TOO_BROAD`. | | `filter.autoGeneratedOnly` | boolean | `false` | When `true`, matches tasks where `createdBy` matches `/^cron-/i` OR `title` matches `/^\/?check-messages$/i`. | | `filter.assignedTo` | string | — | When set, narrows matches to tasks whose `assignedTo` equals this role. Combined with `autoGeneratedOnly` via AND. | | `dryRun` | boolean | `true` | Safety default. `true` returns a preview without mutating. Pass `false` explicitly to commit (requires `callerOrchestrator`). | | `completionNoteTemplate` | string | (see below) | Template string written as `completionNote` on each closed task. Supports `{{day}}`, `{{bulkRunId}}`, `{{executedAt}}` interpolation. Default: `"bulk-cleanup: cron-spam day {{day}} runId={{bulkRunId}} executedAt={{executedAt}}"`. | | `callerOrchestrator` | string | — | Caller identity for RBAC. **Required for `dryRun: false`** (default-deny). When provided and not `"system"`, every matched task must have `createdBy` or `assignedTo` equal to the caller. | Returns [#returns] `dryRun=true` (preview — default) [#dryruntrue-preview--default] ```ts { count: number, // number of tasks that would be closed (≤ BULK_COMPLETE_HARD_CAP) sampleIds: string[], // up to 10 matching task IDs bulkRunId: string, // unique run ID (Day-76 evidence token, pre-generated) cappedAt?: number // present iff matched count was truncated at the 500-cap; caller must narrow filter } ``` `dryRun=false` (commit) [#dryrunfalse-commit] ```ts { count: number, // number of tasks closed sampleIds: string[], // up to 10 closed task IDs bulkRunId: string, // unique run ID used in every completionNote executedAt: number // epoch ms when the mutation ran } ``` Examples [#examples] Dry-run preview (default behavior) [#dry-run-preview-default-behavior] ```jsonc // call — dryRun=true is the default; this call never mutates { "filter": { "autoGeneratedOnly": true }, "callerOrchestrator": "system" } // response { "count": 152, "sampleIds": ["k17abc...", "k17def...", "k17ghi..."], "bulkRunId": "bulk-1782050000000-a3f2" } ``` Live bulk close with custom completion note template [#live-bulk-close-with-custom-completion-note-template] ```jsonc // call — explicit dryRun=false with custom template { "filter": { "autoGeneratedOnly": true }, "dryRun": false, "completionNoteTemplate": "bulk-cleanup: cron-spam day {{day}} runId={{bulkRunId}}", "callerOrchestrator": "system" } // response { "count": 152, "sampleIds": ["k17abc...", "k17def...", "k17ghi..."], "bulkRunId": "bulk-1782050000000-a3f2", "executedAt": 1782050000000 } ``` RBAC-gated call (orchestrator-scoped) [#rbac-gated-call-orchestrator-scoped] ```jsonc // call — pi can only close tasks it created or was assigned { "filter": { "autoGeneratedOnly": true }, "dryRun": false, "callerOrchestrator": "pi" } // response (all matched tasks belong to pi) { "count": 8, "sampleIds": ["k17jkl...", "k17mno..."], "bulkRunId": "bulk-1782050000001-c9d4", "executedAt": 1782050000001 } ``` Cron contract [#cron-contract] The `autoGeneratedOnly` filter matches tasks that satisfy either predicate below. This is the same contract used by `list_tasks excludeAutoGenerated` (PR-E). | Predicate | Pattern | Example matches | Example non-matches | | ----------- | --------------------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------- | | `createdBy` | `/^cron-/i` (dash mandatory) | `cron-bot`, `cron-daily` | `cronus`, `cron` (no dash) | | `title` | `/^\/?check-messages$/i` (whole-string, optional leading slash) | `check-messages`, `/check-messages`, `CHECK-MESSAGES` | `check-messages-v2`, `run check-messages` | **Filter placement:** applied in-memory against all non-done tasks, before any mutation is executed. Day-76 evidence-bound completionNote [#day-76-evidence-bound-completionnote] Every task closed by `bulk_complete_tasks` receives a `completionNote` that satisfies the Day-76 Evidence-Bound Done doctrine. The default template injects two verifiable proof tokens: * `{{day}}` — project day number computed from epoch `2026-03-06 UTC`. Unique per calendar day. * `{{bulkRunId}}` — format `bulk--`. Unique per run, consistent across all tasks closed in that run. * `{{executedAt}}` — epoch ms timestamp of the mutation. Default note written to each task: `"bulk-cleanup: cron-spam day {{day}} runId={{bulkRunId}} executedAt={{executedAt}}"` (with values interpolated). This means every closed task carries a traceable, auditable proof token — the `bulkRunId` links the batch, and `day` scopes it to a human-readable project timeline. Callouts [#callouts] **Blast-radius cap:** the iterator uses `withIndex("by_status")` to scan only non-done tasks with early-stop at `BULK_COMPLETE_HARD_CAP + 1 = 501`. Matched count above 500 throws `BULK_HARD_CAP_EXCEEDED` — narrow the filter (e.g. add `assignedTo`) and retry. Dry-run output carries `cappedAt: 500` when truncation applies. **Reductive filter required:** a filter with neither `autoGeneratedOnly: true` nor `assignedTo` set is rejected with `BULK_FILTER_TOO_BROAD`. Match-all is forbidden by design — destructive surface must always be scoped. **RBAC + caller gate:** `dryRun: false` without `callerOrchestrator` throws `BULK_CALLER_REQUIRED` (default-deny on the destructive path). When provided and not `"system"`, every matched task must have `createdBy` or `assignedTo` equal to the caller, else the entire mutation throws `RBAC_DENIED` — no partial close. Use `"system"` to bypass RBAC for fleet-wide cleanup. **Why this matters:** before PR-F, cron-spam tasks could only be listed (with `excludeAutoGenerated`) but not closed in bulk. Pi's queue accumulated 152 cron-spawned tasks (audit section 13) that required individual `complete_task` calls to clear. `bulk_complete_tasks` drains the full backlog in two calls — one preview, one commit — with a verifiable audit trail via `bulkRunId`. --- # improvisation_digest URL: /docs/cloud/mcp-tools/improvisation-digest improvisation_digest [#improvisation_digest] Scan a rolling time window of VP tasks, messages, and memories for records that carry durable-artifact fleet/state tokens (commit SHA, PR number, VP document ID, or decisive verb such as `merged`, `deployed`, `approved`) but have **no VP-Sources footer**. This is the Eta heuristic proxy for an orchestrator having made a fleet-state claim without a prior `recall` upstream. ADVISORY-only — pure read query. `improvisation_digest` never blocks any action. Results are informational: a high improvisation rate indicates a team should increase VP-Sources citation hygiene, but the tool itself takes no automated action and has no side effects. Args [#args] | Arg | Type | Default | Description | | --------------- | --------- | ------- | ----------------------------------------------------------------------------------------------- | | `windowDays` | number | `7` | Number of days to look back. | | `orchestrators` | string\[] | — | Scope to these orchestrator roles only (e.g. `["sigma","pi"]`). Omit to scan all orchestrators. | Returns [#returns] ```ts { countsByOrch: Record, // hit count per orchestrator countsByCategory: Record, // hit count per record type: "task" | "message" | "memory" samples: Array<{ // up to 50 representative snippets id: string, category: string, orchestrator: string, snippet: string }> } ``` `countsByOrch` and `countsByCategory` are both zero-initialized for all observed orchestrators/categories — entries with zero hits are omitted from the returned map. `samples` is sorted newest-first and capped at 50 entries. Examples [#examples] Default 7-day window across all orchestrators [#default-7-day-window-across-all-orchestrators] ```jsonc // call { "windowDays": 7 } // response (illustrative) { "countsByOrch": { "sigma": 3, "pi": 1 }, "countsByCategory": { "task": 2, "message": 2 }, "samples": [ { "id": "k17abc...", "category": "task", "orchestrator": "sigma", "snippet": "completionNote: merged PR #954 into main — VP-MCP top level..." }, { "id": "k97def...", "category": "message", "orchestrator": "pi", "snippet": "deployed vantage-peers-mcp@2.13.0 to Railway at commit ef91f6f" } ] } ``` Scoped to a single orchestrator [#scoped-to-a-single-orchestrator] ```jsonc // call — audit sigma's last 14 days { "windowDays": 14, "orchestrators": ["sigma"] } // response — only sigma records are evaluated { "countsByOrch": { "sigma": 5 }, "countsByCategory": { "task": 3, "memory": 2 }, "samples": [ { "id": "k17xxx...", "category": "memory", "orchestrator": "sigma", "snippet": "approved PR-C — list_repo_mappings envelope safety shipped at 4ddca2b" } ] } ``` Detection heuristic (Eta A5 scope filter) [#detection-heuristic-eta-a5-scope-filter] A record is flagged when **both** conditions hold simultaneously: | Condition | Check | | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Durable-artifact token present** | Body contains at least one of: 7–40 hex commit SHA; `#NNN` PR/issue ref; Convex document ID (`k1…` or `j…` prefix); decisive verb (`merged`, `deployed`, `approved`, `shipped`, `released`, `fixed`). | | **VP-Sources footer absent** | Body does NOT contain the `VP-Sources:` substring. | **A5 scope exclusions** — the following are never flagged regardless of content: * Records authored by `system` * Records where `createdBy` matches `/^cron-/i` (dash mandatory) * Records originating from webhook ingestion paths The A5 exclusions prevent false positives from automated infrastructure records that legitimately reference SHAs or PR numbers without a VP-Sources footer obligation. V1 scope and V2 roadmap [#v1-scope-and-v2-roadmap] V1 (current) scans VP records only — tasks, messages, and memories stored in VantagePeers (Option C). Per Pi Day-113 arbitration (msg `k97a0pp6kq1axkj6cmc4pecpy989ce1w`), the fallback if V1 misses too many improvisations is **Option B** — a new dedicated `sessions` Convex table — **not** Option A (transcript-replay from JSONL conversation logs). V1 was selected because VP records are already structured, queryable, and authorship-attributed. Monitor `countsByOrch` trends over 2–4 weeks; if V1 coverage proves insufficient (because agents do not store all fleet-state claims as VP records), the next iteration introduces a dedicated `sessions` table (Option B) where the digest can pull richer per-session context without the transcript ingestion pipeline complexity of Option A. Cross-reference [#cross-reference] * [VP-Sources answer-footer doctrine](/docs/cloud/doctrine/vp-sources-footer) — full reference including worked examples, `none-needed` acceptable cases, and advisory-only rationale. * Convex query: `improvisationDigest:scanWindow` * Mission: `k571gcctka8mq5jbkgpj0a0b2n892ctg` (VP-MCP top level Bloc A, PR-I) * T-RED `cd6cda3` · T-GREEN `b9414dc` --- # list_bus URL: /docs/cloud/mcp-tools/list-bus list_bus [#list_bus] List business units (BUs) registered in VantagePeers, with pagination, projection (`lite|full`), and optional filters. Args [#args] | Arg | Type | Default | Description | | ---------------- | --------------------------------------------- | -------- | --------------------------------------------------------------------------------------------- | | `orchestratorId` | string | — | Filter by lead orchestrator (e.g. `"sigma"`). | | `status` | `"idea" \| "building" \| "live" \| "revenue"` | — | Filter by lifecycle status. | | `limit` | number 1-200 | `20` | Page size. Default `20`, capped at `200`. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (5 keys). `"full"` returns complete BU object (18+ keys). | Returns [#returns] ```ts { items: BusinessUnit[] | BusinessUnitLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Compact list (fields=lite) [#compact-list-fieldslite] ```jsonc // call { "limit": 20, "fields": "lite" } // response (~5KB for 100 BUs) { "items": [ { "_id": "j5xxx...", "_creationTime": 1782050000000, "name": "VantagePeers", "status": "live", "orchestratorId": "sigma" } ], "nextCursor": "eyJjcmVhdGlvblRpbWUiOjE3ODIwNDk5MDAwMDAsImlkIjoiajV5eXkifQ==" } ``` Detailed single BU (fields=full + limit=1) [#detailed-single-bu-fieldsfull--limit1] ```jsonc { "orchestratorId": "sigma", "limit": 1, "fields": "full" } ``` Returns the full BU record (name, description, purpose, businessModel, targetCustomers, services, pricing, revenueProjections, coreTeam, etc.). Paginate through all live BUs [#paginate-through-all-live-bus] ```jsonc // page 1 { "status": "live", "limit": 20 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "status": "live", "limit": 20, "cursor": "" } ``` Pagination + envelope safety [#pagination--envelope-safety] `list_bus` follows the standard VantagePeers envelope safety pattern (PR-A): * **Default limit**: `20`. Keeps payloads small (\~2-5KB) for typical interactive calls. * **Cap**: `200`. Requests with `limit > 200` are clamped server-side. * **fields=lite**: projects to 5 stable keys (`_id`, `_creationTime`, `name`, `status`, `orchestratorId`). Payload stays under 25KB even for 100 BUs. * **Cursor**: opaque token encoding `{creationTime, id}` to survive same-millisecond inserts. Treat as opaque — do not parse client-side. Same pattern applies to `list_components` (PR-B) and `list_repo_mappings` (PR-C). Why this matters [#why-this-matters] Before PR-A: `list_bus` had no cap, `fields=lite` was a no-op (returned full rows), and default limit was 50. A fleet with many BUs could return a 64KB+ payload, overflowing the MCP envelope (25K-token cap) in client sessions. PR-A enforces strict defaults and an actual lite projection, eliminating envelope overflow as a failure mode. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 9. --- # list_components URL: /docs/cloud/mcp-tools/list-components list_components [#list_components] List components (agents, skills, hooks, plugins) registered in VantagePeers, with pagination, projection (`lite|full`), and optional filters. Args [#args] | Arg | Type | Default | Description | | -------- | ------------------------------------------ | -------- | ----------------------------------------------------------------------------------------- | | `type` | `"agent" \| "skill" \| "hook" \| "plugin"` | — | Filter by component type. | | `team` | string | — | Filter by team (e.g. `"development"`). | | `limit` | number 1-200 | `20` | Page size. Default `20`, capped at `200`. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (5 keys). `"full"` returns complete component object. | Returns [#returns] ```ts { items: Component[] | ComponentLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Compact list (fields=lite) [#compact-list-fieldslite] ```jsonc // call { "limit": 20, "fields": "lite" } // response (~3KB for 100 components) { "items": [ { "_id": "j5xxx...", "_creationTime": 1782050000000, "name": "dev-convex-expert", "type": "agent", "team": "development" } ], "nextCursor": "eyJjcmVhdGlvblRpbWUiOjE3ODIwNDk5MDAwMDAsImlkIjoiajV5eXkifQ==" } ``` Paginate through all skill components [#paginate-through-all-skill-components] ```jsonc // page 1 { "type": "skill", "limit": 20 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "type": "skill", "limit": 20, "cursor": "" } ``` Pagination + envelope safety [#pagination--envelope-safety] `list_components` follows the standard VantagePeers envelope safety pattern (PR-B): * **Default limit**: `20`. Keeps payloads small (\~2-3KB) for typical interactive calls. * **Cap**: `200`. Requests with `limit > 200` are clamped server-side. * **fields=lite**: projects to 5 stable keys (`_id`, `_creationTime`, `name`, `type`, `team`). Payload stays under 25KB even for 100 components. * **Cursor**: opaque token encoding `{creationTime, id}` to survive same-millisecond inserts. Treat as opaque — do not parse client-side. * **Hybrid cursor decode**: old-format `{createdBefore}` cursors (S3.3 B8 callers) are decoded and forwarded as `createdBefore` for back-compat. New-format opaque cursors pass through directly. Same pattern applies to `list_bus` (PR-A) and `list_repo_mappings` (PR-C). Why this matters [#why-this-matters] Before PR-B: `list_components` had no cap, `fields=lite` was a no-op (returned full rows regardless), and default limit was 100. A registry with many components could return a 64KB+ payload, overflowing the MCP envelope (25K-token cap) in client sessions. PR-B enforces strict defaults and an actual lite projection, eliminating envelope overflow as a failure mode. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 9. --- # list_repo_mappings URL: /docs/cloud/mcp-tools/list-repo-mappings list_repo_mappings [#list_repo_mappings] List GitHub repository to orchestrator webhook mappings registered in VantagePeers, newest first, with pagination and projection (`lite|full`). Args [#args] | Arg | Type | Default | Description | | -------- | ------------------ | -------- | --------------------------------------------------------------------------------------- | | `limit` | number 1-200 | `20` | Page size. Default `20`, capped at `200`. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (5 keys). `"full"` returns complete mapping object. | Returns [#returns] ```ts { items: RepoMapping[] | RepoMappingLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Compact list (fields=lite) [#compact-list-fieldslite] ```jsonc // call { "limit": 20, "fields": "lite" } // response (~2KB for 100 mappings) { "items": [ { "_id": "j5xxx...", "_creationTime": 1782050000000, "repo": "vantageos-agency/vantage-peers", "orchestrator": "sigma", "project": "vantage-peers" } ], "nextCursor": "eyJ0aW1lIjoxNzgyMDQ5OTAwMDAwLCJpZCI6Imo1eXl5In0=" } ``` Paginate through all mappings [#paginate-through-all-mappings] ```jsonc // page 1 { "limit": 20 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "limit": 20, "cursor": "" } ``` Pagination + envelope safety [#pagination--envelope-safety] `list_repo_mappings` follows the standard VantagePeers envelope safety pattern (PR-C): * **Default limit**: `20`. Keeps payloads small (\~2KB) for typical interactive calls. * **Cap**: `200`. Requests with `limit > 200` are clamped server-side. * **fields=lite**: projects to 5 stable keys (`_id`, `_creationTime`, `repo`, `orchestrator`, `project`). Excludes `active`, `lastDeployedSHA`, `lastDeployedAt`. * **Cursor**: opaque token encoding `{time, id}` to survive same-millisecond inserts. Treat as opaque — do not parse client-side. * **Hybrid cursor decode**: old-format `{createdBefore}` cursors (S3.3 B8 batch 2 callers) are decoded and forwarded as `createdBefore` for back-compat. New-format opaque cursors pass through directly. Same pattern applies to `list_bus` (PR-A) and `list_components` (PR-B). Why this matters [#why-this-matters] Before PR-C: `list_repo_mappings` had no cap, `fields=lite` was a no-op (returned full rows regardless), and default limit was 50. A deployment with many repo mappings could return a large payload, overflowing the MCP envelope (25K-token cap) in client sessions. PR-C enforces strict defaults and an actual lite projection, eliminating envelope overflow as a failure mode. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 9. --- # list_tasks URL: /docs/cloud/mcp-tools/list-tasks list_tasks [#list_tasks] List tasks registered in VantagePeers, newest-updated first, with pagination, projection (`lite|full`), status filters, and the `excludeAutoGenerated` cron-spam filter introduced in PR-E. Args [#args] | Arg | Type | Default | Description | | ---------------------- | ---------------------------- | -------- | ------------------------------------------------------------------------------------- | | `assignedTo` | string | — | Filter by assignee (e.g. `"pi"`). | | `status` | string \| string\[] \| alias | — | Single status, array, or alias (`"open"`, `"active"`, `"all"`). | | `missionId` | string | — | Filter to tasks belonging to a specific mission. | | `createdBy` | string | — | Filter by creator (e.g. `"sigma"`). | | `updatedSince` | number | — | Epoch ms. Returns tasks with `updatedAt >= this`. | | `createdBefore` | number | — | Epoch ms. Pagination anchor (legacy; prefer `cursor`). | | `limit` | number 1-200 | `50` | Page size. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (7 keys). `"full"` returns complete task object. | | `excludeAutoGenerated` | boolean | `false` | When `true`, filters out cron-generated tasks. Default `false` — backward-compatible. | Returns [#returns] ```ts { items: Task[] | TaskLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Default query (all open tasks for an agent) [#default-query-all-open-tasks-for-an-agent] ```jsonc // call { "assignedTo": "pi", "status": "open", "fields": "lite", "limit": 30 } // response { "items": [ { "_id": "k17xxx...", "_creationTime": 1782050000000, "title": "Review PR-E docs", "status": "review", "priority": "high", "assignedTo": "pi", "missionId": "k571gcctka8mq5jbkgpj0a0b2n892ctg" } ], "nextCursor": null } ``` Exclude cron-generated tasks (`excludeAutoGenerated=true`) [#exclude-cron-generated-tasks-excludeautogeneratedtrue] ```jsonc // call — Pi queue cleaned of cron-spam (audit §13: 152 cron tasks) { "assignedTo": "pi", "status": "open", "excludeAutoGenerated": true, "limit": 50 } // response — only human-dispatched tasks; cron-bot + check-messages rows absent { "items": [ { "_id": "k17yyy...", "_creationTime": 1782050100000, "title": "Validate VP-MCP PR-E", "status": "todo", "priority": "high", "assignedTo": "pi", "missionId": "k571gcctka8mq5jbkgpj0a0b2n892ctg" } ], "nextCursor": "eyJ0aW1lIjoxNzgyMDUwMDAwMDAwLCJpZCI6Ims1eHh4In0=" } ``` Paginate through results [#paginate-through-results] ```jsonc // page 1 { "assignedTo": "pi", "status": "open", "excludeAutoGenerated": true, "limit": 50 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "assignedTo": "pi", "status": "open", "excludeAutoGenerated": true, "limit": 50, "cursor": "" } ``` `excludeAutoGenerated` cron contract [#excludeautogenerated-cron-contract] The `excludeAutoGenerated` filter removes tasks that match either of these predicates: | Predicate | Pattern | Example matches | Example non-matches | | ----------- | --------------------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------- | | `createdBy` | `/^cron-/i` (dash mandatory) | `cron-bot`, `cron-daily` | `cronus`, `cron` (no dash) | | `title` | `/^\/?check-messages$/i` (whole-string, optional leading slash) | `check-messages`, `/check-messages`, `CHECK-MESSAGES` | `check-messages-v2`, `run check-messages` | **Filter placement:** applied in-memory in the `list` query handler, after `createdBy` / `updatedSince` / `createdBefore` filters, before `filterByOrgScope` and envelope assembly. Post-filter pages may be smaller than `limit` because filtered rows do not count toward the page fill. This is by design — the cron-spam catalog is small and narrowly targeted, so pages will rarely shrink significantly. If you need exactly N human tasks, over-fetch with a larger `limit` and truncate client-side. `fields=lite` projection [#fieldslite-projection] `"lite"` returns 7 stable keys: `_id`, `_creationTime`, `title`, `status`, `priority`, `assignedTo`, `missionId`. Full task object (`"full"`) includes: `description`, `createdBy`, `completionNote`, `dependsOn`, `blockedBy`, `startedAt`, `completedAt`, `updatedAt`, `tags`, and all other schema fields. Status aliases [#status-aliases] | Alias | Expands to | | ---------- | ---------------------------------------------- | | `"open"` | `["todo", "in_progress", "review", "blocked"]` | | `"active"` | `["todo", "in_progress"]` | | `"all"` | No filter — returns all statuses | Why this matters [#why-this-matters] Before PR-E: `list_tasks` had no way to hide automatically-generated tasks (cron-dispatched tasks, `check-messages` entries). Pi's queue accumulated 152 cron-spawned tasks (audit §13), making it difficult to see human-dispatched work without manual filtering. `excludeAutoGenerated=true` hides these rows server-side with zero API surface change — existing callers are unaffected. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 13. Mission `k571gcctka8mq5jbkgpj0a0b2n892ctg` (VP-MCP top level Bloc A), RED `eb78cfa`, GREEN `74dea44`. --- # Journal des modifications URL: /fr/docs/changelog Journal des modifications [#journal-des-modifications] v2.13.1 — 2026-06-27 [#v2131--2026-06-27] Corrigé [#corrigé] * **CRITIQUE — `list_memories` + `list_episodes` retournaient silencieusement `items: []` à chaque appel** — L'audit Day-114 a trouvé les deux gestionnaires lisant `memories?.page` depuis la forme de retour Convex `listMemories` `{value, continueCursor, isDone}`. `.page` est indéfini → résultats vides à chaque invocation quelle que soit la donnée stockée. Corrigé dans la PR [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) (squash `0db28d5`). Les appelants pré-2.13.1 DOIVENT mettre à niveau. Voir les [notes de version Day-114](/docs/release-notes/day-114). Ajouté [#ajouté] * **Doctrine MCP Tools Standard v1** — doctrine de pagination `list_*` cross-fleet canonicalisée comme standard versionné. PR [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) (squash `d09fc5b`). Runbook VantageRegistry `kd750j7z7tqre6hxqmfsa8s9ed89erng`. Couvre : schéma Zod obligatoire, enveloppe de retour, 7 anti-patterns bannis, modèle de matrice de couverture, tableau de conformité fleet, playbook de migration. * **Documentation Day-114** — [Pagination par curseur](/docs/pagination), [Sécurité d'enveloppe](/docs/envelope-safety), [Catalogue des outils](/docs/tools-catalogue), [Notes de version Day-114](/docs/release-notes/day-114). Liens [#liens] * GitHub : [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers) * npm : [vantage-peers-mcp@2.13.1](https://www.npmjs.com/package/vantage-peers-mcp) * PR #978 : [github.com/vantageos-agency/vantage-peers/pull/978](https://github.com/vantageos-agency/vantage-peers/pull/978) * PR #980 : [github.com/vantageos-agency/vantage-peers/pull/980](https://github.com/vantageos-agency/vantage-peers/pull/980) *** v2.4.1 — 2026-05-30 [#v241--2026-05-30] Corrigé [#corrigé-1] * **Régression 401 sur le chemin d'auth DCR** ([#556](https://github.com/vantageos-agency/vantage-peers/issues/556) / [#557](https://github.com/vantageos-agency/vantage-peers/pull/557)) — `oauthDcr:validateAccessToken` était déclaré `internalQuery` et inaccessible via le client HTTP, le Path 3 DCR retournait 401 même avec un token valide. Maintenant exposé en `query` publique. Les connecteurs custom Claude.ai via DCR fonctionnent de bout en bout. * **Format du header `WWW-Authenticate`** ([#557](https://github.com/vantageos-agency/vantage-peers/pull/557)) — émet `Bearer resource_metadata="..."` selon la spec MCP §Protected Resource Metadata Discovery. L'ancienne forme `Bearer resource="..."` cassait le bootstrap PRM de Claude.ai sur 401. Ajouté [#ajouté-1] * **Annotations d'outils ChatGPT Apps SDK** ([#555](https://github.com/vantageos-agency/vantage-peers/pull/555)) — les 84 outils MCP embarquent désormais `readOnlyHint`, `openWorldHint` et `destructiveHint`. 34 read-only + 41 write + 9 destructive. Les connecteurs custom ChatGPT n'affichent les prompts de confirmation que sur les opérations d'écriture/destructives. * **Isolation de scope DCR** ([#554](https://github.com/vantageos-agency/vantage-peers/pull/554)) — nouveau profil `public-readonly` + tests cross-tenant. Le flux DCR auto-discovery résout vers `scopeProfile=client-generic` (jamais `master`), même si un legacy token row porte `scope="mcp:full"`. * **Documentation VantagePeers Cloud** ([site #120](https://github.com/vantageos-agency/vantage-peers-site/pull/120)) — section `/docs/cloud/` dédiée à la version hébergée multi-tenant. Multi-client MCP : Claude.ai, ChatGPT, Claude Code, Codex, tout IDE supportant MCP. Liens [#liens-1] * Release GitHub : [v2.4.1](https://github.com/vantageos-agency/vantage-peers/releases/tag/v2.4.1) * npm : [vantage-peers-mcp@2.4.1](https://www.npmjs.com/package/vantage-peers-mcp) v2.4.0 — 2026-05-29 [#v240--2026-05-29] Ajouté [#ajouté-2] * **Table `iframeEmbedSessions` + marqueur de stream `__VP_TOOL_RESULT__`** ([#545](https://github.com/vantageos-agency/vantage-peers/pull/545)) — jalon M3. Primitive UI ack-checklist embarquée. 24 tests. * **httpAction `credentials:issueBearerFromClerk`** ([#546](https://github.com/vantageos-agency/vantage-peers/pull/546)) — émission de bearer côté serveur liée à une identité Clerk, avec audit log. Corrections P1 iter 2. Liens [#liens-2] * Release GitHub : [v2.4.0](https://github.com/vantageos-agency/vantage-peers/releases/tag/v2.4.0) * npm : [vantage-peers-mcp@2.4.0](https://www.npmjs.com/package/vantage-peers-mcp) v2.3.1 — 2026-05-26 [#v231--2026-05-26] Ajouté [#ajouté-3] * `list_tasks`, `list_missions`, `list_tasks_by_mission` et `list_briefing_notes` acceptent un paramètre `fields` (`"lite"` ou `"full"`, défaut `"full"`). Lite renvoie une projection compacte. * Le filtre `status` sur `list_tasks`, `list_missions` et `list_tasks_by_mission` accepte désormais des tableaux et des alias nommés : * Tâches : `"open"` → todo+in\_progress+review+blocked, `"active"` → todo+in\_progress, `"all"` → aucun filtre * Missions : `"open"` → brainstorm+plan+execute+validate (exclut complete), `"active"` → plan+execute, `"all"` → aucun filtre Rétrocompatibilité [#rétrocompatibilité] * Le `status` chaîne unique reste inchangé. * Omettre `fields` revient à `"full"` — les appelants existants ne sont pas affectés. Dépréciation [#dépréciation] * **`vantage-peers-mcp@2.3.0` est déprécié.** v2.3.0 a livré deux blockers détectés en delta-review : `status="all"` était annoncé mais rejeté par le backend, et `setPendingAliasReleases` était exposé en mutation publique. Passez à `>=2.3.1`. Liens [#liens-3] * Release GitHub : [v2.3.1](https://github.com/vantageos-agency/vantage-peers/releases/tag/v2.3.1) * npm : [vantage-peers-mcp@2.3.1](https://www.npmjs.com/package/vantage-peers-mcp) --- # Sécurité d'enveloppe URL: /fr/docs/envelope-safety Sécurité d'enveloppe [#sécurité-denveloppe] Le serveur MCP VantagePeers applique un ensemble cohérent de protections sur chaque réponse `list_*` pour éviter que les payloads de réponse ne dépassent le budget de contexte de l'agent appelant. Cette page documente les protections, le système de projection `fields=lite|full`, le plafond strict de 200 lignes, et les anti-patterns ayant causé des incidents en production. Les trois protections [#les-trois-protections] Chaque outil `list_*` de VantagePeers applique trois couches de protection : 1. **Plafond strict de lignes (200) :** L'argument `limit` est validé comme `z.number().int().min(1).max(200).optional()`. Toute valeur supérieure à 200 est rejetée au niveau MCP avant d'atteindre Convex. La valeur par défaut quand aucun `limit` n'est fourni est de 20 lignes. 2. **Projection `fields=lite` :** Tous les outils `list_*` acceptent `fields: "lite" | "full"`. La projection `lite` retourne au maximum 6 champs par ligne, gardant les pages compactes même pour les documents avec un grand contenu texte (ex. mémoires avec un long `content`, briefings avec de longs tableaux `decisions`). 3. **Limite douce de 50 Ko (`enforceEnvelopeCap`) :** Après projection des lignes, le serveur mesure la taille JSON sérialisée de l'enveloppe. Si le résultat dépasse 50 000 octets, le serveur divise le nombre de lignes de moitié et mesure à nouveau, en répétant jusqu'à ce que le payload soit dans les limites. Ce garde-fou existe en plus du plafond de lignes — il protège contre les lignes schéma complet avec du texte embarqué volumineux. `fields=lite` vs `fields=full` [#fieldslite-vs-fieldsfull] | Valeur | Champs retournés | Taille typique par ligne | | -------- | ----------------------------------------------------------- | ------------------------ | | `"lite"` | `_id`, `_creationTime`, plus 2 à 4 champs d'affichage | \~200–400 octets | | `"full"` | Tous les champs du schéma incluant le contenu texte complet | \~2 000–20 000 octets | La valeur par défaut est `"full"`. Pour toute boucle traitant plus d'une page, toujours passer `fields: "lite"`. Exemple de projection lite pour `list_tasks` : ```json { "_id": "k17abc...", "_creationTime": 1751020800000, "title": "Corriger la pagination list_memories", "status": "done", "assignedTo": "sigma", "priority": "urgent" } ``` La même tâche en mode `full` inclut `description` (potentiellement des centaines de caractères), `completionNote`, `blockers`, `dependsOn`, `missionId`, `orgId`, `createdBy`, `updatedAt`, et tous les autres champs du schéma. Comportement du plafonnement de limite [#comportement-du-plafonnement-de-limite] La fonction `clampLimit` dans `mcp-server/src/paging.ts` applique ces règles dans l'ordre : 1. Si `limit` est indéfini, retourner `DEFAULT_LIMIT` (20 pour la plupart des outils). 2. Si `limit < 1`, retourner 1. 3. Si `limit > MAX_LIMIT` (200), retourner 200. 4. Sinon retourner `limit` inchangé. Cela signifie qu'un appelant ne peut pas accidentellement demander un résultat non borné en passant une `limit` très grande. Le plafond de 200 lignes est appliqué quel que soit ce que l'appelant envoie. Anti-patterns [#anti-patterns] Les motifs suivants ont causé des incidents en production vérifiés. Chacun est interdit dans toutes les implémentations de serveur MCP VantageOS. **Cause racine de la classe d'incident Day-114.** L'assistant `paginate()` de Convex retourne : ```typescript { value: T[]; continueCursor: string | null; isDone: boolean; } ``` Le champ s'appelle `value`, pas `page`. Lire `result?.page` depuis cette forme retourne `undefined`, causant la production de `items: []` par le gestionnaire MCP à chaque appel — supprimant silencieusement toutes les données. Cela a affecté `list_memories` et `list_episodes` de v2.5.0 à v2.13.0. Les deux outils ont été corrigés dans la PR #978 (squash `0db28d5`). ```typescript // INTERDIT — .page n'existe pas ; items: [] à chaque appel const rawList = Array.isArray((memories as any)?.page) ? (memories as any).page : []; // CORRECT — lire .value depuis { value, continueCursor, isDone } const rawList = Array.isArray((memories as any)?.value) ? (memories as any).value : []; ``` Les appelants utilisant vantage-peers-mcp en dessous de la version 2.13.1 recevaient `items: []` de `list_memories` et `list_episodes` à chaque invocation. La mise à niveau vers `>=2.13.1` est requise. Accepter n'importe quelle valeur de `limit` sans plafond maximal permet aux appelants de demander 10 000+ lignes en une seule réponse. Cela dépasse les budgets de contexte et peut faire planter les limites de taille de réponse Railway/Convex. ```typescript // INTERDIT const limit = args.limit ?? 1000; // par défaut non borné // CORRECT import { clampLimit } from "./paging.js"; const requestedLimit = clampLimit(args.limit); // toujours [1, 200] ``` Plafonner à 200 lignes mais ne pas retourner `nextCursor` laisse les appelants avec un ensemble de résultats tronqué sans moyen de paginer au-delà du plafond. ```typescript // INTERDIT — l'appelant est bloqué à 200 lignes pour toujours const rows = await fetchRows(200); return { items: rows }; // pas de nextCursor // CORRECT — détecter hasMore, émettre nextCursor const requestedLimit = clampLimit(args.limit); const rows = await fetchRows(requestedLimit + 1); const hasMore = rows.length > requestedLimit; const page = hasMore ? rows.slice(0, requestedLimit) : rows; const nextCursor = hasMore ? encodeCursor({ createdBefore: page[page.length - 1]._creationTime }) : undefined; return { items: page, ...(nextCursor !== undefined ? { nextCursor } : {}) }; ``` Retourner `items` comme un tableau nu (pas enveloppé dans `{ items, nextCursor }`) brise la chaîne de pagination car les appelants ne peuvent pas détecter s'il y a d'autres pages. ```typescript // INTERDIT — tableau plat ; l'appelant ne peut pas paginer return { content: [{ type: "text", text: JSON.stringify(rows) }] }; // CORRECT — toujours l'enveloppe { items, nextCursor? } const envelope = { items: projected, ...(nextCursor ? { nextCursor } : {}) }; return { content: [{ type: "text", text: JSON.stringify(envelope, null, 2) }] }; ``` Retourner la chaîne `continueCursor` brute de Convex comme `nextCursor` dans l'enveloppe expose un format interne qui peut changer selon les versions de Convex. ```typescript // INTERDIT — expose le format interne de Convex const envelope = { items: filteredList, nextCursor: result.continueCursor }; // CORRECT — toujours passer par encodeCursor const nextCursor = !result.isDone && result.continueCursor !== null ? encodeCursor({ backendCursor: result.continueCursor }) : undefined; const envelope = { items: filteredList, ...(nextCursor ? { nextCursor } : {}) }; ``` `encodeCursor` produit un jeton base64url opaque. Les appelants passent ce jeton comme argument `cursor` lors du prochain appel. Le côté décodage (`decodeCursor`) se trouve dans le même fichier `paging.ts`. Un test qui affirme `result.items !== undefined` passe même quand `items: []`. C'était la cause racine de la revendication erronée "19/19 couverts" de Day-114 — tous les 19 tests passaient tandis que `list_memories` et `list_episodes` retournaient silencieusement des tableaux vides. ```typescript // INTERDIT — passe même quand items: [] expect(parsed).toHaveProperty("items"); expect(Array.isArray(parsed.items)).toBe(true); // CORRECT — semer N lignes, affirmer items.length === N const N = 5; mockConvex.mockResolvedValueOnce({ value: makeItems(N), continueCursor: null, isDone: true }); const result = await callTool("list_memories", { namespace: "orchestrator/sigma" }); const parsed = JSON.parse(result.content[0].text); expect(parsed.items).toHaveLength(N); // aurait détecté le bug .page de Day-114 ``` Chaque suite de tests d'outil `list_*` doit inclure au moins une assertion "insérer N, affirmer `items.length === N`". Pourquoi chaque outil list_* adopte par défaut une forme d'enveloppe sûre [#pourquoi-chaque-outil-list_-adopte-par-défaut-une-forme-denveloppe-sûre] L'objectif de conception est qu'un appelant ne passant aucun argument reçoive quand même une réponse sûre. La combinaison par défaut `limit: 20` et `fields: "full"` produit au maximum \~400 Ko pour les outils les plus riches en documents, bien dans le budget de contexte sûr pour tous les clients supportés (Claude.ai, Claude Code, ChatGPT, Codex). Pour les boucles de parcours en production — balayage de toutes les tâches d'une BU, export d'un namespace complet, etc. — toujours surcharger avec `limit: 200` et `fields: "lite"` pour maximiser le débit sans risque. Référence des exports paging.ts [#référence-des-exports-pagingts] L'utilitaire partagé `mcp-server/src/paging.ts` centralise toute la logique de pagination. Ses exports clés : | Export | Type | Description | | | ----------------------- | ------------- | ----------------------------------------------------------------------- | ------ | | `pagingArgsSchema` | `z.ZodObject` | Schéma Zod partagé : `{ limit, cursor, fields }` | | | `DEFAULT_LIMIT` | `50` | Valeur de repli de `clampLimit` quand `undefined` est fourni | | | `MAX_LIMIT` | `200` | Plafond strict appliqué par `clampLimit` | | | `ENVELOPE_TARGET_BYTES` | `50 000` | Limite douce en octets pour `enforceEnvelopeCap` | | | `clampLimit` | fonction | Plafonne `limit` à `[1, MAX_LIMIT]`, par défaut `DEFAULT_LIMIT` | | | `encodeCursor` | fonction | `CursorPayload → chaîne base64url` | | | `decodeCursor` | fonction | \`chaîne base64url → CursorPayload | null\` | | `enforceEnvelopeCap` | fonction | Divise les lignes de moitié jusqu'à rester sous `ENVELOPE_TARGET_BYTES` | | L'export `DEFAULT_LIMIT` de `clampLimit` est 50. Les outils individuels surchargent cela à 20 via `DEFAULT_PAGING.limit = 20` dans `applyPagingDefaults`. Quand aucune limite n'est fournie à un outil liste spécifique, la valeur par défaut de l'outil de 20 s'applique — pas la constante `DEFAULT_LIMIT`. Références croisées [#références-croisées] * [Pagination par curseur](/docs/pagination) — contrat d'enveloppe, motif de boucle, matrice de couverture * README du dépôt principal : [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * npm du serveur MCP : [vantage-peers-mcp](https://www.npmjs.com/package/vantage-peers-mcp) * Doctrine MCP Tools Standard : runbook VantageRegistry `kd750j7z7tqre6hxqmfsa8s9ed89erng` * PR de correction Day-114 : [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) * PR de doctrine : [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) --- # Documentation VantagePeers URL: /fr/docs Bienvenue sur VantagePeers [#bienvenue-sur-vantagepeers] VantagePeers est le backend open-source qui donne à vos agents IA une mémoire partagée, une messagerie inter-machines, une coordination des tâches et une planification de missions — le tout dans un seul déploiement Convex. Qu'est-ce que VantagePeers ? [#quest-ce-que-vantagepeers-] Quand vous exécutez plusieurs agents Claude Code sur différentes machines et sessions, ils font face à un problème de coordination : chaque agent démarre sans connaître ce que les autres ont fait, sans moyen d'envoyer des messages entre machines, et sans tableau de bord partagé. Vous finissez par bricoler des plugins mémoire, des hacks basés sur des fichiers et une coordination manuelle — et ça casse à l'échelle. VantagePeers résout ce problème en fournissant un backend auto-hébergé unique avec 20 tables de base de données et 82 outils MCP couvrant chaque primitive de coordination dont votre équipe d'agents a besoin. Les agents stockent des mémoires typées avec recherche sémantique, envoient des messages avec accusés de réception, assignent des tâches avec priorités et dépendances, planifient des missions avec des étapes de cycle de vie, écrivent des journaux de session et maintiennent un registre partagé de composants. Tout persiste dans le cloud Convex et est accessible à tout agent sur n'importe quelle machine. Ce n'est pas un SaaS. Ce n'est pas un service managé. Vous le déployez une fois avec `npx convex deploy`, vous l'ajoutez comme serveur MCP dans votre config Claude Code, et toute votre équipe d'agents est coordonnée. Licence FSL. Gratuit pour toujours. Liens rapides [#liens-rapides] | Sujet | Description | | ------------------------------------------------ | ----------------------------------------------------------- | | [Démarrage](/docs/getting-started) | Installer, déployer et connecter en moins de 10 minutes | | [Quickstart](/docs/getting-started/quickstart) | Deux agents qui échangent des messages en 15 minutes | | [Architecture](/docs/core-concepts/architecture) | Concepts clés, schéma de base de données et intégration MCP | | [Référence des outils](/docs/tools) | Les 14 catégories et 82 outils | | [Mémoire](/docs/capabilities/memory) | Mémoire sémantique, namespaces et recherche vectorielle | | [Messagerie](/docs/capabilities/messaging) | Messagerie inter-machines avec accusés de réception | | [Tâches](/docs/capabilities/tasks) | Cycle de vie des tâches, priorités, missions et cron | Chiffres clés [#chiffres-clés] * **20 tables de base de données** — mémoires, messages, tâches, missions, profils, journal, briefings, composants, patterns de fix, issues, mandats, unités commerciales, et plus * **82 outils MCP** — chaque primitive de coordination exposée comme outil MCP natif * **14 catégories de capacités** — mémoire, messagerie, tâches, missions, profils, journal, recherche, registre, patterns de fix, issues, mandats, unités commerciales, tâches récurrentes, monitoring d'erreurs * **\< 10 minutes** — de zéro à une équipe d'agents pleinement coordonnée * **0 € / mois** — licence FSL, auto-hébergé sur le tier gratuit de Convex À qui s'adresse VantagePeers ? [#à-qui-sadresse-vantagepeers-] VantagePeers est conçu pour les ingénieurs qui gèrent des équipes d'agents Claude Code orchestrés. Si vous avez plus d'un agent, ou si un agent a besoin de se souvenir de choses entre les sessions, vous avez besoin d'un backend de coordination. VantagePeers est ce backend. --- # Pagination par curseur URL: /fr/docs/pagination Pagination par curseur [#pagination-par-curseur] Chaque outil `list_*` dans VantagePeers retourne une enveloppe cohérente qui permet aux appelants de parcourir des ensembles de résultats arbitrairement grands sans atteindre la limite de 200 lignes par réponse. Pourquoi la pagination est essentielle [#pourquoi-la-pagination-est-essentielle] VantagePeers stocke tout dans un backend Convex partagé. Un seul namespace peut accumuler des milliers de tâches, mémoires ou briefings sur la durée de vie d'une équipe d'agents. Sans pagination : * Un appelant demandant toutes les tâches d'un espace de travail volumineux recevrait une réponse tronquée sans possibilité de détecter cette troncature. * Le payload de réponse MCP pourrait dépasser les tailles sûres pour le contexte, causant une perte de données silencieuse côté client. Le contrat d'enveloppe résout ces deux problèmes : chaque réponse `list_*` indique explicitement aux appelants s'il existe d'autres pages, et la limite stricte de 200 lignes par page maintient les payloads de réponse bornés. Enveloppe canonique [#enveloppe-canonique] Chaque outil `list_*` retourne exactement cette forme : ```typescript interface ListEnvelope { items: T[]; // lignes projetées — lite ou full selon le paramètre fields nextCursor?: string; // présent quand il y a d'autres pages ; absent (pas null) quand terminé } ``` `nextCursor` suit deux règles : 1. Quand il est présent, c'est un jeton base64url opaque. Ne pas analyser ni construire les valeurs de curseur — les passer tels quels. 2. Quand il est absent (pas `null`, simplement absent), il n'y a plus de pages. Arrêter l'itération. Sémantique du curseur [#sémantique-du-curseur] Le jeton de curseur est opaque. En interne, il encode soit un horodatage `{ createdBefore: number }` (le cas courant — la plupart des outils de liste utilisent un filtre `createdBefore` au niveau Convex) soit un `{ backendCursor: string }` référençant une continuation Convex native `paginate()` (utilisé par `list_memories` et `list_episodes`). Les appelants n'ont jamais besoin de connaître le format interne appliqué. Le décodage est géré côté serveur. **L'absence de curseur signifie terminé.** Une boucle d'appel doit s'arrêter quand `nextCursor` n'est pas présent dans la réponse — pas quand `items` est vide, et pas après un nombre fixe de pages. Limite par défaut et plafond strict [#limite-par-défaut-et-plafond-strict] | Constante | Valeur | Signification | | ----------------- | ------------- | -------------------------------------------------------------------------------------------- | | Limite par défaut | 20 | Lignes retournées par page quand aucun argument `limit` n'est fourni | | Plafond strict | 200 | Maximum de lignes par page quels que soient les arguments `limit` | | Cible d'enveloppe | 50 000 octets | Limite de taille douce ; le serveur divise les lignes de moitié jusqu'à rester sous ce seuil | Passer `limit: 200` donne la taille de page maximale. Ne pas passer de `limit` donne 20 lignes. Boucle de curseur TypeScript [#boucle-de-curseur-typescript] Le motif suivant parcourt un ensemble complet de résultats `list_tasks` en chaînant les curseurs : ```typescript import type { Client } from "@modelcontextprotocol/sdk/client/index.js"; interface TaskItem { _id: string; title: string; status: string; assignedTo?: string; } interface ListEnvelope { items: T[]; nextCursor?: string; } async function drainTasks( client: Client, assignedTo: string, status: string = "active" ): Promise { const allTasks: TaskItem[] = []; let cursor: string | undefined = undefined; do { const result = await client.callTool({ name: "list_tasks", arguments: { assignedTo, status, fields: "lite", limit: 200, ...(cursor !== undefined ? { cursor } : {}), }, }); const text = (result.content as Array<{ type: string; text: string }>)[0].text; const envelope = JSON.parse(text) as ListEnvelope; allTasks.push(...envelope.items); cursor = envelope.nextCursor; } while (cursor !== undefined); return allTasks; } ``` Points clés : * La condition de boucle est `cursor !== undefined`, pas `items.length > 0`. Une dernière page vide sans `nextCursor` est l'état terminal normal. * `fields: "lite"` maintient chaque page bien en dessous de la cible de 50 Ko d'enveloppe. * `limit: 200` maximise le débit par aller-retour. Matrice de couverture — 18 outils `list_*` [#matrice-de-couverture--18-outils-list_] L'audit Day-114 (`projects/vantage-peers/mcp-pagination-audit-day114.md`) a vérifié les 18 outils `list_*`. | Outil | Support curseur | Forme de l'enveloppe | Sévérité | | ----------------------- | --------------- | ----------------------------- | ---------------------------------------------- | | `list_tasks` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_tasks_by_mission` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_missions` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_messages` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_memories` | OUI | `{items, nextCursor}` | LOW — corrigé Day-114 PR #978 | | `list_episodes` | OUI | `{items, nextCursor}` | LOW — corrigé Day-114 PR #978 | | `list_briefing_notes` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_diaries` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_recurring_tasks` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_bus` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_peers` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_components` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_errors` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_issues` | OUI | `{count, issues, nextCursor}` | LOW — conforme | | `list_repo_mappings` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_fix_patterns` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_mandates` | OUI | `{items, nextCursor}` | LOW — conforme | | `list_broadcast_status` | EXCEPTION | forme objet unique | EXCEPTION — `@cursorPagingException` documenté | `list_broadcast_status` retourne un objet de statut unique (`{ messageId, from, channel, receipts[] }`) plutôt qu'un tableau de premier niveau. La pagination par curseur est architecturalement incompatible avec cette forme. `list_issues` utilise une enveloppe légèrement différente : `{count, issues, nextCursor}` plutôt que `{items, nextCursor}`. Accéder aux lignes via la clé `issues`, pas `items`. Paramètre `fields` [#paramètre-fields] Tous les outils `list_*` acceptent un argument `fields` : | Valeur | Lignes retournées | Cas d'utilisation | | -------- | -------------------------------------------- | -------------------------------------------------------------------- | | `"lite"` | Projection compacte — 4 à 6 champs par ligne | Parcours de grandes pages, listes latérales, vérifications de statut | | `"full"` | Tous les champs du schéma | Récupérations page unique où le détail complet est nécessaire | La valeur par défaut est `"full"`. Pour les boucles de parcours, toujours passer `fields: "lite"` pour rester bien sous la cible de 50 Ko d'enveloppe. Les projections lite incluent toujours `_id` et `_creationTime` plus 2 à 4 champs d'affichage (ex. `title`, `status`, `assignedTo` pour les tâches). Sécurité d'enveloppe [#sécurité-denveloppe] Voir [Sécurité d'enveloppe](/docs/envelope-safety) pour le catalogue complet des anti-patterns — notamment pourquoi `memories?.page` était un incident de sévérité HIGH Day-114 et comment la correction câble `encodeCursor`/`decodeCursor`. Références croisées [#références-croisées] * README du dépôt principal : [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * README du serveur MCP : [vantage-peers-mcp sur npm](https://www.npmjs.com/package/vantage-peers-mcp) * Doctrine MCP Tools Standard : runbook VantageRegistry `kd750j7z7tqre6hxqmfsa8s9ed89erng` * Doc d'audit Day-114 : `projects/vantage-peers/mcp-pagination-audit-day114.md` * PRs de correction Day-114 : [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) + [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) --- # Catalogue des outils URL: /fr/docs/tools-catalogue Catalogue des outils [#catalogue-des-outils] Catalogue complet de chaque outil MCP enregistré dans `vantage-peers-mcp`. Dérivé des littéraux de chaîne enregistrés dans `mcp-server/src/tools.ts`. Version actuelle du package : `vantage-peers-mcp@2.13.1`. Pour la documentation complète des paramètres, voir [Référence des outils](/docs/tools). Pour le comportement de pagination des outils `list_*`, voir [Pagination par curseur](/docs/pagination). Le support curseur/limite (O/N/EXCEPTION) reflète l'audit Day-114. Tous les outils `list_*` portent curseur + plafond 200 lignes après la PR #978. Les outils de recherche (`search_*`) et les accesseurs d'entité unique (`get_*`) n'utilisent pas l'enveloppe de curseur. Mémoire [#mémoire] | Outil | Objectif | Curseur/Limite | | -------------------- | ------------------------------------------------------------------------------------------- | --------------------------- | | `store_memory` | Stocker une mémoire typée et namespacée avec embedding vectoriel optionnel | N | | `get_memory` | Récupérer une seule mémoire par ID de document | N | | `list_memories` | Lister les mémoires dans un namespace filtrées par type ; limite par défaut 20, plafond 200 | O — corrigé Day-114 PR #978 | | `soft_delete_memory` | Suppression douce d'une mémoire pour qu'elle n'apparaisse plus dans les résultats recall | N | | `recall` | Recherche vectorielle sémantique sur les mémoires dans un namespace (fusion RRF) | N | | `text_search` | Recherche plein texte BM25 sur les mémoires | N | | `hybrid_search` | Recherche hybride combinée vecteur + BM25 utilisant la fusion RRF | N | Épisodes [#épisodes] | Outil | Objectif | Curseur/Limite | | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------- | | `store_episode` | Stocker un épisode structuré (contexte, objectif, action, résultat, insight, sévérité) | N | | `get_episode` | Récupérer un seul épisode par ID de document mémoire | N | | `list_episodes` | Lister les épisodes ordonnés du plus récent au plus ancien, filtres optionnels namespace + orchestrateur ; limite par défaut 20, plafond 200 | O — corrigé Day-114 PR #978 | | `search_episodes_by_keyword` | Recherche plein texte BM25 restreinte aux épisodes | N | | `search_episodes_by_semantic` | Recherche vectorielle sémantique restreinte aux épisodes, classée par similarité cosinus | N | Messagerie [#messagerie] | Outil | Objectif | Curseur/Limite | | ---------------------------- | ----------------------------------------------------------------------------------------------------- | ------------------------------ | | `send_message` | Envoyer un message à un canal, un rôle, ou en broadcast | N | | `check_messages` | Récupérer les messages non lus pour un destinataire ; accepte `since` pour la scrutation incrémentale | N | | `mark_as_read` | Marquer un ou plusieurs messages comme lus en utilisant les ID de reçu | N | | `delete_message` | Supprimer un message par ID (expéditeur ou système uniquement) | N | | `get_message` | Récupérer un seul message par ID de document Convex avec corps complet et canal | N | | `list_messages` | Lister les messages avec filtres optionnels from/canal ; limite par défaut 20, plafond 200 | O | | `list_broadcast_status` | Afficher qui a lu un message broadcast et qui ne l'a pas fait | EXCEPTION — forme objet unique | | `search_messages_by_keyword` | Recherche plein texte BM25 sur le contenu des messages | N | Tâches [#tâches] | Outil | Objectif | Curseur/Limite | | | ------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------- | - | | `create_task` | Créer une nouvelle tâche et l'assigner à un orchestrateur | N | | | `get_task` | Récupérer une seule tâche par ID de document Convex avec tous les champs | N | | | `list_tasks` | Lister les tâches par assigné et/ou statut ; \`fields=lite | full`, `createdBy`, `updatedSince`, `excludeAutoGenerated\` ; limite par défaut 20, plafond 200 | O | | `search_tasks_by_keyword` | Recherche plein texte BM25 sur les titres de tâches | N | | | `update_task` | Mettre à jour les champs d'une tâche — statut, priorité, bloqueurs, ou note de complétion ; **annuler** via `status="cancelled"` + `cancelReason` (créateur uniquement) | N | | | `start_task` | Marquer une tâche comme `in_progress` et enregistrer l'horodatage de début ; reprend plutôt que de redémarrer si du temps travaillé existe déjà ; refuse si un segment de travail est déjà ouvert | N | | | `pause_task` | Fermer le segment de travail ouvert et arrêter le chrono, sans terminer la tâche — en pause n'est pas bloqué | N | | | `resume_task` | Ouvrir un nouveau segment de travail sur une tâche en pause et la remettre en `in_progress` | N | | | `complete_task` | Marquer une tâche comme `done` avec une note de complétion obligatoire | N | | | `block_task` | Mettre une tâche en statut `blocked` avec une raison | N | | | `add_task_dependency` | Lier deux tâches pour qu'une ne puisse pas démarrer avant que l'autre soit complète | N | | | `checkout_task` | Revendiquer atomiquement une tâche (sûr pour les conflits multi-instances) | N | | | `delete_task` | Supprimer définitivement une tâche (créateur ou système uniquement ; bloqué en production — **annuler** une tâche erronée via `status="cancelled"` à la place) | N | | | `list_tasks_by_mission` | Lister toutes les tâches liées à une mission spécifique ; mêmes params `status`, `fields`, `createdBy`, `cursor` que `list_tasks` ; limite par défaut 20, plafond 200 | O | | | `bulk_complete_tasks` | Fermer en masse plusieurs tâches avec sécurité dry-run par défaut et porte RBAC | N | | | `validate_task_payload` | Lint dry-run pour les outils VP write-path ; retourne les échecs avec extraits de correction | N | | Missions [#missions] | Outil | Objectif | Curseur/Limite | | | ----------------------------------- | ----------------------------------------------------------------------- | ---------------------------------------------------- | - | | `create_mission` | Créer une nouvelle mission et assigner un pilote | N | | | `get_mission` | Retourner une mission avec toutes ses tâches liées et le statut actuel | N | | | `list_missions` | Lister les missions filtrées par statut ou pilote ; \`fields=lite | full`, `cursor\` ; limite par défaut 20, plafond 200 | O | | `update_mission` | Avancer une mission à l'étape suivante ou mettre à jour ses métadonnées | N | | | `update_mission_status` | Changer le statut du cycle de vie d'une mission en un seul appel | N | | | `get_mission_template` | Récupérer un modèle de mission par nom avec toutes les étapes | N | | | `update_mission_template` | Créer ou mettre à jour (upsert) un modèle de mission par nom | N | | | `instantiate_template_into_mission` | Créer une tâche par étape de modèle dans une mission | N | | Profils [#profils] | Outil | Objectif | Curseur/Limite | | ---------------- | --------------------------------------------------------------------------------------------------------------------------------------- | -------------- | | `get_profile` | Retourner le profil d'un orchestrateur | N | | `update_profile` | Créer ou mettre à jour un profil d'orchestrateur (mises à jour partielles supportées) | N | | `list_peers` | Retourner toutes les instances d'agents connues et leur statut actuel, les plus récentes en premier ; limite par défaut 20, plafond 200 | O | | `set_summary` | Mettre à jour le résumé de travail actuel pour une instance d'orchestrateur | N | | `whoami` | Retourner l'identité de l'orchestrateur intégrée dans le scope OAuth du bearer actuel | N | Journal [#journal] | Outil | Objectif | Curseur/Limite | | -------------- | ------------------------------------------------------------------------------------------------------------------- | -------------- | | `write_diary` | Écrire une entrée de journal pour une date donnée, écrasant toute entrée existante | N | | `get_diary` | Récupérer une entrée de journal spécifique par orchestrateur et date | N | | `list_diaries` | Lister les entrées de journal pour un orchestrateur, plage de dates optionnelle ; limite par défaut 20, plafond 200 | O | Briefings [#briefings] | Outil | Objectif | Curseur/Limite | | | ---------------------------------- | ---------------------------------------------------------------------------------------- | ---------------------------------------------------- | - | | `create_briefing_note` | Créer un enregistrement de briefing structuré avec participants, contenu et décisions | N | | | `update_briefing_note` | Mise à jour partielle d'un briefing existant (RBAC : `createdBy` ou `system` uniquement) | N | | | `get_briefing_note` | Récupérer un seul briefing par ID avec tous les champs | N | | | `list_briefing_notes` | Lister les briefings filtrés par sujet ; \`fields=lite | full`, `cursor\` ; limite par défaut 20, plafond 200 | O | | `search_briefing_notes_by_keyword` | Recherche plein texte BM25 sur le contenu des briefings | N | | Composants [#composants] | Outil | Objectif | Curseur/Limite | | -------------------- | ------------------------------------------------------------------------------------------------- | -------------- | | `register_component` | Enregistrer un composant (agent, skill, hook, plugin) avec sauvegarde complète du contenu | N | | `get_component` | Récupérer un composant par nom et type | N | | `list_components` | Lister tous les composants enregistrés filtrés par type ; limite par défaut 20, plafond 200 | O | | `update_component` | Mettre à jour le contenu ou la version d'un composant | N | | `delete_component` | Supprimer un composant du registre | N | | `search_components` | Recherche BM25 par sous-chaîne sur les composants par nom ou équipe avec filtre de type optionnel | N | Tâches récurrentes [#tâches-récurrentes] | Outil | Objectif | Curseur/Limite | | ----------------------- | ---------------------------------------------------------------------------------- | -------------- | | `create_recurring_task` | Définir un modèle de tâche récurrente avec expression cron | N | | `get_recurring_task` | Récupérer une seule définition de tâche récurrente par ID de document Convex | N | | `list_recurring_tasks` | Lister tous les modèles de tâches récurrentes ; limite par défaut 20, plafond 200 | O | | `update_recurring_task` | Mettre à jour un modèle de tâche récurrente | N | | `delete_recurring_task` | Supprimer un modèle de tâche récurrente (ne supprime pas les instances existantes) | N | | `pause_recurring_task` | Mettre en pause une tâche récurrente | N | | `resume_recurring_task` | Reprendre une tâche récurrente en pause | N | Mandats [#mandats] | Outil | Objectif | Curseur/Limite | | --------------------------- | ------------------------------------------------------------------- | -------------- | | `create_mandate` | Créer une demande de service inter-agents avec suivi de budget | N | | `accept_mandate` | Accepter un mandat | N | | `update_mandate` | Mettre à jour les champs d'un mandat | N | | `settle_mandate` | Enregistrer le coût réel et fermer un mandat | N | | `validate_mandate_spending` | Vérifier si une transaction est dans les limites du mandat | N | | `list_mandates` | Lister les mandats avec filtres ; limite par défaut 20, plafond 200 | O | | `get_mandate` | Récupérer un seul mandat par ID de document Convex | N | Unités commerciales [#unités-commerciales] | Outil | Objectif | Curseur/Limite | | ----------- | --------------------------------------------------------- | -------------- | | `create_bu` | Créer une unité commerciale avec stratégie et KPIs | N | | `update_bu` | Mettre à jour les champs d'une UC | N | | `get_bu` | Récupérer une UC par ID | N | | `list_bus` | Lister toutes les UCs ; limite par défaut 20, plafond 200 | O | | `delete_bu` | Supprimer une UC | N | Issues GitHub [#issues-github] | Outil | Objectif | Curseur/Limite | | ----------------------- | ------------------------------------------------------------------------------------------------------------ | -------------- | | `list_issues` | Lister les issues avec filtres ; enveloppe `{count, issues, nextCursor}` ; limite par défaut 20, plafond 200 | O | | `get_issue` | Récupérer une seule issue | N | | `update_issue_status` | Mettre à jour le statut d'une issue | N | | `link_commit_to_issue` | Lier un SHA de commit à une issue | N | | `verify_issue` | Marquer une issue comme vérifiée | N | | `issue_stats` | Obtenir les statistiques de nombre d'issues par projet et statut | N | | `link_issue_to_pattern` | Lier une issue à un fix pattern | N | Mappings de dépôts [#mappings-de-dépôts] | Outil | Objectif | Curseur/Limite | | | --------------------- | -------------------------------------------------------------- | ---------------------------------------------------- | - | | `add_repo_mapping` | Mapper un slug de dépôt GitHub à un orchestrateur | N | | | `list_repo_mappings` | Lister tous les mappings de dépôts ; \`fields=lite | full`, `cursor\` ; limite par défaut 20, plafond 200 | O | | `remove_repo_mapping` | Supprimer un mapping de dépôt | N | | | `get_repo_mapping` | Récupérer un seul mapping de dépôt par slug (propriétaire/nom) | N | | Fix Patterns [#fix-patterns] | Outil | Objectif | Curseur/Limite | | --------------------- | -------------------------------------------------------------------------- | -------------- | | `create_fix_pattern` | Créer un fix pattern documentant un bug, sa cause racine et sa correction | N | | `get_fix_pattern` | Récupérer un seul fix pattern par ID de document Convex | N | | `add_fix_attempt` | Documenter une tentative de correction (réussie/échouée) avec raisonnement | N | | `validate_fix` | Définir la correction validée sur un pattern | N | | `search_fix_patterns` | Recherche sémantique sur les fix patterns par symptôme | N | | `list_fix_patterns` | Lister les fix patterns par projet ; limite par défaut 20, plafond 200 | O | Déploiements [#déploiements] | Outil | Objectif | Curseur/Limite | | ------------------- | ---------------------------------------------------------------------------- | -------------- | | `add_deployment` | Enregistrer un déploiement Convex pour la surveillance proactive des erreurs | N | | `remove_deployment` | Désactiver un déploiement surveillé | N | Monitoring d'erreurs [#monitoring-derreurs] | Outil | Objectif | Curseur/Limite | | ------------- | ----------------------------------------------------------------------------------------------------------------------------------------- | -------------- | | `list_errors` | Lister les erreurs de déploiement détectées avec comptages de déduplication et numéros d'issues liées ; limite par défaut 20, plafond 200 | O | | `get_error` | Récupérer une seule entrée de log d'erreur par ID de document Convex | N | Bundles OKF [#bundles-okf] | Outil | Objectif | Curseur/Limite | | --------------------- | -------------------------------------------------------------------------------- | -------------- | | `export_okf_bundle` | Exporter un namespace comme tarball OKF portable (mémoires, briefings, tâches) | N | | `validate_okf_bundle` | Valider un bundle OKF sans écrire en base de données (dry-run, lecture seule) | N | | `import_okf_bundle` | Importer un bundle OKF dans un namespace cible (modes dry-run / merge / replace) | N | Improvisation [#improvisation] | Outil | Objectif | Curseur/Limite | | ---------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------- | | `improvisation_digest` | Digest hebdomadaire analysant les tâches, messages et mémoires VP pour les revendications d'artefacts durables manquant le pied de page VP-Sources ; consultatif uniquement | N | Récapitulatif [#récapitulatif] | Domaine | Nombre d'outils | | -------------------- | --------------- | | Mémoire | 7 | | Épisodes | 5 | | Messagerie | 8 | | Tâches | 16 | | Missions | 8 | | Profils | 5 | | Journal | 3 | | Briefings | 5 | | Composants | 6 | | Tâches récurrentes | 7 | | Mandats | 7 | | Unités commerciales | 5 | | Issues GitHub | 7 | | Mappings de dépôts | 4 | | Fix Patterns | 6 | | Déploiements | 2 | | Monitoring d'erreurs | 2 | | Bundles OKF | 3 | | Improvisation | 1 | | **Total** | **107** | Note : 14 alias en doublon ont été retirés de la surface enregistrée (PR #1169) ; chaque outil ci-dessous est un nom canonique, sans alias. Références croisées [#références-croisées] * [Référence des outils](/docs/tools) — documentation complète des paramètres par outil * [Pagination par curseur](/docs/pagination) — motif de boucle, contrat d'enveloppe, matrice de couverture * [Sécurité d'enveloppe](/docs/envelope-safety) — anti-patterns, `fields=lite`, plafonnement de limite * [Notes de version Day-114](/docs/release-notes/day-114) * README du dépôt principal : [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * npm du serveur MCP : [vantage-peers-mcp](https://www.npmjs.com/package/vantage-peers-mcp) * Doctrine MCP Tools Standard : runbook VantageRegistry `kd750j7z7tqre6hxqmfsa8s9ed89erng` --- # Référence des outils URL: /fr/docs/tools Référence des outils [#référence-des-outils] VantagePeers expose 114 outils MCP organisés en 15 catégories de capacités. Chaque outil accepte et retourne du JSON. Toutes les valeurs sont des chaînes en minuscules sauf indication contraire. Catégories d'outils [#catégories-doutils] | Catégorie | Nombre | Description | | ----------------------------------------------------- | ------ | -------------------------------------------------------------------------------- | | [Mémoire + Épisodes](#outils-mémoire--épisodes) | 14 | Mémoires typées, apprentissage épisodique, recherche sémantique et par mots-clés | | [Messagerie](#outils-messagerie) | 8 | Envoyer des messages inter-machines avec accusés de réception | | [Tâches](#outils-tâches) | 13 | Créer et gérer des tâches avec suivi complet du cycle de vie | | [Missions + Modèles](#outils-missions--modèles) | 8 | Regrouper les tâches en missions ; instancier des modèles | | [Profils et sessions](#outils-profils-et-sessions) | 6 | Identité d'agent, état de session et résolution d'identité | | [Journal + Briefings](#outils-journal--briefings) | 9 | Journaux quotidiens, notes de briefing et recherche par mots-clés | | [Composants](#outils-composants) | 7 | Sauvegarde et inventaire de composants | | [Tâches récurrentes](#outils-tâches-récurrentes) | 7 | Automatisation basée sur cron | | [Mandats](#outils-mandats) | 8 | Demandes de services inter-agents avec budgets | | [Unités commerciales](#outils-unités-commerciales) | 5 | Stratégie, tarification et KPIs des UC | | [Issues GitHub + Repos](#outils-issues-github--repos) | 13 | Suivi d'issues avec synchronisation webhook et mappings de dépôts | | [Fix Patterns](#outils-fix-patterns) | 9 | Base de connaissances de correctifs avec recherche sémantique | | [Monitoring d'erreurs](#outils-monitoring-derreurs) | 2 | Détection proactive d'erreurs de déploiement | | [Déploiements](#outils-déploiements) | 4 | Enregistrer et gérer les déploiements surveillés | | [Utilitaires](#outils-utilitaires) | 1 | Validation de payload | *** Outils mémoire [#outils-mémoire] Le système de mémoire stocke des connaissances typées et namespacées avec des embeddings vectoriels sémantiques. Toutes les mémoires sont recherchables par sens, pas seulement par mot-clé. `store_memory` [#store_memory] Stocke une nouvelle mémoire avec embedding vectoriel optionnel. ```json { "namespace": "global", "type": "feedback", "content": "Always use Edit tool over Write for existing files.", "createdBy": "alice" } ``` `recall` [#recall] Recherche sémantique sur les mémoires d'un namespace. ```json { "query": "Edit tool best practices", "namespace": "global", "limit": 5 } ``` `store_episode` [#store_episode] Stocke un épisode structuré (événement de succès ou d'échec avec contexte complet). ```json { "namespace": "orchestrator/alice", "createdBy": "alice", "context": "Deploying frontend component", "goal": "Fix broken layout on mobile", "action": "Delegated to dev-frontend with exact file:line brief", "outcome": "Fixed in one pass, no revisions needed", "insight": "Precise briefs with file:line citations eliminate revision cycles", "severity": "minor" } ``` `list_memories` [#list_memories] Liste les mémoires d'un namespace, avec filtre optionnel par type. ```json { "namespace": "project/vantage-starter", "type": "project", "limit": 20 } ``` `soft_delete_memory` [#soft_delete_memory] Suppression douce d'une mémoire pour qu'elle n'apparaisse plus dans les résultats de rappel. ```json { "memoryId": "memory-abc123" } ``` `get_memory` [#get_memory] Récupérer une mémoire unique par son ID. ```json { "memoryId": "memory-abc123" } ``` *** Outils recherche [#outils-recherche] Recherche plein texte et hybride sur le magasin de mémoires. `text_search` [#text_search] Recherche par mots-clés BM25 plein texte sur les mémoires. ```json { "query": "deployment error", "namespace": "global", "limit": 10 } ``` `hybrid_search` [#hybrid_search] Recherche combinée vectorielle + BM25 avec fusion RRF. ```json { "query": "deployment error", "namespace": "global", "limit": 10 } ``` *** Outils messagerie [#outils-messagerie] Les messages persistent dans le cloud Convex. Les agents hors ligne reçoivent les messages à la reconnexion. Les accusés de réception sont suivis par destinataire. `send_message` [#send_message] Envoie un message à un canal, rôle ou instance spécifique. ```json { "from": "alice", "channel": "bob", "content": "Phase 1 complete. Ready for review." } ``` `check_messages` [#check_messages] Récupère les messages non lus pour un destinataire. Optionnellement filtre par instance ou interroge de manière incrémentale via `since`. ```json { "recipient": "alice", "recipientInstanceId": "alice-main" } ``` Pour les polls fréquents, passez `since` (timestamp Unix ms de votre dernier check) pour ne recevoir que les messages créés après ce point. C'est le pattern recommandé pour les agents longue durée — il évite de re-transférer l'intégralité du backlog non lu à chaque appel. ```json { "recipient": "alice", "recipientInstanceId": "alice-main", "since": 1776803000000 } ``` Retourne un tableau de messages avec leurs receipt IDs. `mark_as_read` [#mark_as_read] Marque un ou plusieurs messages comme lus. ```json { "receiptIds": ["receipt-abc123", "receipt-def456"] } ``` `list_messages` [#list_messages] Liste les messages avec filtres optionnels. ```json { "from": "alice", "limit": 20 } ``` `delete_message` [#delete_message] Supprime un message par ID. ```json { "messageId": "jn7..." } ``` `list_peers` [#list_peers] Retourne toutes les instances d'agents connues et leur statut actuel. ```json {} ``` `list_broadcast_status` [#list_broadcast_status] Afficher qui a lu un message de diffusion et qui ne l'a pas lu. ```json { "messageId": "msg-abc123" } ``` *** Outils tâches [#outils-tâches] Les tâches suivent le travail de la création à la complétion avec piste d'audit complète. `create_task` [#create_task] ```json { "title": "Migrate HeroSection to lit-ui components", "assignedTo": "alice", "priority": "high", "createdBy": "bob" } ``` `list_tasks` [#list_tasks] ```json { "assignedTo": "alice", "status": "todo" } ``` **v2.3.1 — `fields` + `status` tableaux/alias.** `status` accepte : * une valeur unique (correspondance exacte) * un tableau : `["todo", "in_progress"]` * un alias : `"open"` → todo+in\_progress+review+blocked, `"active"` → todo+in\_progress, `"all"` → aucun filtre `fields=lite` renvoie une projection compacte (`_id`, `_creationTime`, `title`, `status`, `priority`, `assignedTo`, `missionId`). Omettre ou passer `"full"` pour le payload par défaut inchangé. ```json { "assignedTo": "alice", "status": "active", "fields": "lite" } ``` `list_tasks_by_mission` [#list_tasks_by_mission] Lister toutes les tâches liées à une mission spécifique. ```json { "missionId": "mission-abc123" } ``` **v2.3.1** — accepte les mêmes `status` tableaux/alias (`"open"`, `"active"`, `"all"`) et `fields=lite|full` que `list_tasks`, limité à la mission donnée. ```json { "missionId": "mission-abc123", "status": "active", "fields": "lite" } ``` `update_task` [#update_task] ```json { "taskId": "task-abc123", "priority": "urgent", "completionNote": "Reprioritized — waiting on API key" } ``` **Annuler une tâche créée par erreur** en passant `status="cancelled"` avec un `cancelReason` obligatoire — seul le créateur de la tâche peut l'annuler. Une tâche annulée est exclue des filtres `open`/`active` et n'est jamais comptée comme `done` ; une tâche déjà `done` ne peut pas être annulée. À privilégier sur `delete_task` (bloqué en production). Idem pour les missions via `update_mission` (`status="cancelled"` + `cancelReason`, créateur uniquement). ```json { "taskId": "task-abc123", "status": "cancelled", "cancelReason": "créée sur le mauvais projet", "callerOrchestrator": "sigma" } ``` `start_task` [#start_task] Marque une tâche comme `in_progress` et enregistre l'horodatage de début. Sur une tâche qui porte déjà du temps travaillé, ceci la reprend plutôt que de redémarrer le chrono — l'horodatage de début d'origine est conservé et un nouveau segment de travail est ouvert. Refuse si la tâche a déjà un segment de travail ouvert (quelqu'un travaille déjà activement dessus) : l'erreur nomme le verbe probablement attendu à la place (`resume_task` si la tâche était en pause). ```json { "taskId": "task-abc123" } ``` `pause_task` [#pause_task] Ferme le segment de travail actuellement ouvert de la tâche et arrête le chrono, sans terminer la tâche. Pause n'est pas la même chose que bloqué : `blocked` signifie en attente de quelqu'un d'autre, `pause_task` signifie que personne n'y travaille en ce moment mais que rien n'empêche le travail. La tâche repasse à `todo`, et son propriétaire la reprend avec `resume_task` ; `checkout_task` refuse une tâche en pause plutôt que de laisser quelqu'un d'autre s'en emparer. ```json { "taskId": "task-abc123" } ``` `resume_task` [#resume_task] Ouvre un nouveau segment de travail sur une tâche en pause et la remet en `in_progress`. Refuse si la tâche n'est pas actuellement en pause. ```json { "taskId": "task-abc123" } ``` `complete_task` [#complete_task] ```json { "taskId": "task-abc123", "completionNote": "HeroSection migrated. Biome and tsc passing." } ``` `checkout_task` [#checkout_task] Réclamer atomiquement une tâche (sans conflit pour les instances multiples). ```json { "taskId": "task-abc123", "callerOrchestrator": "alice" } ``` `delete_task` [#delete_task] Supprimer définitivement une tâche (créateur ou système uniquement). ```json { "taskId": "task-abc123", "callerOrchestrator": "carol" } ``` *** Outils missions [#outils-missions] Les missions regroupent les tâches liées et suivent la progression. `create_mission` [#create_mission] ```json { "name": "Landing Page Migration — Phase 1", "project": "vantage-starter", "priority": "high", "pilot": "alice", "agents": ["alice"], "status": "plan", "createdBy": "alice", "targetDate": 1712275200000 } ``` `list_missions` [#list_missions] ```json { "pilot": "alice" } ``` **v2.3.1 — `fields` + `status` tableaux/alias.** `status` accepte une valeur unique, un tableau (`["plan", "execute"]`), ou un alias spécifique aux missions : * `"open"` → brainstorm+plan+execute+validate (exclut `complete`) * `"active"` → plan+execute * `"all"` → aucun filtre `fields=lite` renvoie uniquement `_id`, `_creationTime`, `name`, `status`, `pilot`, `priority`, `project`. ```json { "status": "active", "fields": "lite" } ``` `update_mission` [#update_mission] ```json { "missionId": "mission-abc123", "status": "validate" } ``` `update_mission_status` [#update_mission_status] Changer le statut du cycle de vie d'une mission. ```json { "missionId": "mission-abc123", "status": "validate" } ``` *** Outils profils et sessions [#outils-profils-et-sessions] Les profils d'agents stockent l'identité statique et l'état dynamique. Le journal fournit des logs de session persistants. `get_profile` [#get_profile] ```json { "orchestratorId": "alice" } ``` `update_profile` [#update_profile] Créer ou mettre à jour un profil d'orchestrateur (mises à jour partielles supportées). ```json { "orchestratorId": "alice", "name": "Tau", "dynamic": { "currentTask": "Building dashboard", "lastSeen": 1712275200000, "sessionCount": 42 } } ``` `set_summary` [#set_summary] ```json { "orchestratorId": "alice", "instanceId": "alice-main", "summary": "Migrating HeroSection to lit-ui — ETA 30 minutes" } ``` `write_diary` [#write_diary] ```json { "date": "2026-03-29", "orchestrator": "alice", "content": "Completed Phase 1 of landing page migration.", "highlights": ["Nav fully migrated", "Hero responsive layout fixed"] } ``` `get_diary` [#get_diary] ```json { "orchestrator": "alice", "date": "2026-03-29" } ``` `list_diaries` [#list_diaries] ```json { "orchestrator": "alice", "limit": 10 } ``` `create_briefing_note` [#create_briefing_note] ```json { "title": "Landing page migration kickoff", "topic": "migration", "participants": ["alice", "bob"], "content": "Discussion du plan de migration de la landing page de shadcn vers lit-ui.", "decisions": ["Migrate section by section"], "createdBy": "alice" } ``` `list_briefing_notes` [#list_briefing_notes] ```json { "limit": 10 } ``` **v2.3.1** — accepte `fields=lite|full`. Lite renvoie `_id`, `_creationTime`, `topic`, `title`, `participants`, `createdBy`. Les notes de briefing n'ont pas de cycle de vie de statut, donc aucun alias `status` ne s'applique. ```json { "fields": "lite", "limit": 10 } ``` *** Outils tâches récurrentes [#outils-tâches-récurrentes] Automatisation basée sur cron. Voir [Tâches récurrentes](/docs/capabilities/recurring-tasks) pour la documentation complète. | Outil | Description | | ----------------------- | --------------------------------------------- | | `create_recurring_task` | Créer un nouveau modèle de tâche récurrente | | `list_recurring_tasks` | Lister tous les modèles de tâches récurrentes | | `delete_recurring_task` | Supprimer un modèle | `pause_recurring_task` [#pause_recurring_task] Mettre en pause une tâche récurrente. ```json { "recurringTaskId": "rt-abc123" } ``` `resume_recurring_task` [#resume_recurring_task] Reprendre une tâche récurrente en pause. ```json { "recurringTaskId": "rt-abc123" } ``` *** Outils registre [#outils-registre] Sauvegarde et inventaire de composants. Voir [Registre de composants](/docs/infrastructure/components) pour la documentation complète. | Outil | Description | | -------------------- | -------------------------------------- | | `register_component` | Enregistrer un composant | | `get_component` | Récupérer un composant par nom et type | | `list_components` | Lister les composants avec filtres | *** Outils mandats [#outils-mandats] Demandes de services inter-agents avec suivi de budget. Voir [Mandats](/docs/capabilities/mandates) pour la documentation complète. | Outil | Description | | --------------------------- | ------------------------------------------------ | | `create_mandate` | Créer une demande de service avec budget | | `accept_mandate` | Accepter un mandat | | `update_mandate` | Mettre à jour les champs d'un mandat | | `settle_mandate` | Enregistrer le coût réel, clore le mandat | | `validate_mandate_spending` | Vérifier si une transaction est dans les limites | | `list_mandates` | Lister les mandats avec filtres | *** Outils unités commerciales [#outils-unités-commerciales] Suivi des unités organisationnelles avec stratégie et KPIs. Voir [Unités commerciales](/docs/infrastructure/business-units) pour la documentation complète. | Outil | Description | | ----------- | --------------------------------- | | `create_bu` | Créer une unité commerciale | | `update_bu` | Mettre à jour les champs d'une UC | | `get_bu` | Récupérer une UC par ID | | `list_bus` | Lister toutes les UC | | `delete_bu` | Supprimer une UC | *** Outils issues GitHub [#outils-issues-github] Suivi d'issues avec synchronisation webhook et auto-liaison. Voir [Issues GitHub](/docs/infrastructure/issues) pour la documentation complète. | Outil | Description | | ----------------------- | ----------------------------------------------- | | `add_repo_mapping` | Mapper un dépôt GitHub à un orchestrateur | | `list_repo_mappings` | Lister tous les mappages de dépôts | | `remove_repo_mapping` | Supprimer un mappage de dépôt | | `list_issues` | Lister les issues avec filtres | | `get_issue` | Récupérer une issue | | `update_issue_status` | Mettre à jour le statut d'une issue | | `link_commit_to_issue` | Lier un commit à une issue | | `verify_issue` | Marquer une issue comme vérifiée | | `issue_stats` | Obtenir les statistiques de comptage des issues | | `link_issue_to_pattern` | Lier une issue à un fix pattern | *** Outils fix patterns [#outils-fix-patterns] Base de connaissances de correctifs avec recherche sémantique. Voir [Fix Patterns KB](/docs/capabilities/fix-patterns) pour la documentation complète. | Outil | Description | | ----------------------- | ------------------------------------------------------------------------- | | `create_fix_pattern` | Créer un fix pattern documentant un bug, sa cause racine et son correctif | | `add_fix_attempt` | Documenter une tentative de correctif (réussie/échouée) avec raisonnement | | `validate_fix` | Définir le correctif validé sur un pattern | | `search_fix_patterns` | Recherche sémantique sur les patterns | | `list_fix_patterns` | Lister les patterns par projet | | `link_issue_to_pattern` | Lier une issue VantagePeers à un fix pattern | *** Outils modèles de missions [#outils-modèles-de-missions] Modèles configurables pour la création automatique de missions avec des étapes prédéfinies. Voir [Protocole de résolution d'issues](/docs/infrastructure/issue-resolution) pour l'utilisation. | Outil | Description | | ------------------------- | ------------------------------------------------------ | | `get_mission_template` | Récupérer un modèle par nom | | `update_mission_template` | Mettre à jour les étapes et la configuration du modèle | *** Outils monitoring d'erreurs [#outils-monitoring-derreurs] Détection proactive d'erreurs de déploiement avec création automatique d'issues GitHub. Voir [Monitoring d'erreurs](/docs/infrastructure/error-monitoring) pour la documentation complète. | Outil | Description | | ------------------- | ------------------------------------------- | | `add_deployment` | Enregistrer un déploiement à surveiller | | `remove_deployment` | Désactiver la surveillance d'un déploiement | | `list_errors` | Lister les erreurs détectées avec filtres | | `get_error` | Récupérer une erreur par ID | --- # briefingNotes — Référence API URL: /fr/docs/api-reference/briefing-notes briefingNotes [#briefingnotes] **Source :** `convex/briefingNotes.ts` **Fn-paths :** 5 Les notes de briefing sont des transferts de session structurés entre orchestrateurs. Chaque note a un sujet, des participants, un contenu et des décisions optionnelles. Elles constituent l'enregistrement canonique pour le transfert de contexte inter-sessions — une note de briefing de la fin d'une session est lue au début de la suivante. *** `briefingNotes:create` [#briefingnotescreate] **Portée :** mutation Insère une nouvelle note de briefing. Arguments [#arguments] ```typescript { title: string, topic: string, // clé de catégorie, ex. "vp-release", "sprint-review" participants: string[], // IDs d'orchestrateurs présents content: string, decisions?: string[], linkedMemoryIds?: Id<"memories">[], createdBy: string, // ID d'orchestrateur } ``` Retour [#retour] `Id<"briefingNotes">` — l'ID de la nouvelle note. Exemple (outil MCP) [#exemple-outil-mcp] ```json { "tool": "mcp__vantage-peers__create_briefing_note", "args": { "title": "Clôture sprint Jour 82", "topic": "sprint-review", "participants": ["pi", "sigma"], "content": "Complété M3 iframeEmbedSessions.", "createdBy": "pi" } } ``` *** `briefingNotes:get` [#briefingnotesget] **Portée :** query Récupère une note de briefing unique par ID. Arguments [#arguments-1] ```typescript { noteId: Id<"briefingNotes"> } ``` Retour [#retour-1] ```typescript { _id: Id<"briefingNotes">, _creationTime: number, title: string, topic: string, participants: string[], content: string, decisions?: string[], linkedMemoryIds?: Id<"memories">[], createdBy: string, createdAt: number, updatedAt?: number, updatedBy?: string, } | null ``` *** `briefingNotes:list` [#briefingnoteslist] **Portée :** query Liste les notes de briefing, ordonnées par `createdAt` desc. Filtre de sujet optionnel. Arguments [#arguments-2] ```typescript { topic?: string, limit?: number, // défaut 20 (auto-limité à 15 pour fields=full) fields?: "lite" | "full", updatedSince?: number, // Unix ms } ``` **Projection `fields="lite"` :** `{ _id, _creationTime, topic, title, participants, createdBy }` Exemple (outil MCP) [#exemple-outil-mcp-1] ```json { "tool": "mcp__vantage-peers__list_briefing_notes", "args": { "topic": "sprint-review" } } ``` *** `briefingNotes:update` [#briefingnotesupdate] **Portée :** mutation Mise à jour partielle de tout champ mutable d'une note de briefing. `callerOrchestrator` est **requis** et doit être le créateur ou `"system"`. Arguments [#arguments-3] ```typescript { noteId: Id<"briefingNotes">, callerOrchestrator: string, // REQUIS — doit être createdBy ou "system" title?: string, topic?: string, participants?: string[], content?: string, decisions?: string[], linkedMemoryIds?: Id<"memories">[], } ``` Retour [#retour-2] `null` Note RBAC [#note-rbac] Contrairement à la plupart des autres mutations, `callerOrchestrator` n'est pas optionnel ici. L'omettre provoque une erreur de validation. C'est intentionnel — les notes de briefing utilisent une politique de mise à jour deny-by-default. *** `briefingNotes:deleteBriefingNote` [#briefingnotesdeletebriefingnote] **Portée :** mutation Suppression définitive d'une note de briefing. Seul le créateur (`createdBy`) ou `"system"` peut supprimer. Arguments [#arguments-4] ```typescript { noteId: Id<"briefingNotes">, callerOrchestrator?: string, } ``` Retour [#retour-3] ```typescript { deleted: boolean } ``` --- # diary — Référence API URL: /fr/docs/api-reference/diary diary [#diary] **Source :** `convex/diary.ts` **Fn-paths :** 5 Le module diary fournit des journaux de session quotidiens par orchestrateur. Chaque entrée est indexée par `(orchestrator, date)` — écrire pour la même date est un upsert. Les entrées de journal supportent du contenu libre ainsi que des tableaux structurés `highlights` et `blockers`. *** `diary:write` [#diarywrite] **Portée :** mutation Upsert d'une entrée de journal. Si une entrée existe déjà pour cette combinaison `date + orchestrator`, elle est mise à jour sur place. Arguments [#arguments] ```typescript { date: string, // chaîne de date ISO 8601 ex. "2026-05-29" orchestrator: string, // ID d'orchestrateur content: string, highlights?: string[], blockers?: string[], } ``` Retour [#retour] `Id<"diary">` — l'ID de l'entrée créée ou mise à jour. Exemple (outil MCP) [#exemple-outil-mcp] ```json { "tool": "mcp__vantage-peers__write_diary", "args": { "date": "2026-05-29", "orchestrator": "sigma", "content": "Livraison M3 complétée.", "highlights": ["M3 livré dans les temps"] } } ``` *** `diary:get` [#diaryget] **Portée :** query Récupère une entrée de journal par date et orchestrateur. Arguments [#arguments-1] ```typescript { date: string, orchestrator: string, } ``` Retour [#retour-1] ```typescript { _id: Id<"diary">, _creationTime: number, date: string, orchestrator: string, instanceId?: string, content: string, highlights?: string[], blockers?: string[], createdAt: number, } | null ``` *** `diary:list` [#diarylist] **Portée :** query Liste les entrées de journal par orchestrateur, ordonnées par date desc. Arguments [#arguments-2] ```typescript { orchestrator?: string, // si omis, retourne toutes les entrées de tous les orchestrateurs limit?: number, // défaut 20 } ``` Exemple (outil MCP) [#exemple-outil-mcp-1] ```json { "tool": "mcp__vantage-peers__list_diary", "args": { "orchestrator": "sigma", "limit": 7 } } ``` *** `diary:deleteDiary` [#diarydeletediary] **Portée :** mutation Suppression définitive d'une entrée de journal. Seul le propriétaire (`orchestrator`) ou `"system"` peut supprimer. Arguments [#arguments-3] ```typescript { diaryId: Id<"diary">, callerOrchestrator?: string, } ``` Retour [#retour-2] ```typescript { deleted: boolean } ``` *** `diary:listByDateRange` [#diarylistbydaterange] **Portée :** query Liste les entrées de journal entre deux dates (incluses). Utile pour les revues hebdomadaires ou la relecture de session. Arguments [#arguments-4] ```typescript { from: string, // chaîne de date ISO 8601 ex. "2026-05-20" to: string, // chaîne de date ISO 8601 ex. "2026-05-29" orchestrator?: string, } ``` Les résultats sont ordonnés par date ascendante. Exemple (outil MCP) [#exemple-outil-mcp-2] ```json { "tool": "mcp__vantage-peers__list_diary_by_date_range", "args": { "from": "2026-05-20", "to": "2026-05-29", "orchestrator": "sigma" } } ``` --- # iframeEmbedSessions — Référence API URL: /fr/docs/api-reference/iframe-embed-sessions iframeEmbedSessions [#iframeembedsessions] **Source :** `convex/iframeEmbedSessions.ts` **Fn-paths :** 4 **Ajouté :** v2.4.0 (livrable M3 — SEP-1865) Le module `iframeEmbedSessions` gère les enregistrements de sessions authentifiées pour les embeds iframe Gen UI VantagePeers. Chaque session représente une connexion authentifiée depuis une origine spécifique, portant un contexte optionnel de tenant et d'utilisateur. Les sessions expirent automatiquement via le champ `expiresAt`. **Principes de conception :** * `getSession` retourne `null` pour les sessions expirées — les appelants doivent les traiter comme inexistantes * `revokeSession` est le chemin de déconnexion sécurisée — les sessions révoquées sont immédiatement traitées comme inexistantes par `getSession` * `touchSession` étend la présence sans changer `expiresAt` — il ne met à jour que `lastSeenAt` * Les IDs de session sont des chaînes générées par le client — utilisez `crypto.randomUUID()` ou équivalent *** `iframeEmbedSessions:createSession` [#iframeembedsessionscreatesession] **Portée :** mutation Crée un nouvel enregistrement de session embed iframe. Arguments [#arguments] ```typescript { sessionId: string, // ID unique généré par le client (ex. crypto.randomUUID()) tenantId?: string, // contexte de routage multi-tenant origin: string, // origine de l'embed, ex. "https://app.example.com" userId?: string, // contexte par utilisateur pour l'embed expiresAt: number, // Unix ms — quand la session expire } ``` Retour [#retour] `Id<"iframeEmbedSessions">` — l'ID de document Convex de la nouvelle session. Exemple (ConvexHttpClient) [#exemple-convexhttpclient] ```typescript const docId = await client.mutation("iframeEmbedSessions:createSession", { sessionId: crypto.randomUUID(), origin: "https://dashboard.example.com", userId: "user_abc123", expiresAt: Date.now() + 30 * 60 * 1000, // 30 minutes }); ``` Exemple (outil MCP) [#exemple-outil-mcp] ```json { "tool": "mcp__vantage-peers__create_iframe_session", "args": { "sessionId": "550e8400-e29b-41d4-a716-446655440000", "origin": "https://dashboard.example.com", "userId": "user_abc123", "expiresAt": 1748556000000 } } ``` *** `iframeEmbedSessions:getSession` [#iframeembedsessionsgetsession] **Portée :** query Récupère une session par `sessionId`. Retourne `null` pour les sessions expirées ou révoquées. Arguments [#arguments-1] ```typescript { sessionId: string } ``` Retour [#retour-1] ```typescript { _id: Id<"iframeEmbedSessions">, _creationTime: number, sessionId: string, tenantId?: string, origin: string, userId?: string, createdAt: number, lastSeenAt: number, expiresAt: number, revoked: boolean, } | null ``` Retourne `null` si : * La session n'existe pas * `session.expiresAt <= Date.now()` — expirée * `session.revoked === true` — révoquée Exemple (ConvexHttpClient) [#exemple-convexhttpclient-1] ```typescript const session = await client.query("iframeEmbedSessions:getSession", { sessionId: "550e8400-e29b-41d4-a716-446655440000", }); if (session === null) { // Session expirée ou révoquée — rediriger vers la connexion } ``` *** `iframeEmbedSessions:touchSession` [#iframeembedsessionstouchsession] **Portée :** mutation Met à jour `lastSeenAt` à l'heure actuelle. Appelé à chaque événement d'activité de l'embed pour maintenir une fenêtre de présence précise. Ne prolonge **pas** `expiresAt`. Arguments [#arguments-2] ```typescript { sessionId: string } ``` Retour [#retour-2] `boolean` — `true` si la session a été trouvée et mise à jour, `false` si non trouvée ou déjà révoquée. Exemple (outil MCP) [#exemple-outil-mcp-1] ```json { "tool": "mcp__vantage-peers__touch_iframe_session", "args": { "sessionId": "550e8400-e29b-41d4-a716-446655440000" } } ``` *** `iframeEmbedSessions:revokeSession` [#iframeembedsessionsrevokesession] **Portée :** mutation Marque une session comme révoquée. Les sessions révoquées sont immédiatement traitées comme inexistantes par `getSession`. À utiliser pour les flux de déconnexion ou d'invalidation sécurisée. Arguments [#arguments-3] ```typescript { sessionId: string } ``` Retour [#retour-3] `boolean` — `true` si la session a été trouvée et révoquée, `false` si non trouvée (déjà supprimée ou jamais créée). Exemple (outil MCP) [#exemple-outil-mcp-2] ```json { "tool": "mcp__vantage-peers__revoke_iframe_session", "args": { "sessionId": "550e8400-e29b-41d4-a716-446655440000" } } ``` Note de sécurité [#note-de-sécurité] `revokeSession` ne supprime pas la ligne de session — elle définit `revoked: true`. La ligne est préservée à des fins d'audit. Un nettoyage basé sur des crons des sessions expirées et révoquées peut être ajouté en déployant une fonction planifiée contre `iframeEmbedSessions` — voir `convex/crons.ts` pour le pattern. --- # Référence API URL: /fr/docs/api-reference Référence API [#référence-api] Cette section catalogue les **41 fn-paths** exposés par le backend Convex VantagePeers. Ce sont les signatures de fonctions de référence utilisées par chaque consommateur du backend : le serveur MCP, le pattern d'agents Hermes/Mu, et tout consommateur direct via `ConvexHttpClient`. Contrat de stabilité [#contrat-de-stabilité] Les fn-paths sont un **contrat stable**. Les changements incompatibles — arguments supprimés, formes de retour modifiées, chemins renommés — sont signalés par un bump de version majeure SemVer sur le package npm `vantage-peers-mcp`. Les changements additifs (nouveaux arguments optionnels, nouveaux champs de retour optionnels) sont non-incompatibles et peuvent arriver dans une version mineure. Utiliser les fn-paths directement [#utiliser-les-fn-paths-directement] Chaque fn-path peut être appelé directement via `ConvexHttpClient` depuis n'importe quel environnement Node.js ou navigateur : ```typescript import { ConvexHttpClient } from "convex/browser"; const client = new ConvexHttpClient("https://votre-deployment.convex.cloud"); // Query (lecture, temps réel, mise en cache) const tasks = await client.query("tasks:list", { assignedTo: "sigma" }); // Mutation (écriture, transactionnelle) const taskId = await client.mutation("tasks:create", { title: "Déployer en production", assignedTo: "sigma", priority: "high", status: "todo", createdBy: "pi", }); ``` Les outils MCP sont de fines couches au-dessus de ces fn-paths exacts. Pour le débogage, vous pouvez toujours appeler le fn-path directement depuis l'onglet **Functions** du tableau de bord Convex. Index des modules [#index-des-modules] | Module | Fn-paths | Source | | ---------------------------------------------------------------- | -------- | ------------------------------- | | [tasks](/docs/api-reference/tasks) | 10 | `convex/tasks.ts` | | [messages](/docs/api-reference/messages) | 8 | `convex/messages.ts` | | [memories](/docs/api-reference/memories) | 4 | `convex/memories.ts` | | [briefingNotes](/docs/api-reference/briefing-notes) | 5 | `convex/briefingNotes.ts` | | [diary](/docs/api-reference/diary) | 5 | `convex/diary.ts` | | [missions](/docs/api-reference/missions) | 6 | `convex/missions.ts` | | [iframeEmbedSessions](/docs/api-reference/iframe-embed-sessions) | 4 | `convex/iframeEmbedSessions.ts` | **Total : 41 fn-paths** Types communs [#types-communs] Ces types apparaissent dans plusieurs modules. `creatorValidator` (ID d'orchestrateur) [#creatorvalidator-id-dorchestrateur] Une chaîne simple — tout nom d'orchestrateur est accepté. Valeurs courantes : `"sigma"`, `"pi"`, `"tau"`, `"phi"`, `"system"`. Pas de contrainte d'enum — les nouveaux orchestrateurs sont enregistrés dynamiquement via la table des profils. Enum de priorité [#enum-de-priorité] `"urgent" | "high" | "medium" | "low"` Alias de statut (tasks) [#alias-de-statut-tasks] L'argument `status` de `tasks:list` et `tasks:listByMission` accepte : * Une valeur littérale : `"todo" | "in_progress" | "review" | "blocked" | "done"` * Un alias : `"open"` (s'étend à `["todo","in_progress","review","blocked"]`) ou `"active"` (s'étend à `["todo","in_progress"]`) * Un tableau de valeurs littérales : `["todo", "in_progress"]` Alias de statut (missions) [#alias-de-statut-missions] L'argument `status` de `missions:list` accepte : * Une valeur littérale : `"brainstorm" | "plan" | "execute" | "validate" | "complete"` * Un alias : `"open"` (s'étend à `["brainstorm","plan","execute","validate"]`) ou `"active"` (s'étend à `["plan","execute"]`) Limites de taux et RBAC [#limites-de-taux-et-rbac] VantagePeers n'applique pas de limites de taux par fn-path au niveau Convex. La limitation de taux, si nécessaire, doit être appliquée au niveau du serveur MCP ou de la passerelle HTTP. Le RBAC est appliqué dans les mutations via le pattern d'argument `callerOrchestrator`. Lorsqu'il est fourni, la mutation vérifie que l'appelant est le créateur ou l'assigné de la ressource. Passer `callerOrchestrator: "system"` contourne les vérifications RBAC — à utiliser uniquement pour les appels internes serveur-à-serveur. --- # memories — Référence API URL: /fr/docs/api-reference/memories memories [#memories] **Source :** `convex/memories.ts` **Fn-paths :** 4 Le module memories est le magasin de connaissances central. Chaque mémoire stockée est automatiquement embeddée via `text-embedding-3-small` (1536 dims) et indexée pour la recherche vectorielle sémantique. Les mémoires supportent les namespaces, les types, les relations, l'expiration TTL et un flag `isLatest` pour le versionnage. L'embedding RAG est asynchrone — il est planifié via `ctx.scheduler.runAfter(0, ...)` immédiatement après la complétion de la mutation `storeMemory`. Il n'y a pas d'attente synchrone ; l'embedding est disponible en quelques secondes. *** `memories:storeMemory` [#memoriesstorememory] **Portée :** mutation Crée une ligne de mémoire et planifie l'embedding RAG asynchrone. Arguments [#arguments] ```typescript { namespace: string, // ex. "global", "sigma/feedback", "project/vp" type: MemoryType, // voir enum de types ci-dessous content: string, createdBy: string, // ID d'orchestrateur relations?: Array<{ targetId: Id<"memories">, type: RelationType, // "updates" | "references" | "contradicts" | "extends" }>, isLatest?: boolean, // défaut true côté serveur ttl?: string, // datetime ISO 8601 — expire automatiquement à ce moment episode?: { context: string, goal: string, action: string, outcome: string, insight: string, severity: "low" | "medium" | "high" | "critical", }, } ``` **Enum `type` :** `"fact"` | `"decision"` | `"feedback"` | `"project"` | `"architecture"` | `"note"` | `"warning"` | `"procedure"` | `"episode"` | `"observation"` **Enum `relations[].type` :** `"updates"` | `"references"` | `"contradicts"` | `"extends"` Quand une relation a `type: "updates"`, la mémoire cible est marquée `isLatest: false` et retirée des résultats de recherche futurs. Retour [#retour] `Id<"memories">` — l'ID de la nouvelle mémoire. Exemple (outil MCP) [#exemple-outil-mcp] ```json { "tool": "mcp__vantage-peers__store_memory", "args": { "namespace": "sigma/feedback", "type": "feedback", "content": "La limitation de taux au niveau gateway est la bonne approche.", "createdBy": "pi" } } ``` *** `memories:getMemory` [#memoriesgetmemory] **Portée :** query Récupère une mémoire unique par ID. Arguments [#arguments-1] ```typescript { memoryId: Id<"memories"> } ``` Retour [#retour-1] Document de mémoire complet ou `null`. *** `memories:listMemories` [#memorieslistmemories] **Portée :** query Liste les mémoires actives par namespace, avec un filtre de type optionnel. Supporte la pagination par curseur. Arguments [#arguments-2] ```typescript { namespace: string, type?: MemoryType, includeSuperseded?: boolean, // défaut false — uniquement isLatest=true limit?: number, // défaut 50 paginationOpts?: { numItems: number, cursor: string | null, }, } ``` Retour [#retour-2] ```typescript { value: MemoryDoc[], continueCursor: string | null, isDone: boolean, } ``` Exemple (ConvexHttpClient) [#exemple-convexhttpclient] ```typescript // Première page const page1 = await client.query("memories:listMemories", { namespace: "sigma/feedback", paginationOpts: { numItems: 20, cursor: null }, }); // Page suivante if (!page1.isDone) { const page2 = await client.query("memories:listMemories", { namespace: "sigma/feedback", paginationOpts: { numItems: 20, cursor: page1.continueCursor }, }); } ``` *** `memories:softDeleteMemory` [#memoriessoftdeletememory] **Portée :** mutation Marque une mémoire comme `isLatest: false`. La ligne de mémoire est préservée (piste d'audit) mais n'apparaîtra plus dans `listMemories` ni dans les résultats de recherche sémantique. Arguments [#arguments-3] ```typescript { memoryId: Id<"memories"> } ``` Retour [#retour-3] `null` Effets secondaires [#effets-secondaires] 1. Patch la mémoire à `isLatest: false`. 2. Planifie `internal.ragSync.markRagEntrySuperseded` — retire de la recherche vectorielle de façon asynchrone. Exemple (outil MCP) [#exemple-outil-mcp-1] ```json { "tool": "mcp__vantage-peers__soft_delete_memory", "args": { "memoryId": "m57..." } } ``` --- # messages — Référence API URL: /fr/docs/api-reference/messages messages [#messages] **Source :** `convex/messages.ts` **Fn-paths :** 8 Le module messages fournit la messagerie inter-machines entre orchestrateurs. Chaque message crée une ligne dans `messages` plus une ligne `messageReceipts` par destinataire. Les reçus suivent l'état de lecture par destinataire de façon indépendante. La **résolution broadcast** est dynamique : le canal `"broadcast"` se résout en tous les orchestrateurs avec un profil enregistré au moment de l'envoi — pas de liste hardcodée. *** `messages:sendMessage` [#messagessendmessage] **Portée :** mutation Envoie un message à un ou plusieurs orchestrateurs. Arguments [#arguments] ```typescript { from: string, // ID de l'orchestrateur expéditeur fromInstanceId?: string, channel: string, // "broadcast" | "sigma" | "pi,phi" (multi séparé par virgule) content: string, sessionDay?: number, tenantId?: string, } ``` **Routage de canal :** * `"broadcast"` — résolution dynamique : tous les profils sauf l'expéditeur * `"sigma"` — destinataire unique * `"pi,phi"` — multi-destinataire séparé par virgule * `"sigma-vps-01"` — ciblage au niveau instance (contient `"-"`) Retour [#retour] `Id<"messages">` — l'ID du nouveau message. Exemple (outil MCP) [#exemple-outil-mcp] ```json { "tool": "mcp__vantage-peers__send_message", "args": { "from": "pi", "channel": "broadcast", "content": "Déploiement v2.4.0 dans 5 minutes — suspendre les écritures." } } ``` *** `messages:checkNewMessages` [#messageschecknewmessages] **Portée :** query Récupère les messages non lus pour un destinataire. Retourne les messages avec leurs IDs de reçu (nécessaires pour marquer comme lu). Arguments [#arguments-1] ```typescript { recipient: string, // ID d'orchestrateur recipientInstanceId?: string, tenantId?: string, since?: number, // Unix ms — uniquement les reçus avec _creationTime > since } ``` Retour [#retour-1] ```typescript Array<{ receiptId: Id<"messageReceipts">, messageId: Id<"messages">, from: string, fromInstanceId?: string, channel?: string, content: string, createdAt: number, }> ``` Exemple (outil MCP) [#exemple-outil-mcp-1] ```json { "tool": "mcp__vantage-peers__check_messages", "args": { "recipient": "sigma" } } ``` *** `messages:markAsRead` [#messagesmarkasread] **Portée :** mutation Marque un ou plusieurs reçus comme lus. Passez les valeurs `receiptId` de `checkNewMessages`. Arguments [#arguments-2] ```typescript { receiptIds: Id<"messageReceipts">[] } ``` Retour [#retour-2] `number` — nombre de reçus effectivement marqués (ignore les reçus déjà lus). *** `messages:deleteMessage` [#messagesdeletemessage] **Portée :** mutation Supprime un message et supprime en cascade tous ses reçus. Arguments [#arguments-3] ```typescript { messageId: Id<"messages">, callerOrchestrator?: string, // RBAC : doit être message.from ou "system" } ``` Retour [#retour-3] ```typescript { deleted: boolean, receiptsDeleted: number } ``` *** `messages:listMessages` [#messageslistmessages] **Portée :** query Récupère les messages pour un jour de session ou d'un expéditeur (historique/relecture). Arguments [#arguments-4] ```typescript { sessionDay?: number, from?: string, limit?: number, // défaut 100 } ``` Exemple (ConvexHttpClient) [#exemple-convexhttpclient] ```typescript const history = await client.query("messages:listMessages", { sessionDay: 82, }); ``` *** `messages:getUnreadCount` [#messagesgetunreadcount] **Portée :** query Compte les reçus non lus pour un rôle destinataire. Arguments [#arguments-5] ```typescript { orchestratorId: string } ``` Retour [#retour-4] `number` — nombre de reçus non lus (limité à 500 dans une seule requête). *** `messages:listBroadcastStatus` [#messageslistbroadcaststatus] **Portée :** query Affiche qui a lu un message broadcast et qui ne l'a pas fait. Utile pour confirmer que tous les agents ont reçu une annonce critique. Arguments [#arguments-6] ```typescript { messageId: Id<"messages"> } ``` Retour [#retour-5] ```typescript { messageId: Id<"messages">, from: string, channel?: string, createdAt: number, receipts: Array<{ recipient: string, recipientInstanceId?: string, read: boolean, readAt?: number, }>, } ``` *** `messages:listByChannel` [#messageslistbychannel] **Portée :** query Liste les messages récents pour un canal spécifique, ou tous les messages si le canal n'est pas spécifié. Arguments [#arguments-7] ```typescript { channel?: string, limit?: number, // défaut 100 } ``` Exemple (ConvexHttpClient) [#exemple-convexhttpclient-1] ```typescript const recent = await client.query("messages:listByChannel", { channel: "broadcast", limit: 20, }); ``` --- # missions — Référence API URL: /fr/docs/api-reference/missions missions [#missions] **Source :** `convex/missions.ts` **Fn-paths :** 6 Les missions sont l'unité de planification de plus haut niveau. Une mission regroupe des tâches, définit un pilote, suit la progression (0–100) et passe par un cycle de vie : `brainstorm → plan → execute → validate → complete`. Les missions sont automatiquement complétées quand toutes leurs tâches liées atteignent `status="done"`. *** `missions:create` [#missionscreate] **Portée :** mutation Insère une nouvelle mission. Arguments [#arguments] ```typescript { name: string, description?: string, project: string, status: "brainstorm" | "plan" | "execute" | "validate" | "complete", priority: "urgent" | "high" | "medium" | "low", pilot: string, // ID de l'orchestrateur lead agents: string[], // IDs des orchestrateurs participants brief?: string, startDate?: number, // Unix ms targetDate?: number, // Unix ms progress?: number, // 0-100 createdBy: string, } ``` Retour [#retour] `Id<"missions">` — l'ID de la nouvelle mission. Exemple (outil MCP) [#exemple-outil-mcp] ```json { "tool": "mcp__vantage-peers__create_mission", "args": { "name": "M3 sessions iframe embed", "project": "vantage-peers", "status": "plan", "priority": "high", "pilot": "sigma", "agents": ["sigma", "pi"], "createdBy": "pi" } } ``` *** `missions:get` [#missionsget] **Portée :** query Récupère une mission unique par ID. Arguments [#arguments-1] ```typescript { missionId: Id<"missions"> } ``` Retour [#retour-1] Document complet de mission ou `null`. *** `missions:list` [#missionslist] **Portée :** query Liste les missions avec des filtres optionnels. Supporte la projection lite et les alias de statut. Arguments [#arguments-2] ```typescript { project?: string, pilot?: string, status?: string | string[], // "brainstorm"|"open"|"active"|["plan","execute"] limit?: number, // défaut 50 (auto-limité à 30 pour fields=full) fields?: "lite" | "full", updatedSince?: number, // Unix ms } ``` **Alias de statut :** * `"open"` → `["brainstorm","plan","execute","validate"]` * `"active"` → `["plan","execute"]` **Projection `fields="lite"` :** `{ _id, _creationTime, name, status, pilot, priority, project }` Exemple (outil MCP) [#exemple-outil-mcp-1] ```json { "tool": "mcp__vantage-peers__list_missions", "args": { "project": "vantage-peers", "status": "open" } } ``` Fichier source [#fichier-source] `convex/missions.ts:177` *** `missions:update` [#missionsupdate] **Portée :** mutation Mise à jour partielle de tout champ mutable d'une mission. Tous les champs sauf `missionId` sont optionnels. Arguments [#arguments-3] ```typescript { missionId: Id<"missions">, name?: string, description?: string, project?: string, status?: "brainstorm" | "plan" | "execute" | "validate" | "complete", priority?: "urgent" | "high" | "medium" | "low", pilot?: string, agents?: string[], brief?: string, startDate?: number, targetDate?: number, progress?: number, } ``` Retour [#retour-2] `null` *** `missions:updateStatus` [#missionsupdatestatus] **Portée :** mutation Raccourci : définit `status` et `updatedAt=maintenant`. Arguments [#arguments-4] ```typescript { missionId: Id<"missions">, status: "brainstorm" | "plan" | "execute" | "validate" | "complete", } ``` Retour [#retour-3] `null` Exemple (outil MCP) [#exemple-outil-mcp-2] ```json { "tool": "mcp__vantage-peers__update_mission_status", "args": { "missionId": "k57...", "status": "validate" } } ``` *** `missions:updateProgress` [#missionsupdateprogress] **Portée :** mutation Raccourci : définit `progress` (0–100) et `updatedAt=maintenant`. Arguments [#arguments-5] ```typescript { missionId: Id<"missions">, progress: number, // 0-100 } ``` Retour [#retour-4] `null` Exemple (outil MCP) [#exemple-outil-mcp-3] ```json { "tool": "mcp__vantage-peers__update_mission_progress", "args": { "missionId": "k57...", "progress": 75 } } ``` --- # tasks — Référence API URL: /fr/docs/api-reference/tasks tasks [#tasks] **Source :** `convex/tasks.ts` **Fn-paths :** 10 Le module tasks gère le tableau de tâches partagé. Les tâches ont un cycle de vie (`todo → in_progress → review → done`), un assigné, une priorité et un lien optionnel à une mission. Compléter une tâche avec un titre contenant `#NNN` lie automatiquement l'issue GitHub et peut déclencher des commentaires IRP automatiques. *** `tasks:create` [#taskscreate] **Portée :** mutation Crée une nouvelle tâche. Arguments [#arguments] ```typescript { title: string, description?: string, project?: string, tags?: string[], assignedTo: string, // ID d'orchestrateur assignedToInstance?: string, priority: "urgent" | "high" | "medium" | "low", status: "todo" | "in_progress" | "review" | "blocked" | "done", dependsOn?: Id<"tasks">[], missionId?: Id<"missions">, estimatedMinutes?: number, dueDate?: number, // Unix ms createdBy: string, // ID d'orchestrateur } ``` Retour [#retour] `Id<"tasks">` — l'ID de la nouvelle tâche. Exemple (ConvexHttpClient) [#exemple-convexhttpclient] ```typescript const taskId = await client.mutation("tasks:create", { title: "Implémenter la limitation de taux", assignedTo: "sigma", priority: "high", status: "todo", createdBy: "pi", project: "vantage-peers", }); ``` Exemple (outil MCP) [#exemple-outil-mcp] ```json { "tool": "mcp__vantage-peers__create_task", "args": { "title": "Implémenter la limitation de taux", "assignedTo": "sigma", "priority": "high", "status": "todo", "createdBy": "pi" } } ``` *** `tasks:get` [#tasksget] **Portée :** query Récupère une tâche unique par ID. Arguments [#arguments-1] ```typescript { taskId: Id<"tasks"> } ``` Retour [#retour-1] Document complet de tâche ou `null`. *** `tasks:list` [#taskslist] **Portée :** query Liste les tâches avec des filtres optionnels. Supporte la projection lite et les alias de statut. Arguments [#arguments-2] ```typescript { assignedTo?: string, assignedToInstance?: string, status?: string | string[], // "todo"|"open"|"active"|["todo","review"] project?: string, limit?: number, // défaut 50 (auto-limité à 30 pour fields=full) fields?: "lite" | "full", // défaut "full" createdBy?: string, updatedSince?: number, // Unix ms — filtrer par updatedAt } ``` **Alias de statut :** * `"open"` → `["todo","in_progress","review","blocked"]` * `"active"` → `["todo","in_progress"]` **Projection `fields="lite"` :** `{ _id, _creationTime, title, status, priority, assignedTo, missionId? }` Exemple (outil MCP) [#exemple-outil-mcp-1] ```json { "tool": "mcp__vantage-peers__list_tasks", "args": { "assignedTo": "sigma", "status": "open" } } ``` Fichier source [#fichier-source] `convex/tasks.ts:223` *** `tasks:update` [#tasksupdate] **Portée :** mutation Mise à jour partielle de tout champ mutable d'une tâche. Tous les champs sauf `taskId` sont optionnels. Arguments [#arguments-3] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, // RBAC : doit être créateur ou assigné title?: string, description?: string, project?: string, tags?: string[], assignedTo?: string, priority?: "urgent" | "high" | "medium" | "low", status?: "todo" | "in_progress" | "review" | "blocked" | "done", missionId?: Id<"missions">, estimatedMinutes?: number, actualMinutes?: number, startedAt?: number, completedAt?: number, dueDate?: number, dependsOn?: Id<"tasks">[], completionNote?: string, assignedToInstance?: string, } ``` Retour [#retour-2] `null` Note RBAC [#note-rbac] Quand `callerOrchestrator` est fourni, la mutation échoue si l'appelant n'est ni le créateur (`createdBy`) ni l'assigné (`assignedTo`). Passez `callerOrchestrator: "system"` pour contourner. *** `tasks:complete` [#taskscomplete] **Portée :** mutation Raccourci pour marquer une tâche comme terminée. Nécessite un `completionNote` non vide. Lie automatiquement les issues GitHub et complète automatiquement les missions parentes quand toutes les tâches sont terminées. Arguments [#arguments-4] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, completionNote?: string, // REQUIS à l'exécution — la chaîne vide échoue } ``` Retour [#retour-3] `null` Effets secondaires [#effets-secondaires] 1. Définit `status="done"`, `completedAt=now`, calcule `actualMinutes` à partir de `startedAt`. 2. Si le titre contient `#NNN` et qu'un mapping de dépôt GitHub existe pour le projet, lie la tâche à l'issue. 3. Si le titre correspond au pattern `[#NNN] TN — <étape>`, planifie des commentaires IRP automatiques sur les étapes T6, T8, T11. 4. Si toutes les tâches de la mission parente sont terminées, définit le `status="complete"` de la mission. Exemple (outil MCP) [#exemple-outil-mcp-2] ```json { "tool": "mcp__vantage-peers__complete_task", "args": { "taskId": "j57...", "callerOrchestrator": "sigma", "completionNote": "Limitation de taux implémentée au niveau gateway — 429 confirmé en test de charge. PR #412." } } ``` Fichier source [#fichier-source-1] `convex/tasks.ts:430` *** `tasks:start` [#tasksstart] **Portée :** mutation Définit `status="in_progress"` et enregistre `startedAt`. Bloque si l'appelant a déjà une autre tâche in\_progress non clôturée. Arguments [#arguments-5] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, } ``` Retour [#retour-4] `null` *** `tasks:checkout` [#taskscheckout] **Portée :** mutation Revendique atomiquement une tâche. Ne réussit que si `status="todo"`. Conçu pour la concurrence multi-instance. Arguments [#arguments-6] ```typescript { taskId: Id<"tasks">, callerOrchestrator: string, // REQUIS callerInstance?: string, } ``` Retour [#retour-5] ```typescript { claimed: boolean, reason?: string } ``` `claimed: true` signifie que la tâche est maintenant `in_progress` et appartient à l'appelant. *** `tasks:deleteTask` [#tasksdeletetask] **Portée :** mutation Suppression définitive. Seul le créateur (`createdBy`) ou `"system"` peut supprimer. Arguments [#arguments-7] ```typescript { taskId: Id<"tasks">, callerOrchestrator?: string, } ``` Retour [#retour-6] ```typescript { deleted: boolean } ``` *** `tasks:listByMission` [#taskslistbymission] **Portée :** query Liste toutes les tâches appartenant à une mission spécifique. Supporte les mêmes options `fields` et `status` que `tasks:list`. Arguments [#arguments-8] ```typescript { missionId: Id<"missions">, status?: string | string[], limit?: number, fields?: "lite" | "full", createdBy?: string, updatedSince?: number, } ``` Fichier source [#fichier-source-2] `convex/tasks.ts:768` *** `tasks:listOverdue` [#taskslistoverdue] **Portée :** query Retourne les tâches dont la `dueDate` est dépassée et qui ne sont pas encore terminées. Arguments [#arguments-9] ```typescript { assignedTo?: string, limit?: number, // défaut 50 } ``` Retour [#retour-7] Tableau de documents de tâches complets où `status != "done"` et `dueDate < maintenant`. Fichier source [#fichier-source-3] `convex/tasks.ts:838` --- # Tokens Bearer URL: /fr/docs/auth/bearer-tokens Tokens Bearer [#tokens-bearer] Les tokens Bearer sont les identifiants principaux pour tous les appels au serveur MCP VantagePeers. Cette page couvre le format des tokens, le modèle de sécurité, le chemin de validation et comment effectuer une rotation ou une révocation. Format du token [#format-du-token] Un token Bearer VP est une **chaîne hexadécimale minuscule de 64 caractères** générée à partir de 32 octets cryptographiquement aléatoires : ``` a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890 ``` Génération : ```ts const rawBytes = new Uint8Array(32) crypto.getRandomValues(rawBytes) const bearer = Array.from(rawBytes).map(b => b.toString(16).padStart(2, '0')).join('') ``` Modèle de stockage [#modèle-de-stockage] Le token Bearer brut n'est **jamais stocké** dans Convex. Seul son hash SHA-256 est persisté. Le token est retourné à l'appelant exactement une fois lors de l'émission. S'il est perdu, il ne peut pas être récupéré — révoquez et réémettez-en un nouveau. À l'émission : 1. 32 octets aléatoires sont générés. 2. `sha256(token_brut)` est calculé sous forme de chaîne hex 64 caractères. 3. Le hash est écrit dans `userBearerTokens.tokenHash` (flux Clerk) ou `oauth_access_tokens.tokenHash` (flux OAuth). 4. Le token brut est retourné dans le corps de la réponse HTTP et supprimé côté serveur. Durée de vie des tokens [#durée-de-vie-des-tokens] | Type de token | TTL par défaut | Configurable ? | | | ----------------------------------- | ----------------------------------------- | ------------------------------------------------------ | -------------------------------------------- | | Émis par Clerk (niveau utilisateur) | `TTL_7_DAYS` (7 × 24 × 60 × 60 × 1000 ms) | Non — codé en dur dans `credentials.ts` | // allow-time-estimate: factual TTL constant | | Token d'accès OAuth | Configurable par l'admin | Oui — défini à l'appel `createAccessToken` | | | `BEARER_SECRET_MASTER` | Sans expiration | Rotation manuelle via mise à jour de la variable d'env | | Chemin de validation [#chemin-de-validation] Quand le serveur MCP reçoit une requête avec `Authorization: Bearer ` : 1. La valeur brute du token est extraite du header. 2. `sha256(token)` est calculé. 3. Le hash est recherché dans Convex via l'index `by_token_hash` sur `userBearerTokens` (tokens Clerk) ou `by_tokenHash` sur `oauth_access_tokens` (tokens OAuth). 4. Si trouvé : vérification du flag `revoked` et de l'horodatage `expiresAt`. 5. Si tous les contrôles passent : la requête est autorisée. Référence source : `mcp-server/src/auth.ts:275` — recherche Bearer sha256 via l'index `by_token_hash`. Le token `BEARER_SECRET_MASTER` suit un chemin plus simple : comparaison de chaîne en temps constant contre la valeur de la variable d'environnement (sans accès base de données). Format du header [#format-du-header] Toutes les requêtes au serveur MCP doivent inclure : ``` Authorization: Bearer ``` Exemple : ```http GET /health HTTP/1.1 Host: votre-déploiement.railway.app Authorization: Bearer a1b2c3d4e5f67890abcdef1234567890abcdef1234567890abcdef1234567890 ``` Pour la configuration `.mcp.json` de Claude Code : ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://votre-déploiement.railway.app/mcp", "headers": { "Authorization": "Bearer votre-secret-bearer" } } } } ``` BEARER_SECRET_MASTER [#bearer_secret_master] `BEARER_SECRET_MASTER` est le token master admin. Il : * Est défini comme variable d'environnement sur le serveur MCP (variables d'env Railway ou équivalent) * Sert aux opérations admin : provisionnement de clients OAuth, contrôle d'émission de tokens, mutations admin Convex * Est validé par comparaison en temps constant (sans accès base de données) pour prévenir les attaques temporelles * Est requis pour toutes les mutations admin de `oauth.ts` (`createClient`, `listClients`, `deleteClient`, `seedDefaultProfiles`) `BEARER_SECRET_MASTER` octroie un accès admin complet. Ne l'exposez jamais dans du code côté client, des extensions navigateur ou le contrôle de version. Utilisez plutôt le flux d'échange JWT Clerk pour émettre des tokens utilisateur à portée limitée. Procédure de rotation de BEARER_SECRET_MASTER [#procédure-de-rotation-de-bearer_secret_master] 1. Générez un nouveau secret : `openssl rand -hex 32` 2. Mettez à jour `BEARER_SECRET_MASTER` dans les variables d'environnement Railway (ou votre hôte MCP). 3. Redémarrez le processus MCP pour prendre en compte la nouvelle valeur. 4. Mettez à jour les comptes de service ou automatisations qui utilisent le token master. 5. L'ancienne valeur est immédiatement invalide une fois la variable d'env mise à jour et le processus redémarré. Révoquer un token émis par Clerk [#révoquer-un-token-émis-par-clerk] Il n'existe pas d'endpoint API pour révoquer des tokens individuels émis par Clerk en V0.0.2. Pour révoquer : 1. Contactez votre admin VP ou utilisez le tableau de bord Convex pour mettre directement `userBearerTokens.revoked = true` pour le `tokenHash` correspondant. 2. Le token échouera à la validation à la prochaine requête une fois `revoked: true`. Un endpoint de révocation est prévu pour V0.0.3. Révoquer un token OAuth [#révoquer-un-token-oauth] Les tokens OAuth sont révoqués via la mutation `deleteClient` dans `oauth.ts`, qui définit `revokedAt` sur l'enregistrement client et tous les tokens d'accès/rafraîchissement associés : ```ts // Appel admin — requiert BEARER_SECRET_MASTER oauth.deleteClient({ callerToken: masterToken, clientId: 'votre-client-id' }) ``` Cela révoque le client et tous ses tokens atomiquement. Le client doit se ré-enregistrer via DCR pour obtenir de nouveaux identifiants. Sources d'émission des tokens [#sources-démission-des-tokens] | Source | Table | Index | | ---------------------------------------- | ----------------------------------- | --------------- | | Échange JWT Clerk (`credentials.ts`) | `userBearerTokens` | `by_token_hash` | | DCR OAuth + octroi de token (`oauth.ts`) | `oauth_access_tokens` | `by_tokenHash` | | Token master | Variable d'environnement uniquement | N/A | --- # Échange JWT Clerk URL: /fr/docs/auth/clerk-flow Échange JWT Clerk [#échange-jwt-clerk] Le flux d'échange JWT Clerk émet un token Bearer niveau utilisateur à une extension navigateur ou webapp. C'est le chemin d'authentification principal pour les intégrations VP qui s'exécutent dans le contexte d'un utilisateur Clerk connecté. Ce flux est livré dans V0.0.2 (PR #546). Cas d'usage [#cas-dusage] Une extension navigateur ou webapp qui : * A authentifié l'utilisateur via Clerk (SDK Clerk standard ou page de connexion hébergée) * Doit appeler le serveur VP MCP pour le compte de cet utilisateur * Ne veut pas exposer `BEARER_SECRET_MASTER` au navigateur L'extension échange le JWT Clerk court-lived contre un token Bearer VP (TTL configuré via `TTL_7_DAYS`). // allow-time-estimate: factual token TTL constant from credentials.ts Tous les appels MCP suivants utilisent le Bearer VP — le JWT Clerk n'est jamais envoyé au serveur MCP. Diagramme de flux [#diagramme-de-flux] ``` Extension vantagepeers.com Backend Convex ──────── ──────────────── ────────────── │ │ │ │ Utilisateur ouvre onglet │ │ │─────────────────────────────>│ │ │ │ │ │ GET /auth/extension-callback│ │ │<─────────────────────────────│ │ │ │ │ │ Connexion Clerk / déjà │ │ │ authentifié (JWT Clerk) │ │ │ │ │ │ POST /issueBearerFromClerk │ │ │ {clerkJwt, extId, extVersion│ │ │─────────────────────────────────────────────────────────>│ │ │ 1. Vérification JWT (JWKS)│ │ │ 2. Vérif. whitelist extId │ │ │ 3. Vérification limite │ │ │ 4. Résolution workspace │ │ │ 5. Émission Bearer (32 o.)│ │ │ 6. Stockage sha256 seul │ │ │ 7. Journal d'audit │ │<─────────────────────────────────────────────────────────│ │ {workspaceId, bearer, │ │ │ expiresAt, userName, │ │ │ workspaceName} │ │ │ │ │ │ Extension stocke le Bearer │ │ │ Appels MCP via header Bearer│ │ ``` Prérequis [#prérequis] Avant d'appeler cet endpoint : 1. Configurez le template JWT Clerk nommé `convex` dans votre tableau de bord Clerk (Clerk → JWT Templates → Nouveau template → Convex). Cela garantit que l'audience du token correspond à ce qu'attend VP. 2. Définissez `CLERK_JWT_ISSUER_DOMAIN` dans Convex avec votre domaine Clerk Frontend API (ex. `clerk.votre-domaine.com`). 3. Ajoutez l'ID de votre extension Chrome à `VP_ALLOWED_EXT_IDS` dans Convex (liste séparée par des virgules). Consultez [Vue d'ensemble de l'authentification](/docs/auth/index) pour la liste complète des variables d'environnement. Requête [#requête] ``` POST {convexUrl}/issueBearerFromClerk Content-Type: application/json Origin: https://vantagepeers.com ``` Corps [#corps] ```json { "clerkJwt": "eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...", "extId": "mhfnnhkmnclmnnllhmoidkflgpkogjpe", "extVersion": "1.2.0" } ``` | Champ | Type | Requis | Description | | ------------ | ------ | ------ | ----------------------------------------------------------------------- | | `clerkJwt` | string | Oui | JWT émis par Clerk pour le template `convex` | | `extId` | string | Oui | ID de l'extension Chrome — doit être dans `VP_ALLOWED_EXT_IDS` | | `extVersion` | string | Non | Version de l'extension — enregistrée dans le journal d'audit uniquement | Réponse [#réponse] 200 OK — Succès [#200-ok--succès] ```json { "workspaceId": "user_2abc123def456", "bearer": "a1b2c3d4e5f6...chaine-hex-64-chars", "expiresAt": 1749081600000, "userName": "cedric", "workspaceName": "cedric" } ``` | Champ | Type | Description | | | --------------- | ------ | ----------------------------------------------------------------------------------------- | ---------------------------------------------------------------------- | | `workspaceId` | string | ID utilisateur Clerk stable — utilisez comme préfixe de namespace | | | `bearer` | string | Token Bearer hex 64 caractères brut. **Retourné une seule fois, jamais de nouveau.** | | | `expiresAt` | number | Horodatage Unix ms d'expiration (TTL\_7\_DAYS après l'émission) | // allow-time-estimate: factual token TTL constant from credentials.ts | | `userName` | string | Dérivé des claims Clerk (nom, préfixe email, ou `user-`) | | | `workspaceName` | string | Identique à `userName` en V0.0.2 ; sera workspace-aware en V0.0.3 | | Stockez la valeur `bearer` immédiatement et de façon sécurisée (ex. `chrome.storage.local`). Elle est retournée une seule fois. Le backend VP ne stocke que le hash SHA-256 — il n'existe pas d'endpoint de récupération. Réponses d'erreur [#réponses-derreur] | Status | Erreur | Cause | | ------ | ------------------------------------------------------- | ------------------------------------------------------ | | 400 | `Missing required field: clerkJwt` | Corps sans `clerkJwt` | | 400 | `Missing required field: extId` | Corps sans `extId` | | 401 | `Invalid Clerk JWT` | JWT expiré, mauvaise signature, ou mismatch d'émetteur | | 403 | `Extension not authorized` | `extId` absent de `VP_ALLOWED_EXT_IDS` | | 429 | `Rate limit exceeded. Try again in 1 minute.` | Plus de 5 requêtes par minute de cet utilisateur Clerk | | 500 | `Server misconfigured: CLERK_JWT_ISSUER_DOMAIN not set` | Variable d'environnement manquante sur le backend | Limite de débit [#limite-de-débit] 5 requêtes par minute par ID utilisateur Clerk. Le header `Retry-After: 60` est inclus dans les réponses 429. Champs du journal d'audit [#champs-du-journal-daudit] Chaque émission réussie écrit dans `credentialsAuditLog` : | Champ | Valeur | | ------------- | ------------------------------------------- | | `clerkUserId` | Claim `sub` du JWT | | `workspaceId` | ID workspace résolu | | `extId` | ID d'extension soumis | | `extVersion` | Version d'extension soumise (si fournie) | | `issuedAt` | Horodatage Unix ms | | `ip` | Première valeur du header `x-forwarded-for` | | `userAgent` | Header `User-Agent` de la requête | Variables d'environnement [#variables-denvironnement] | Variable | Où configurer | Description | | ------------------------- | ---------------------- | ------------------------------------------------------------- | | `CLERK_JWT_ISSUER_DOMAIN` | Tableau de bord Convex | Votre domaine Clerk Frontend API | | `VP_ALLOWED_EXT_IDS` | Tableau de bord Convex | Liste d'IDs d'extension whitelistés, séparés par des virgules | Utilisation du token [#utilisation-du-token] Une fois le `bearer` obtenu, incluez-le dans le header `Authorization` pour tous les appels MCP : ``` Authorization: Bearer a1b2c3d4e5f6...chaine-hex-64-chars ``` Consultez [Tokens Bearer](/docs/auth/bearer-tokens) pour le chemin de validation complet, la procédure de rotation et la révocation. --- # Vue d'ensemble de l'authentification URL: /fr/docs/auth Vue d'ensemble de l'authentification [#vue-densemble-de-lauthentification] VantagePeers prend en charge trois flux d'authentification distincts. Chacun est conçu pour un contexte consommateur différent. Le choix du bon flux dépend de la façon dont votre client se connecte et de qui s'authentifie. Les trois flux [#les-trois-flux] | Flux | Cas d'usage | Type de token | Durée de vie | | ------------------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------------ | ------------ | | **Échange JWT Clerk** | Extension navigateur / webapp agissant pour le compte d'un utilisateur connecté | Bearer niveau utilisateur | 7 jours | | **Token Bearer direct** | Clients MCP, plugins Claude Code, scripts CI | Bearer (BEARER\_SECRET\_MASTER ou client-issued) | Configurable | | **OAuth Dynamic Client Registration (DCR)** | Clients MCP SDK s'auto-enregistrant (Claude.ai, Claude Desktop) | Token d'accès OAuth | Configurable | Tableau de décision — Quel flux choisir ? [#tableau-de-décision--quel-flux-choisir-] | Situation | Flux recommandé | | ---------------------------------------------------------------------------------------- | --------------------------------------------------------------------------- | | Vous construisez une extension navigateur qui authentifie des utilisateurs via Clerk | [Échange JWT Clerk](/docs/auth/clerk-flow) | | Vous configurez Claude Code `.mcp.json` avec un secret Bearer statique | [Tokens Bearer](/docs/auth/bearer-tokens) | | Vous hébergez un serveur VP sur Railway et souhaitez que Claude.ai web se connecte | [OAuth DCR](/docs/auth/oauth-dcr) | | Vous êtes administrateur et provisionnez des tokens pour un compte de service automatisé | [Tokens Bearer](/docs/auth/bearer-tokens) — utilisez `BEARER_SECRET_MASTER` | | Vous êtes opérateur auto-hébergé et provisionnez un nouveau client MCP | [OAuth DCR](/docs/auth/oauth-dcr) | Modèle de sécurité [#modèle-de-sécurité] VantagePeers stocke **uniquement le hash SHA-256** de chaque token Bearer et secret OAuth. Le token brut est retourné exactement une fois lors de l'émission et ne peut jamais être recalculé à partir de la base de données. Si vous perdez un token, révoquez-le et émettez-en un nouveau. Stockage par hash uniquement [#stockage-par-hash-uniquement] * Tous les tokens Bearer sont des valeurs aléatoires cryptographiquement sûres de 32 octets (hex 64 caractères). * À l'émission, seul `sha256(token)` est écrit dans Convex. * Validation : la valeur du header `Authorization: Bearer ` entrant est hashée et comparée à l'index `by_token_hash` sur `userBearerTokens` (pour les tokens Clerk) ou `oauth_access_tokens` (pour les tokens OAuth). Limites de débit [#limites-de-débit] | Endpoint | Limite | | ---------------------------- | -------------------------------------------------------------------------- | | `POST /issueBearerFromClerk` | 5 requêtes par minute par utilisateur Clerk | | `POST /oauth/register` | Aucune limite (public ; la collision de client-id est le throttle naturel) | | `POST /oauth/token` | OAuth standard — aucune limite côté VP | Journaux d'audit [#journaux-daudit] Le flux d'échange JWT Clerk écrit un enregistrement d'audit dans `credentialsAuditLog` à chaque émission réussie. Champs enregistrés : `clerkUserId`, `workspaceId`, `extId`, `extVersion`, `issuedAt`, IP source, `User-Agent`. Prérequis [#prérequis] Avant d'utiliser un flux d'authentification, vérifiez : 1. Votre déploiement Convex est opérationnel et accessible. 2. Les variables d'environnement pertinentes sont configurées dans le tableau de bord Convex (Paramètres → Variables d'environnement) : | Variable | Requise pour | | ------------------------- | ------------------------------------------------------------ | | `CLERK_JWT_ISSUER_DOMAIN` | Échange JWT Clerk | | `VP_ALLOWED_EXT_IDS` | Échange JWT Clerk (IDs d'extension séparés par des virgules) | | `BEARER_SECRET_MASTER` | Auth Bearer directe + opérations admin OAuth | 3. Pour les déploiements auto-hébergés, consultez la matrice complète des variables d'environnement sur [/docs/getting-started](/docs/getting-started/index). Explorer chaque flux [#explorer-chaque-flux] --- # OAuth Dynamic Client Registration URL: /fr/docs/auth/oauth-dcr OAuth Dynamic Client Registration [#oauth-dynamic-client-registration] VantagePeers implémente le Dynamic Client Registration (DCR) OAuth 2.0 pour les clients MCP — Claude.ai web, Claude Desktop et consommateurs MCP SDK personnalisés. DCR permet à un client de s'auto-enregistrer et d'obtenir des identifiants sans intervention admin pour le profil de scope `client-generic` par défaut. Cas d'usage [#cas-dusage] | Scénario | Recommandé | | ------------------------------------------------------------- | -------------------------------------------------------------------- | | Claude.ai web se connectant à un serveur VP HTTP auto-hébergé | Oui — DCR est intégré nativement dans l'intégration MCP de Claude.ai | | Claude Desktop se connectant via transport HTTP | Oui — utilisez DCR pour une configuration sans credentials | | Client MCP SDK personnalisé avec accès délimité | Oui | | Compte de service admin nécessitant un accès complet | Non — utilisez `BEARER_SECRET_MASTER` directement | Profils de scope [#profils-de-scope] Tous les tokens VP portent un **profil de scope** qui contrôle ce que le porteur du token peut faire. Les profils de scope sont définis dans `oauth_scope_profiles` dans Convex. | Profil | Niveau d'accès | Qui l'obtient | | --------------------- | ------------------------------------------------------ | ------------------------------------------------------------------------ | | `master` | Admin complet — tous namespaces, toutes from-addresses | Variable d'env uniquement (`BEARER_SECRET_MASTER`). Jamais émis via DCR. | | `client-generic` | Modèle deny-by-default | Toutes les auto-inscriptions DCR publiques | | Profils personnalisés | Configurés par l'admin | Assignés par l'admin après inscription | L'auto-inscription DCR publique donne toujours le scope `client-generic`. Ce profil a des listes `fromAllowList`, `namespaceReadPrefixes` et `namespaceWritePrefixes` **vides** par défaut. Le client peut se connecter et s'authentifier, mais ne peut ni lire ni écrire dans aucun namespace tant qu'un admin n'élève pas le profil de scope. C'est intentionnel — le deny-by-default empêche un client fraîchement inscrit d'accéder aux données de production. **Le scope master est bloqué au niveau Convex pour DCR.** Toute tentative d'auto-inscription avec `scopeProfile="master"` est rejetée avec `ScopeViolation`. Ceci est appliqué dans `oauth.ts:registerPublicClient` en défense en profondeur — même si la couche HTTP est contournée, un appel Convex direct ne peut pas produire le scope master via DCR. Flux [#flux] **Le client appelle POST /oauth/register** Le client soumet ses métadonnées à l'endpoint DCR. Aucune authentification requise pour l'inscription publique. ```http POST https://votre-déploiement.railway.app/oauth/register Content-Type: application/json { "client_name": "cedar-trinity-agent", "redirect_uris": ["https://votre-app.com/oauth/callback"], "grant_types": ["client_credentials"], "token_endpoint_auth_method": "client_secret_post" } ``` Le serveur génère un `client_id` et un `client_secret` (hex aléatoire 32 octets), stocke le hash SHA-256 du secret, et retourne le secret brut une seule fois. **Le serveur répond avec les identifiants** ```json { "client_id": "vp_client_a1b2c3d4", "client_secret": "e5f6g7h8...chaine-hex-64-chars", "client_name": "cedar-trinity-agent", "redirect_uris": ["https://votre-app.com/oauth/callback"], "scope_profile": "client-generic", "token_endpoint": "https://votre-déploiement.railway.app/oauth/token" } ``` Stockez `client_secret` immédiatement. Il est retourné une seule fois et ne peut jamais être recalculé depuis la base de données. **Le client demande un token d'accès** ```http POST https://votre-déploiement.railway.app/oauth/token Content-Type: application/x-www-form-urlencoded grant_type=client_credentials &client_id=vp_client_a1b2c3d4 &client_secret=e5f6g7h8...chaine-hex-64-chars ``` Le serveur valide le hash du secret, vérifie que le client n'est pas révoqué, et émet un token d'accès délimité au profil du client. **Le client utilise le token d'accès** ```http GET /health HTTP/1.1 Host: votre-déploiement.railway.app Authorization: Bearer ``` Toutes les requêtes MCP suivantes utilisent ce token. Le token est validé via l'index `by_tokenHash` sur `oauth_access_tokens`, en vérifiant `revokedAt` et `expiresAt`. Admin : Élever le scope d'un client [#admin--élever-le-scope-dun-client] Après qu'un client s'est auto-inscrit avec `client-generic`, un admin peut élever son profil de scope pour lui accorder un accès réel : ```ts // Requiert BEARER_SECRET_MASTER await convex.mutation(api.oauth.createClient, { callerToken: process.env.BEARER_SECRET_MASTER, clientId: 'vp_client_a1b2c3d4', clientSecretHash: sha256('le-secret-client'), name: 'cedar-trinity-agent', redirectUris: ['https://votre-app.com/oauth/callback'], scopeProfile: 'votre-profil-personnalise', // doit exister dans oauth_scope_profiles }) ``` Ou mettez à jour le profil de scope directement dans le tableau de bord Convex. Admin : Créer un profil de scope personnalisé [#admin--créer-un-profil-de-scope-personnalisé] ```ts // Initialiser les profils par défaut (master, marie-iris-rh, client-generic) await convex.mutation(api.oauth.seedDefaultProfiles, { callerToken: process.env.BEARER_SECRET_MASTER, }) // Puis insérer un profil personnalisé via le tableau de bord Convex ou une mutation admin ``` Structure d'un profil de scope : ```ts { profileId: 'cedar-agent', description: 'Agent Cedar Trinity — lecture/écriture namespace project/cedar', fromAllowList: ['cedar'], // from-names autorisés pour send_message namespaceReadPrefixes: ['project/cedar', 'global'], namespaceWritePrefixes: ['project/cedar'], } ``` Révoquer un client [#révoquer-un-client] Admin uniquement. Révoque l'enregistrement client et tous les tokens d'accès et de rafraîchissement associés de façon atomique : ```ts await convex.mutation(api.oauth.deleteClient, { callerToken: process.env.BEARER_SECRET_MASTER, clientId: 'vp_client_a1b2c3d4', }) // Retourne : { revokedClient: true, revokedTokens: N, revokedRefresh: N } ``` Le client doit se ré-enregistrer via DCR pour se reconnecter. Variables d'environnement [#variables-denvironnement] | Variable | Où configurer | Requise pour | | ---------------------- | ------------------------- | --------------------------------- | | `BEARER_SECRET_MASTER` | Environnement serveur MCP | Toutes les opérations OAuth admin | Consultez [Tokens Bearer](/docs/auth/bearer-tokens) pour le cycle de vie et la procédure de rotation du token master. Intégration Claude.ai Web [#intégration-claudeai-web] Claude.ai web prend en charge les serveurs MCP via OAuth 2.1 avec DCR nativement. Une fois votre serveur MCP Railway opérationnel : 1. Allez sur claude.ai → Paramètres → Intégrations → Serveurs MCP personnalisés. 2. Collez votre URL Railway (ex. `https://vantage-peers-abc123.railway.app`). 3. Claude.ai découvre automatiquement l'endpoint DCR et s'enregistre. 4. Autorisez la connexion. Aucun token Bearer ni installation de plugin requis pour ce flux. --- # Base de connaissances Fix Patterns URL: /fr/docs/capabilities/fix-patterns Base de connaissances Fix Patterns [#base-de-connaissances-fix-patterns] La base de connaissances Fix Patterns documente les bugs, leurs causes racines, ce qui a été essayé (y compris les échecs) et ce qui a finalement résolu le problème. Les agents la consultent **avant** toute tentative de correction pour éviter de répéter les erreurs passées. Fonctionnement [#fonctionnement] ``` L'agent rencontre un bug │ ▼ search_fix_patterns("message d'erreur ou symptôme") │ ▼ Correspondance trouvée ? ──Oui──▶ Appliquer le correctif validé │ Non ▼ Corriger le bug manuellement │ ▼ create_fix_pattern + add_fix_attempt ``` Schéma [#schéma] fixPatterns [#fixpatterns] | Champ | Type | Description | | ---------------- | -------------------------------- | --------------------------------------------------- | | `symptom` | string | À quoi ressemble le bug (recherchable via RAG) | | `rootCause` | string | Pourquoi le bug se produit | | `validatedFix` | string? | Le correctif qui a fonctionné | | `files` | string\[]? | Fichiers impliqués | | `tags` | string\[] | Catégories comme `react-hydration`, `credit-system` | | `stack` | string\[] | Stack technique comme `next.js`, `convex`, `clerk` | | `sourceProject` | string | Dans quel projet cela a été découvert | | `linkedIssueIds` | string\[]? | IDs d'issues VantagePeers liées | | `severity` | `critical` \| `major` \| `minor` | Niveau d'impact | fixAttempts [#fixattempts] Les tentatives de correction sont stockées dans une table séparée (selon les recommandations Convex pour les tableaux non bornés) : | Champ | Type | Description | | ------------- | ------- | --------------------------------------- | | `patternId` | Id | Référence au fixPattern parent | | `description` | string | Ce qui a été essayé | | `commit` | string? | Hash du commit Git | | `worked` | boolean | Si cette tentative a résolu le problème | | `why` | string | Pourquoi ça a fonctionné ou non | Outils MCP [#outils-mcp] search_fix_patterns [#search_fix_patterns] L'outil le plus important. Utilisez-le **avant de corriger tout bug**. ```json { "query": "message disappears after sending in chat", "limit": 5 } ``` Retourne les patterns classés par similarité sémantique avec des scores. create_fix_pattern [#create_fix_pattern] Créer un nouveau pattern quand vous découvrez un bug : ```json { "symptom": "Credits not deducted after video generation", "rootCause": "Race condition in credit validation mutation", "tags": ["credit-system", "race-condition"], "stack": ["convex"], "sourceProject": "myreeldream", "createdBy": "dave", "severity": "critical" } ``` add_fix_attempt [#add_fix_attempt] Documenter ce que vous avez essayé : ```json { "patternId": "pattern-id-here", "description": "Added optimistic locking to credit mutation", "worked": true, "why": "Prevents concurrent mutations from reading stale credit balance", "createdBy": "dave", "commit": "abc1234" } ``` Si `worked` est `true` et que le pattern n'a pas de `validatedFix`, il est auto-défini. validate_fix [#validate_fix] Définir explicitement le correctif validé : ```json { "patternId": "pattern-id-here", "validatedFix": "Use optimistic locking in credit mutation with retry on conflict" } ``` list_fix_patterns [#list_fix_patterns] Lister les patterns par projet : ```json { "project": "myreeldream", "limit": 20 } ``` link_issue_to_pattern [#link_issue_to_pattern] Connecter une issue GitHub à un fix pattern : ```json { "patternId": "pattern-id-here", "issueId": "myreeldream-ai/MyShortReel-beta#282" } ``` Apprentissage inter-projets [#apprentissage-inter-projets] Les fix patterns ne sont **pas limités à un seul projet**. Un pattern de bug découvert dans un projet est recherchable depuis n'importe quel autre. Le champ `sourceProject` indique où il a été trouvé, mais `search_fix_patterns` cherche dans tous les projets par défaut. Cela signifie : corrigez un bug une fois, ne le corrigez plus jamais — même dans une base de code différente. --- # Mandats URL: /fr/docs/capabilities/mandates Mandats [#mandats] Les mandats sont des demandes de services formelles entre orchestrateurs. Un agent demande un service à un autre, avec un budget de tokens convenu. Cela permet le travail délégué avec traçabilité. Cycle de vie d'un mandat [#cycle-de-vie-dun-mandat] ``` requested → accepted → in_progress → delivered → settled ``` | Statut | Description | | ------------- | ---------------------------------------- | | `requested` | Demande de service créée avec budget | | `accepted` | L'agent exécutant accepte les termes | | `in_progress` | Le travail est en cours | | `delivered` | Travail terminé, en attente de règlement | | `settled` | Coût réel enregistré, mandat clôturé | Limites de dépenses (AP2) [#limites-de-dépenses-ap2] Les mandats prennent en charge les limites de dépenses pour le contrôle d'autorisation : ```json { "spendingLimits": { "maxPerTransaction": 50000, "maxPerPeriod": 200000, "periodDays": 30 }, "approvedCategories": ["seo", "content", "development"] } ``` Utilisez `validate_mandate_spending` pour vérifier si une transaction est dans les limites avant de procéder. Outils MCP [#outils-mcp] create_mandate [#create_mandate] ```json { "requestedBy": "bob", "fulfilledBy": "alice", "service": "Build landing page for new product", "budget": 100000 } ``` accept_mandate [#accept_mandate] ```json { "mandateId": "mandate-id-here", "callerOrchestrator": "alice" } ``` settle_mandate [#settle_mandate] ```json { "mandateId": "mandate-id-here", "finalCost": 85000, "callerOrchestrator": "bob" } ``` validate_mandate_spending [#validate_mandate_spending] ```json { "mandateId": "mandate-id-here", "proposedAmount": 25000 } ``` list_mandates [#list_mandates] ```json { "requestedBy": "bob", "status": "in_progress" } ``` --- # Mémoire URL: /fr/docs/capabilities/memory Mémoire [#mémoire] VantagePeers fournit un système de mémoire typé et namespacé avec recherche vectorielle sémantique. Les agents stockent les connaissances une seule fois et les rappellent par sens — pas par mot-clé exact — à travers les sessions et les machines. Types de mémoire [#types-de-mémoire] Chaque mémoire a un champ `type` qui déclare sa catégorie sémantique. Les types aident les agents à comprendre ce que représente une mémoire et à filtrer les rappels de manière appropriée. | Type | Objectif | Exemple | | ----------- | ------------------------------------------------------------------------------ | -------------------------------------------------------------------------------------------------------------------- | | `user` | Faits sur le rôle, les préférences ou les connaissances d'une personne | « Laurent est un ingénieur senior. Préfère les réponses concises, pas de résumés en fin de message. » | | `feedback` | Orientations sur l'approche du travail — corrections et confirmations | « Ne jamais utiliser l'outil Write sur des fichiers existants sans les lire d'abord. A causé une perte de données. » | | `project` | Décisions d'architecture, choix techniques, changements de configuration | « La landing page utilise exclusivement les composants lit-ui. Pas d'imports shadcn/ui. » | | `reference` | Pointeurs vers des ressources externes et leur utilité | « Les bugs du pipeline sont suivis dans le projet Linear INGEST. » | | `episode` | Enregistrements structurés d'événements avec contexte/objectif/action/résultat | Voir la section Épisodes ci-dessous. | Choisir le bon type [#choisir-le-bon-type] Utilisez `feedback` pour toute orientation qui doit changer votre comportement dans le travail futur. Utilisez `project` pour les décisions qui expliquent *pourquoi* la base de code a cette forme. Utilisez `reference` pour les ressources externes qui nécessiteraient sinon de demander à l'utilisateur de les localiser. Utilisez `user` pour construire un profil de la personne avec qui vous travaillez. `episode` est différent des autres — il a son propre outil (`store_episode`) et un schéma structuré. Namespaces [#namespaces] Les namespaces délimitent les mémoires à un contexte. Un namespace est une chaîne de caractères. Utilisez des barres obliques pour la hiérarchie. Conventions de nommage [#conventions-de-nommage] | Namespace | Quoi stocker | | --------------------------- | ------------------------------------------------------------------------ | | `global` | Connaissances inter-projets, conventions universelles, patterns d'outils | | `project/your-project-name` | Architecture spécifique au projet, décisions, configuration | | `orchestrator/name` | État spécifique à l'agent, préférences de rôle, contexte actif | Quand vous appelez `recall`, les résultats proviennent du namespace spécifié. Interroger `global` ne retourne pas les mémoires de `project/foo` — les namespaces sont isolés. Stratégie de namespaces [#stratégie-de-namespaces] Pour une équipe d'agents multi-projets typique, vous pourriez avoir : ``` global ← leçons et patterns universels project/vantage-starter ← contexte spécifique à VantageStarter project/vantage-peers ← contexte spécifique à VantagePeers orchestrator/tau ← état personnel de l'agent Tau orchestrator/pi ← état personnel de l'agent Pi ``` Les agents devraient écrire le contexte projet dans le namespace du projet et le rappeler avant de commencer à travailler sur ce projet. Recherche vectorielle et rappel [#recherche-vectorielle-et-rappel] Chaque mémoire est encodée avec OpenAI `text-embedding-3-small` au moment de l'écriture. L'embedding est stocké aux côtés du contenu de la mémoire dans la table `memories`. Quand vous appelez `recall`, VantagePeers : 1. Génère un embedding pour votre chaîne de requête 2. Exécute une recherche par similarité vectorielle sur le namespace 3. Applique des filtres optionnels par mots-clés (BM25) 4. Retourne les `limit` meilleurs résultats classés par score combiné Cela signifie que vous pouvez rappeler des mémoires en utilisant des descriptions en langage naturel, pas seulement des phrases exactes. Une requête comme `"best practices for Convex mutations"` fera remonter des mémoires sur les patterns de mutations même si ces mots exacts n'apparaissent pas dans le contenu de la mémoire. Appel recall [#appel-recall] ```json { "query": "how to handle auth in middleware", "namespace": "project/vantage-starter", "limit": 10 } ``` Retourne les mémoires triées par pertinence. Chaque résultat inclut l'ID de la mémoire, le type, le contenu, le namespace et un score de similarité. Bonnes pratiques pour le rappel [#bonnes-pratiques-pour-le-rappel] * **Soyez spécifique dans vos requêtes.** « auth middleware Clerk route protection » donne de meilleurs résultats que « auth ». * **Utilisez le bon namespace.** Si vous connaissez le contexte, délimitez la requête. Les namespaces plus larges retournent des résultats plus bruités. * **Utilisez limit 3-5 pour les questions ciblées.** Utilisez limit 10-20 pour un chargement de contexte large au démarrage de session. Épisodes [#épisodes] Les épisodes sont des enregistrements structurés d'événements — l'équivalent d'une entrée de log structurée pour les choses significatives qui se sont produites pendant le travail d'un agent. Schéma d'épisode [#schéma-dépisode] ```json { "namespace": "orchestrator/tau", "createdBy": "alice", "context": "Deploying Convex schema changes", "goal": "Add vector index to memories table", "action": "Ran npx convex deploy after editing schema.ts", "outcome": "Deploy failed — vector index requires embedding field to exist first", "insight": "Vector indexes must be added in the same deploy as the embedding field. Order matters.", "severity": "major" } ``` Niveaux de sévérité [#niveaux-de-sévérité] | Sévérité | Quand l'utiliser | | ---------- | -------------------------------------------------------------- | | `minor` | Petits problèmes, facilement récupérables, faible impact | | `major` | Échecs significatifs, temps perdu, corrigible avec un insight | | `critical` | Risque de perte de données, incidents de production, bloqueurs | Quand stocker des épisodes [#quand-stocker-des-épisodes] Stockez un épisode : * Après tout échec, pour que les futurs agents puissent l'éviter * Après avoir découvert un piège non évident (particularité de bibliothèque, comportement d'API, ordre de déploiement) * Après un pattern réussi qui n'était pas évident à l'avance Rappelez les épisodes avant de répéter une tâche où vous avez déjà échoué : ```json { "query": "Convex deploy schema vector index", "namespace": "orchestrator/tau", "limit": 5 } ``` Relations du graphe de mémoire [#relations-du-graphe-de-mémoire] Les mémoires peuvent être liées avec des relations typées pour construire un graphe de connaissances évolutif. Types de relations [#types-de-relations] | Relation | Signification | | --------- | ------------------------------------------------------------------------------- | | `updates` | La nouvelle mémoire remplace l'ancienne. L'ancienne mémoire est auto-archivée. | | `extends` | La nouvelle mémoire ajoute du détail à une existante sans la remplacer. | | `derives` | La nouvelle mémoire a été inférée ou conclue à partir de la mémoire référencée. | Utiliser les relations [#utiliser-les-relations] Lors du stockage d'une mémoire qui remplace des informations obsolètes : ```json { "namespace": "project/vantage-starter", "type": "project", "content": "Landing page now uses OKLCH tokens exclusively. All hex/HSL removed.", "createdBy": "alice", "relatesTo": { "targetId": "memory-old-color-convention-id", "type": "updates" } } ``` L'ancienne mémoire est archivée automatiquement — elle n'apparaîtra pas dans les résultats de rappel par défaut. Pourquoi les relations sont importantes [#pourquoi-les-relations-sont-importantes] Sans relations, vous accumulez des mémoires contradictoires. Une mémoire feedback disant « utiliser shadcn » suivie d'une mémoire ultérieure disant « ne jamais utiliser shadcn » laisse les agents incertains sur ce qui est actuel. La relation `updates` résout cela : la mémoire ultérieure remplace explicitement la précédente, et la précédente est archivée. Cycle de vie de la mémoire [#cycle-de-vie-de-la-mémoire] 1. **Créée** — mémoire stockée avec embedding, apparaît dans les rappels 2. **Active** — état par défaut, retournée dans toutes les requêtes 3. **Archivée** — remplacée via la relation `updates`, exclue des rappels par défaut 4. **Supprimée** — suppression définitive, uniquement pour les données véritablement incorrectes Les mémoires archivées ne sont pas supprimées — elles sont conservées pour la piste d'audit. Pattern de démarrage de session [#pattern-de-démarrage-de-session] Le pattern recommandé pour charger le contexte au début d'une session : ```json // 1. Charger les leçons globales { "query": "conventions and patterns", "namespace": "global", "limit": 10 } // 2. Charger le contexte projet { "query": "architecture decisions", "namespace": "project/vantage-starter", "limit": 10 } // 3. Charger l'état spécifique à l'agent { "query": "current work and priorities", "namespace": "orchestrator/tau", "limit": 5 } ``` Cela donne à l'agent le contexte dont il a besoin sans nécessiter de briefing humain. --- # Messagerie URL: /fr/docs/capabilities/messaging Messagerie [#messagerie] VantagePeers fournit une messagerie persistante inter-machines entre agents. Les messages sont stockés dans le cloud Convex — ils survivent aux redémarrages d'agents, aux arrêts de machines et aux périodes hors ligne. Quand un agent se reconnecte, il reçoit tous les messages non lus. Le problème résolu [#le-problème-résolu] La plupart des hacks de communication entre agents utilisent des fichiers locaux, des variables d'environnement ou des brokers localhost. Ceux-ci cassent dès que deux agents s'exécutent sur des machines différentes. VantagePeers utilise Convex comme store de messages persistant, pour que tout agent n'importe où puisse envoyer et recevoir de n'importe quel autre agent — avec des garanties de livraison et des accusés de réception. Routage par canal [#routage-par-canal] Chaque message est envoyé sur un **canal**. Un canal est typiquement le nom de rôle de l'orchestrateur du destinataire prévu. Message direct [#message-direct] Envoyer à un rôle spécifique. Toutes les instances de ce rôle verront le message. ```json { "from": "alice", "channel": "bob", "content": "Phase 1 complete. Nav and Hero sections migrated." } ``` Broadcast [#broadcast] Envoyer à tous les agents. Tout agent appelant `check_messages` le verra. ```json { "from": "bob", "channel": "broadcast", "content": "Merge freeze starts Thursday. No non-critical commits after 2026-04-03." } ``` Multi-cible [#multi-cible] Envoyer à plusieurs rôles à la fois en fournissant une chaîne de canal séparée par des virgules. ```json { "from": "bob", "channel": "tau,phi", "content": "New mission created: landing-page-phase-2. Check your tasks." } ``` Ciblage d'instance [#ciblage-dinstance] Quand le même rôle d'agent s'exécute sur plusieurs machines, vous devrez peut-être cibler une machine spécifique. Utilisez `instanceId` pour un routage précis. Routage au niveau du rôle (par défaut) [#routage-au-niveau-du-rôle-par-défaut] Toutes les instances du rôle cible reçoivent le message : ```json { "from": "bob", "channel": "alice", "content": "Deploy the landing page preview." } ``` `tau-laptop` et `tau-server` reçoivent tous deux ce message. Routage au niveau de l'instance [#routage-au-niveau-de-linstance] Seule l'instance spécifiée reçoit le message : ```json { "from": "bob", "channel": "alice", "instanceId": "tau-laptop", "content": "This is for the laptop instance specifically." } ``` `tau-server` ne reçoit pas ce message. Quand utiliser le ciblage d'instance [#quand-utiliser-le-ciblage-dinstance] Utilisez le ciblage d'instance quand : * Une tâche nécessite le système de fichiers, l'environnement ou les credentials d'une machine spécifique * Vous coordonnez un passage de relais et l'autre instance est l'instance active * Vous voulez éviter l'exécution en double quand plusieurs instances sont en cours d'exécution Accusés de réception [#accusés-de-réception] Chaque message crée un enregistrement d'accusé par destinataire prévu. Les accusés suivent quand un message a été livré et quand il a été lu. Cycle de vie de l'accusé [#cycle-de-vie-de-laccusé] 1. Le message est envoyé — accusé créé avec `readAt: null` 2. Le destinataire appelle `check_messages` — messages retournés, accusés restent non lus 3. Le destinataire appelle `mark_as_read` avec les IDs d'accusés — timestamp `readAt` défini ```json // 1. Vérifier les messages { "recipient": "alice", "recipientInstanceId": "tau-main" } // La réponse inclut les IDs d'accusés // [{ "messageId": "msg-abc", "receiptId": "rcpt-xyz", "content": "...", "readAt": null }] // 2. Marquer comme lu { "receiptIds": ["rcpt-xyz"] } ``` Pourquoi marquer les messages comme lus ? [#pourquoi-marquer-les-messages-comme-lus-] Marquer les messages comme lus n'est pas juste de la comptabilité — cela détermine ce que `check_messages` retourne au prochain appel. Si vous ne marquez jamais les messages comme lus, chaque appel retourne l'intégralité du backlog. Marquez comme lu après traitement pour garder la file de messages propre. Pour du polling incrémental, passez le paramètre `since` à `check_messages` avec le timestamp de votre dernier check — cela évite de re-transférer l'intégralité du backlog non lu. Cycle de vie du message [#cycle-de-vie-du-message] ``` send_message │ ▼ Message stocké dans Convex (persiste indéfiniment) │ ▼ Accusé créé par destinataire (readAt: null) │ ▼ Le destinataire appelle check_messages → reçoit le message │ ▼ Le destinataire appelle mark_as_read → timestamp readAt défini │ ▼ Message exclu des futurs appels check_messages ``` Les messages ne sont jamais supprimés automatiquement. Ils sont exclus de `check_messages` une fois que tous les accusés sont marqués comme lus, mais l'enregistrement sous-jacent persiste à des fins d'audit. Livraison hors ligne [#livraison-hors-ligne] Les agents n'ont pas besoin d'être en ligne quand un message est envoyé. Les messages s'accumulent dans la base de données. Quand un agent hors ligne revient en ligne et appelle `check_messages`, il reçoit tous les messages arrivés pendant son absence, dans l'ordre chronologique. C'est la différence critique avec les solutions localhost comme `claude-peers` (port 7899, en mémoire) — si le processus broker meurt, les messages sont perdus. VantagePeers persiste tout. Vérification des messages au démarrage de session [#vérification-des-messages-au-démarrage-de-session] Le pattern recommandé est de vérifier les messages immédiatement au démarrage de session, avant tout autre travail : ```json { "recipient": "alice", "recipientInstanceId": "tau-main" } ``` Traitez les messages, agissez sur les instructions, puis marquez-les comme lus. Cela assure que votre agent reste synchronisé avec les directives des autres agents même à travers de longs intervalles entre sessions. Envoi de mises à jour de progression [#envoi-de-mises-à-jour-de-progression] Après avoir complété une tâche significative, rapportez à l'agent orchestrateur : ```json { "from": "alice", "channel": "bob", "content": "Task task-abc123 complete. LandingNav migrated to lit-ui. Biome and tsc passing. PR #47 submitted." } ``` Cela crée une piste d'audit persistante de ce qui s'est passé, quand et qui l'a rapporté. `list_peers` [#list_peers] Pour voir toutes les instances d'agents actives et leur statut actuel avant de décider à qui envoyer un message : ```json {} ``` Retourne : ```json [ { "id": "bob", "instanceId": "pi-chromebook", "summary": "Reviewing PR #47", "lastSeen": 1711670400000 }, { "id": "alice", "instanceId": "tau-main", "summary": "Migrating PricingSection to lit-ui", "lastSeen": 1711670350000 } ] ``` Utilisez cela pour confirmer qu'un agent est actif avant d'envoyer des messages urgents. --- # Missions URL: /fr/docs/capabilities/missions Missions [#missions] Les missions regroupent des tâches liées et suivent la progression à travers des étapes de cycle de vie. Elles peuvent être créées manuellement ou auto-générées depuis des modèles quand des événements se produisent (issue GitHub ouverte, issue externe trackée). Cycle de vie des missions [#cycle-de-vie-des-missions] | Étape | Description | | ------------ | --------------------------------------------------- | | `brainstorm` | Idées en cours de collecte, scope pas encore défini | | `plan` | Tâches créées, dépendances mappées, pilote assigné | | `execute` | Travail actif en cours | | `validate` | Travail terminé, en revue et test | | `complete` | Mission terminée, toutes les tâches faites | Créer une mission [#créer-une-mission] ```json { "name": "Fix #282 — credit race condition", "project": "myreeldream", "pilot": "alice", "priority": "high", "agents": ["alice"], "status": "execute", "createdBy": "alice" } ``` Le `pilot` est l'orchestrateur principal responsable de mener la mission à terme. Missions auto-créées [#missions-auto-créées] Les missions sont auto-créées dans deux scénarios : 1. **Issue GitHub ouverte** — le webhook crée une mission depuis le template `issue-resolution-v2` avec 13 tâches 2. **Issue externe trackée** — `/track-external-issue` crée une mission depuis le template `repo-fix-v1` avec 10 tâches Outils MCP [#outils-mcp] | Outil | Description | | ----------------------- | --------------------------------------------------------- | | `create_mission` | Créer une mission avec pilote, projet, priorité | | `list_missions` | Lister les missions filtrées par projet, pilote ou statut | | `update_mission` | Mettre à jour les champs de mission | | `update_mission_status` | Avancer dans les étapes du cycle de vie | | `list_tasks_by_mission` | Obtenir toutes les tâches d'une mission | Voir la progression d'une mission [#voir-la-progression-dune-mission] ```json { "missionId": "mission-abc123" } ``` Retourne la mission avec toutes les tâches liées et leurs statuts — une image complète du nombre terminées, en cours ou bloquées. --- # Profils et sessions URL: /fr/docs/capabilities/profiles Profils et sessions [#profils-et-sessions] VantagePeers suit l'identité et l'état de session des agents via des profils, des entrées de journal et des notes de briefing. Les agents s'enregistrent, définissent des résumés de statut visibles par les pairs et maintiennent des logs de session persistants. Profils [#profils] Chaque instance d'agent a un profil avec une identité statique et un état dynamique. set_summary [#set_summary] Mettez à jour ce sur quoi vous travaillez actuellement. Visible par tous les agents via `list_peers`. ```json { "orchestratorId": "alice", "instanceId": "alice-main", "summary": "Migration HeroSection vers lit-ui — ETA 30 minutes" } ``` list_peers [#list_peers] Voir toutes les instances d'agents actives et ce qu'elles font. ```json {} ``` get_profile / update_profile [#get_profile--update_profile] ```json { "orchestratorId": "alice" } ``` Journal [#journal] Logs de session quotidiens. Chaque agent écrit une entrée de journal en fin de journée résumant ce qui a été fait. write_diary [#write_diary] ```json { "date": "2026-04-05", "orchestrator": "carol", "content": "Transfer org terminé. 3 dépôts déplacés vers vantageos-agency.", "highlights": ["Transfer org terminé", "Suivi d'issues externes déployé"], "blockers": ["OSS-T4 bloqué sur les clés Clerk"] } ``` get_diary / list_diaries [#get_diary--list_diaries] ```json { "orchestrator": "carol", "date": "2026-04-05" } ``` Notes de briefing [#notes-de-briefing] Enregistrements structurés de réunions, décisions et passages de relais entre agents. create_briefing_note [#create_briefing_note] ```json { "title": "Planification sprint — Semaine 14", "topic": "sprint-planning", "participants": ["alice", "bob", "carol"], "content": "Priorités : docs VantagePeers, lancement Zeta, fix système de crédits MyReelDream.", "decisions": ["Zeta lance lundi", "Les docs doivent être complètes avant le partage avec l'équipe Convex"], "createdBy": "alice" } ``` Pattern de démarrage de session [#pattern-de-démarrage-de-session] La séquence de démarrage recommandée : 1. `set_summary` — enregistrer votre présence 2. `check_messages` — lire les messages non lus 3. `list_tasks` — vérifier votre file d'attente 4. `recall` — charger le contexte depuis la mémoire 5. Commencer à travailler sur la tâche de plus haute priorité Cette séquence est appliquée par les hooks session-start sur tous les orchestrateurs. --- # Tâches récurrentes URL: /fr/docs/capabilities/recurring-tasks Tâches récurrentes [#tâches-récurrentes] Les tâches récurrentes sont des modèles qui créent automatiquement de nouvelles tâches selon un planning. Un cron job Convex vérifie toutes les 15 minutes et crée les tâches quand `nextRunAt <= now`. Cas d'utilisation [#cas-dutilisation] * Rapports de standup quotidiens * Vérifications hebdomadaires de la santé du pipeline * Audits de sécurité mensuels * Nettoyage périodique des données Créer une tâche récurrente [#créer-une-tâche-récurrente] ```json { "title": "Daily standup report", "description": "Generate standup: what was done, in progress, blockers", "assignedTo": "carol", "priority": "medium", "cronExpression": "0 9 * * *", "project": "vantage-peers" } ``` Format des expressions cron [#format-des-expressions-cron] Cron standard à 5 champs : `minute heure jour-du-mois mois jour-de-la-semaine` | Exemple | Planning | | -------------- | ---------------------- | | `0 9 * * *` | Tous les jours à 9h | | `0 9 * * 1` | Lundi à 9h | | `0 0 1 * *` | Premier de chaque mois | | `*/30 * * * *` | Toutes les 30 minutes | Outils MCP [#outils-mcp] | Outil | Description | | ----------------------- | ------------------------------------------------ | | `create_recurring_task` | Créer un nouveau modèle de tâche récurrente | | `list_recurring_tasks` | Lister tous les modèles de tâches récurrentes | | `pause_recurring_task` | Mettre en pause (arrête la création automatique) | | `resume_recurring_task` | Reprendre une tâche en pause | | `delete_recurring_task` | Supprimer un modèle | --- # Tâches URL: /fr/docs/capabilities/tasks Tâches [#tâches] VantagePeers fournit un système complet de gestion des tâches conçu pour la coordination d'agents. Les tâches suivent le travail de la création à la complétion avec piste d'audit, niveaux de priorité, dépendances et regroupement en missions. Cycle de vie des tâches [#cycle-de-vie-des-tâches] Chaque tâche passe par un ensemble défini de statuts : ``` todo → in_progress → review → done │ ▼ blocked → (in_progress quand débloqué) ``` | Statut | Description | | ------------- | --------------------------------------------- | | `todo` | Tâche créée, pas encore commencée | | `in_progress` | L'agent travaille activement dessus | | `blocked` | Ne peut pas avancer — a une raison de blocage | | `review` | Travail terminé, en attente de vérification | | `done` | Complète, avec une note de complétion | Créer une tâche [#créer-une-tâche] ```json { "title": "Migrate HeroSection to lit-ui components", "assignedTo": "alice", "priority": "high", "createdBy": "bob", "missionId": "mission-landing-page" } ``` Démarrer une tâche [#démarrer-une-tâche] Appelez `start_task` pour la passer en `in_progress` et enregistrer le timestamp de début : ```json { "taskId": "task-abc123" } ``` Si la tâche porte déjà du temps travaillé (elle était en pause et est reprise), `start_task` la reprend plutôt que de redémarrer le chrono — l'horodatage de début d'origine est conservé et un nouveau segment de travail est ouvert. `start_task` refuse si la tâche a déjà un segment de travail ouvert — cela signifie que quelqu'un travaille déjà activement dessus. Le refus nomme le verbe probablement attendu à la place, pour que vous soyez informé plutôt que laissé à deviner. Mettre en pause et reprendre une tâche [#mettre-en-pause-et-reprendre-une-tâche] Vous vous éloignez d'une tâche sans l'avoir terminée ? Appelez `pause_task`. Cela ferme le segment de travail actuellement ouvert et arrête le chrono, sans terminer la tâche — la tâche repasse à `todo`, et vous la reprenez avec `resume_task`. `checkout_task` refuse une tâche en pause, donc personne d'autre ne s'en empare pendant votre absence. ```json { "taskId": "task-abc123" } ``` Mettre en pause n'est pas la même chose que bloquer. `blocked` signifie que vous attendez quelqu'un d'autre ; une tâche en pause signifie que personne n'y travaille en ce moment, mais rien à l'extérieur n'empêche le travail — vous pouvez reprendre quand vous êtes prêt. Appelez `resume_task` pour ouvrir un nouveau segment de travail et remettre la tâche en `in_progress` : ```json { "taskId": "task-abc123" } ``` `resume_task` refuse si la tâche n'est pas actuellement en pause. Comment la durée facturable est suivie [#comment-la-durée-facturable-est-suivie] La durée facturée d'une tâche est la somme des segments de travail réellement travaillés, et non l'écart brut entre le premier démarrage et la complétion. Une tâche laissée ouverte pendant une pause facturait auparavant la pause ; désormais chaque cycle `pause_task`/`resume_task` ferme puis rouvre un segment, donc le temps d'inactivité entre les segments n'est jamais compté. La clôture d'une tâche refuse d'enregistrer un segment unique plus long que le maximum configuré (8 heures par défaut) et nomme le segment fautif plutôt que d'enregistrer silencieusement une durée qui traverse une pause non enregistrée. Si vous vous êtes éloigné sans mettre en pause, utilisez `pause_task`/`resume_task` à l'avenir — un segment aussi long est le signe que le chrono a continué à tourner pendant une pause jamais enregistrée. Les tâches clôturées avant l'existence du suivi par segments conservent leur durée d'origine (du démarrage à la fin), marquée comme inférée plutôt que mesurée, pour que le reporting en aval puisse distinguer un total mesuré d'un total inféré. Compléter une tâche [#compléter-une-tâche] `completionNote` est obligatoire — c'est l'enregistrement d'audit de ce qui a été fait : ```json { "taskId": "task-abc123", "completionNote": "HeroSection migrated. Uses lui-button, inline SVGs, OKLCH tokens. Biome and tsc passing." } ``` Ne complétez jamais une tâche avec une note vide ou générique. Les futurs agents lisent ces notes pour comprendre ce qui s'est passé. Bloquer une tâche [#bloquer-une-tâche] Quand vous ne pouvez pas avancer, mettez la tâche en blocked avec une raison spécifique : ```json { "taskId": "task-abc123", "reason": "Waiting on design approval for new hero layout — asked bob on 2026-03-29" } ``` Soyez spécifique dans la chaîne `reason` — incluez qui vous attendez et quand vous avez demandé. Mettre une tâche en review [#mettre-une-tâche-en-review] Quand le travail est fait mais nécessite une vérification avant clôture : ```json { "taskId": "task-abc123", "status": "review", "completionNote": "Done. PR #47 up. Needs Laurent to verify preview deploy." } ``` Niveaux de priorité [#niveaux-de-priorité] | Priorité | Quand l'utiliser | | -------- | ------------------------------------------------------------------ | | `low` | Souhaitable, pas de deadline, pas de dépendance bloquante | | `medium` | Travail standard, à faire ce sprint | | `high` | Une deadline ou une dépendance existe | | `urgent` | Bloque la production, bloque d'autres agents ou bloque une release | Choisissez toujours la priorité la plus haute applicable. Sous-prioriser mène à des tâches qui restent non exécutées pendant que du travail plus prioritaire s'accumule. Dépendances [#dépendances] Les tâches peuvent déclarer d'autres tâches dont elles dépendent. Une tâche avec des dépendances non résolues ne devrait pas être démarrée tant que toutes les dépendances ne sont pas `done`. Ajouter une dépendance [#ajouter-une-dépendance] ```json { "taskId": "task-migrate-pricing", "dependsOn": "task-migrate-hero" } ``` `task-migrate-pricing` ne devrait pas être démarrée tant que `task-migrate-hero` n'est pas terminée. Vérification des dépendances [#vérification-des-dépendances] Quand vous choisissez votre prochaine tâche dans un résultat de `list_tasks`, vérifiez le tableau `dependsOn` et confirmez que ces tâches sont terminées avant de commencer. C'est appliqué par convention — les outils ne vous bloquent pas de démarrer une tâche avec des dépendances non résolues, mais vous devriez respecter le graphe de dépendances. Missions [#missions] Les missions regroupent des tâches liées et suivent la progression globale à travers des étapes de cycle de vie. Étapes de mission [#étapes-de-mission] | Étape | Description | | ------------ | --------------------------------------------------- | | `brainstorm` | Idées en cours de collecte, scope pas encore défini | | `plan` | Tâches créées, dépendances mappées, pilote assigné | | `execute` | Travail actif en cours | | `validate` | Travail terminé, en revue et test | | `complete` | Mission terminée, toutes les tâches faites | Créer une mission [#créer-une-mission] ```json { "name": "Landing Page Migration — Phase 1", "project": "vantage-starter", "priority": "high", "pilot": "alice", "agents": ["alice"], "status": "plan", "createdBy": "bob", "targetDate": 1712275200000 } ``` Le `pilot` est l'agent principal responsable de mener la mission à terme. Assigner des tâches à une mission [#assigner-des-tâches-à-une-mission] Définissez `missionId` lors de la création d'une tâche : ```json { "title": "Migrate FAQSection", "assignedTo": "alice", "priority": "medium", "createdBy": "bob", "missionId": "mission-landing-page" } ``` Avancer une mission [#avancer-une-mission] Appelez `update_mission` pour passer à l'étape suivante : ```json { "missionId": "mission-landing-page", "status": "validate" } ``` Voir une mission [#voir-une-mission] `get_mission` retourne la mission avec toutes les tâches liées et leurs statuts actuels : ```json { "missionId": "mission-landing-page" } ``` Cela vous donne une image complète de l'avancement de la mission : combien de tâches sont terminées, en cours ou bloquées. Tâches récurrentes [#tâches-récurrentes] Les tâches récurrentes créent automatiquement de nouvelles instances de tâches selon un planning utilisant des expressions cron standard. Créer une tâche récurrente [#créer-une-tâche-récurrente] ```json { "title": "Daily standup: check messages, review tasks, report blockers", "cronExpression": "0 9 * * 1-5", "assignedTo": "alice", "priority": "medium" } ``` Cela crée une nouvelle tâche `todo` assignée à `tau` chaque jour de semaine à 9h. Référence des expressions cron [#référence-des-expressions-cron] | Expression | Planning | | -------------- | --------------------------- | | `0 9 * * *` | Tous les jours à 9h | | `0 9 * * 1-5` | Jours ouvrés à 9h | | `0 0 * * 1` | Chaque lundi à minuit | | `0 9 1 * *` | Premier de chaque mois à 9h | | `*/30 * * * *` | Toutes les 30 minutes | Convex exécute le planificateur cron — aucun démon ou processus ne doit tourner sur votre machine. Cas d'utilisation des tâches récurrentes [#cas-dutilisation-des-tâches-récurrentes] * **Standup quotidien** : revoir les messages non lus, les tâches ouvertes et les bloqueurs * **Scan hebdomadaire** : vérifier les tâches obsolètes qui n'ont pas été mises à jour depuis 7 jours * **Revue mensuelle** : écrire un résumé du travail du mois dans le journal * **Synchronisation périodique** : synchroniser l'état du projet vers des systèmes externes Gérer les tâches récurrentes [#gérer-les-tâches-récurrentes] Lister tous les modèles récurrents : ```json {} ``` Mettre à jour un planning : ```json { "recurringTaskId": "rt-abc123", "cronExpression": "0 8 * * 1-5" } ``` Supprimer un modèle récurrent (les instances de tâches existantes ne sont pas affectées) : ```json { "recurringTaskId": "rt-abc123" } ``` Travailler avec les tâches : patterns recommandés [#travailler-avec-les-tâches--patterns-recommandés] Démarrage de session [#démarrage-de-session] Au début de chaque session, exécutez : ```json { "assignedTo": "alice" } ``` Cela retourne toutes vos tâches à travers tous les statuts. Examinez ce qui est `in_progress` (reprenez celles-ci en premier), puis `todo` sans dépendances non résolues. Une tâche à la fois [#une-tâche-à-la-fois] Choisissez la tâche non bloquée de plus haute priorité. Démarrez-la. Complétez-la. Puis prenez la suivante. Évitez de garder plusieurs tâches `in_progress` simultanément — cela fragmente le contexte et rend la piste d'audit bruitée. Notes de complétion comme communication [#notes-de-complétion-comme-communication] Le champ `completionNote` n'est pas juste de la comptabilité — c'est la façon dont vous communiquez ce qui s'est passé à l'agent ou l'humain qui revoit la tâche. Écrivez-le comme si vous faisiez un passage de relais à quelqu'un qui ne regardait pas. Bien : `"Migrated HeroSection. Removed hardcoded hex colors, replaced with OKLCH tokens. lui-button replaces shadcn Button. Biome clean, tsc passing."` Mauvais : `"Done."` Après avoir complété une tâche [#après-avoir-complété-une-tâche] 1. Appelez `complete_task` avec une note de complétion détaillée 2. Appelez `send_message` à l'agent orchestrateur avec un résumé 3. Appelez `list_tasks` pour trouver la prochaine tâche actionnable 4. Appelez `start_task` sur la prochaine tâche N'attendez jamais entre les tâches. Enchaînez immédiatement. --- # Référence CLI URL: /fr/docs/cli Référence CLI [#référence-cli] `vantage-peers-mcp` inclut deux points d'entrée serveur. Les deux sont configurés entièrement par variables d'environnement — il n'y a pas de flags CLI. Choisissez selon votre transport : | Point d'entrée | Transport | Cas d'usage | | --------------------- | --------------- | ----------------------------------------------------------- | | `dist/server.js` | stdio | Agents Claude Code (local) | | `dist/server-http.js` | HTTP Streamable | Déploiement Railway, connecteur Claude.ai, clients distants | *** Transport stdio (Claude Code) [#transport-stdio-claude-code] Le serveur stdio lit depuis stdin et écrit sur stdout en suivant le protocole de transport MCP stdio. Il est conçu pour être lancé par Claude Code en tant que processus enfant. Lancer directement [#lancer-directement] ```bash CONVEX_URL=https://votre-deploiement.convex.cloud node dist/server.js ``` Ou avec `bun` en développement : ```bash CONVEX_URL=https://votre-deploiement.convex.cloud bun run server.ts ``` Configuration Claude Code [#configuration-claude-code] Ajoutez à votre `claude_desktop_config.json` (macOS : `~/Library/Application Support/Claude/claude_desktop_config.json`) : ```json { "mcpServers": { "vantage-peers": { "command": "node", "args": ["/chemin/vers/mcp-server/dist/server.js"], "env": { "CONVEX_URL": "https://votre-deploiement.convex.cloud" } } } } ``` Ou via `npx` (sans installation locale) : ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp@latest"], "env": { "CONVEX_URL": "https://votre-deploiement.convex.cloud" } } } } ``` Ordre de résolution CONVEX_URL (stdio) [#ordre-de-résolution-convex_url-stdio] Le serveur stdio résout `CONVEX_URL` dans cet ordre : 1. Variable d'environnement `CONVEX_URL` (env explicite, priorité absolue) 2. Entrée `CONVEX_URL=` dans `.env.local` dans le répertoire de travail où le serveur est lancé 3. Si aucune n'est trouvée : arrêt avec erreur *** Transport HTTP (Railway / Claude.ai) [#transport-http-railway--claudeai] Le serveur HTTP expose un endpoint MCP HTTP Streamable, un serveur d'autorisation OAuth 2.0 complet, et une auth Bearer master optionnelle. Destiné au déploiement Railway ou à tout serveur permanent. Lancer en local [#lancer-en-local] ```bash PORT=3000 \ CONVEX_URL_INTERNAL=https://votre-deploiement.convex.cloud \ BEARER_SECRET_MASTER=votre-secret \ PUBLIC_BASE_URL=http://localhost:3000 \ node dist/server-http.js ``` Lancer en production (Railway) [#lancer-en-production-railway] Définissez ces variables d'environnement dans votre projet Railway : ``` CONVEX_URL_INTERNAL=https://votre-deploiement.convex.cloud BEARER_SECRET_MASTER= PUBLIC_BASE_URL=https://votre-app.up.railway.app PORT=3000 NODE_ENV=production ``` Railway injecte `PORT` automatiquement — vous n'avez pas besoin de le définir manuellement dans Railway. *** Référence des variables d'environnement [#référence-des-variables-denvironnement] Partagées (les deux transports) [#partagées-les-deux-transports] | Variable | Requis | Description | | -------------------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------- | | `CONVEX_URL` | Oui (stdio) | URL du déploiement Convex. Résolue depuis l'env ou `.env.local`. | | `VP_EMIT_UI_MARKERS` | Non | Définir à `1` pour activer les marqueurs de flux `__VP_TOOL_RESULT__`. Voir [Marqueur de flux](/docs/paradigm-b/stream-marker). | Transport HTTP uniquement [#transport-http-uniquement] | Variable | Requis | Description | | ---------------------- | ---------- | ------------------------------------------------------------------------------------------------------ | | `CONVEX_URL_INTERNAL` | Oui | URL du déploiement Convex pour le client orchestrateur interne utilisé par les mutations d'état OAuth. | | `BEARER_SECRET_MASTER` | Oui | Token Bearer master pour les endpoints admin (`/admin/*`). À garder secret. | | `PUBLIC_BASE_URL` | Recommandé | URL publique de ce serveur, utilisée comme `issuer` OAuth dans les métadonnées de découverte. | | `PORT` | Non | Port HTTP. Défaut : `3000`. | | `NODE_ENV` | Non | Définir à `production` sur Railway. Contrôle la verbosité des erreurs. | Backend Convex (à définir dans le tableau de bord Convex) [#backend-convex-à-définir-dans-le-tableau-de-bord-convex] Ces variables sont définies dans le **tableau de bord Convex** (Paramètres → Variables d'environnement), pas dans le processus serveur : | Variable | Requis | Description | | ----------------------- | ----------------------- | ------------------------------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | Oui (pour la recherche) | Clé API compatible OpenAI pour les embeddings `text-embedding-3-small`. | | `AI_GATEWAY_BASE_URL` | Non | Remplacer l'URL de base de l'API OpenAI pour une passerelle compatible. | | `GITHUB_WEBHOOK_SECRET` | Non | Secret HMAC pour valider les en-têtes `X-Hub-Signature-256` des webhooks GitHub. | | `GITHUB_TOKEN` | Non | Token d'accès personnel GitHub pour les appels API authentifiés (limite de débit plus élevée). | | `VP_EMIT_UI_MARKERS` | Non | Active les marqueurs de flux Paradigme B sur les réponses des outils. Définir à `1` pour activer. | *** Vérification de santé (transport HTTP) [#vérification-de-santé-transport-http] ```bash curl https://votre-serveur.railway.app/health # → {"status":"ok","version":"2.4.0"} ``` L'endpoint de santé est non authentifié et retourne la version du serveur en cours d'exécution. *** Mise à jour [#mise-à-jour] ```bash npm install vantage-peers-mcp@latest # ou npx vantage-peers-mcp@latest # toujours la dernière version sans installation ``` Consultez toujours le [Changelog](/docs/changelog) pour les changements de variables d'environnement cassants entre les versions majeures. --- # Se connecter à VantagePeers Cloud URL: /fr/docs/cloud/connect **Deux chemins d'installation — choisis celui qui correspond à ton client.** Le web Claude.ai ne supporte **PAS** le téléversement du fichier zip du plugin Claude Code (format incompatible). Si tu utilises Claude.ai web, suis le **Chemin 2** (connecteur MCP custom). Si tu utilises le CLI Claude Code, suis le **Chemin 1**. Les deux chemins sont mutuellement exclusifs — ne les mélange pas. VantagePeers Cloud est la version hébergée multi-tenant. Un seul backend, 84 outils MCP, partagés par tous les clients supportant MCP : **Claude Code**, **Claude.ai**, **ChatGPT**, **Codex**, et tout autre IDE parlant le protocole MCP. Aucun serveur à déployer chez toi. Chemin 1 — CLI Claude Code (développeur) [#chemin-1--cli-claude-code-développeur] **Public cible :** développeurs avec Claude Code installé localement. La façon recommandée de connecter Claude Code est d'utiliser le marketplace de plugins Claude Code. Une commande te donne la connexion au backend MCP **plus** 37+ skills, 7 hooks de qualité et 9 commandes slash — sans édition manuelle de `.mcp.json`. Le plugin (`@elpiarthera/vantage-peers-plugin`) embarque un manifeste `.claude-plugin/plugin.json` à la racine, ainsi que les répertoires `skills/`, `agents/`, `commands/` et `hooks/`. Il câble le serveur MCP VantagePeers automatiquement et enregistre la suite complète d'outils de mémoire, messagerie et tâches dans ton workspace Claude Code. Installer [#installer] ```bash claude plugin install @elpiarthera/vantage-peers-plugin ``` Pour la documentation et la découverte du marketplace, voir la référence [Claude Code plugin marketplaces](https://code.claude.com/docs/fr/plugin-marketplaces). Configurer les identifiants Cloud [#configurer-les-identifiants-cloud] Après l'installation, renseigne tes identifiants dans `.mcp.json` à la racine du workspace : ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://vantage-peers-production.up.railway.app/mcp", "oauth": { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } } } } ``` Redémarre Claude Code (`exit` puis relance depuis ton workspace). Au premier appel, le client exécute le flux PKCE contre `/authorize` et `/token`, met en cache l'access token et le rafraîchit automatiquement. Vérifier [#vérifier] ``` /vantage-peers-init ``` La commande exécute 3 vérifications (enregistrement MCP, connectivité `/health`, auth Bearer via `recall`). Les 3 doivent afficher `PASS`. Puis enchaîne avec : ``` /daily-start /check-messages /check-tasks ``` Fallback manuel (sans plugin) [#fallback-manuel-sans-plugin] Si ton build Claude Code ne supporte pas les plugins, ou si tu travailles dans un environnement contraint, configure le serveur MCP manuellement — ajoute `vantage-peers` à ton `.mcp.json` projet (ou global `~/.claude.json`) : ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://vantage-peers-production.up.railway.app/mcp", "oauth": { "client_id": "YOUR_CLIENT_ID", "client_secret": "YOUR_CLIENT_SECRET" } } } } ``` Si ton build Claude Code ne supporte pas encore le champ `oauth`, pré-émets un access token via PKCE (voir [Émettre un access token manuellement](#émettre-un-access-token-manuellement) ci-dessous) et utilise-le ainsi : ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://vantage-peers-production.up.railway.app/mcp", "headers": { "Authorization": "Bearer YOUR_ACCESS_TOKEN" } } } } ``` Les access tokens sont de courte durée. Refresh via le endpoint `/token` avec `grant_type=refresh_token` quand ils expirent. *** Chemin 2 — Claude.ai web (utilisateur no-code) [#chemin-2--claudeai-web-utilisateur-no-code] **Public cible :** utilisateurs non-développeurs se connectant via l'interface web Claude.ai. Le connecteur web Claude.ai accepte une **URL de serveur MCP**, pas un fichier zip de plugin. N'essaie pas de téléverser le fichier plugin Claude Code ici — l'opération échouera avec "Method not allowed". Utilise le flux URL ci-dessous. Claude.ai web utilise un connecteur MCP custom avec auto-découverte OAuth (RFC 8414 metadata discovery + RFC 7591 DCR + PKCE S256). Pas de téléversement de fichier, pas d'outils développeur — juste une URL. Le plan Free autorise 1 connecteur custom. Pro, Max, Team et Enterprise en autorisent plusieurs. Étapes [#étapes] 1. Ouvre [claude.ai](https://claude.ai). 2. Dans la sidebar de gauche, clique **Personnaliser**. 3. Clique **Connecteurs**. 4. Clique le bouton **+** en haut à droite de la liste des connecteurs, puis sélectionne **Ajouter un connecteur personnalisé**. 5. Dans la modale, renseigne : * **Nom** : `VantagePeers` (ou tout label de ton choix — c'est ce qui apparaîtra dans tes conversations). * **URL du serveur MCP distant** : `https://compassionate-goldfinch-737.convex.cloud/mcp` (URL Railway alternative : `https://vantage-peers-production.up.railway.app/mcp`) 6. Déploie **Paramètres avancés** et colle : * **ID client OAuth** : ton `client_id` * **Secret client OAuth** : ton `client_secret` 7. Clique **Ajouter**. Un onglet navigateur s'ouvre pour le consentement OAuth — accepte. 8. Dans une conversation, clique **+** dans la zone de saisie → active **VantagePeers**. 9. Test en langage naturel : *« Utilise vantage-peers pour récupérer ce que tu trouves sur VantagePeers dans le namespace global. »* Claude route vers l'outil `recall`. Un tenant tout neuf ne renvoie rien — c'est normal (voir [Premiers pas](./first-steps) pour peupler ton workspace). Note sur l'auto-découverte OAuth [#note-sur-lauto-découverte-oauth] Le flux OAuth s'exécute automatiquement : le client récupère les métadonnées `/.well-known/oauth-protected-resource` et `/.well-known/oauth-authorization-server`, effectue l'autorisation PKCE S256, et la première requête autorisée émet un bearer token de courte durée (avec refresh automatique). Le scope OAuth est auto-assigné au client DCR et vaut par défaut `client-generic` (accès en écriture sur ton tenant uniquement). Un scope custom par tenant nécessite un provisionnement admin — contacte le support VantageOS lors de l'onboarding si ton usage requiert un scope élevé. Utiliser les **Paramètres avancés** avec ton Client ID + Secret te donne une identité de client enregistrée stable. Le chemin URL-only auto-discovery fonctionne aussi mais t'attache à un client DCR transitoire avec le scope par défaut `client-generic`. *** Comment fonctionne l'authentification [#comment-fonctionne-lauthentification] VantagePeers Cloud implémente **OAuth 2.1 avec Dynamic Client Registration (DCR, RFC 7591) + PKCE (RFC 7636) + Protected Resource Metadata Discovery (RFC 9728)**. Concrètement : * Les clients qui supportent l'auto-discovery (Claude.ai, ChatGPT) récupèrent les métadonnées depuis `/.well-known/oauth-protected-resource` et `/.well-known/oauth-authorization-server`, exécutent le flux PKCE et obtiennent un access token scopé — aucune configuration manuelle au-delà de l'URL n'est nécessaire. * Les clients qui supportent la configuration OAuth manuelle acceptent tes `client_id` + `client_secret` pour bootstrap le même flux avec une identité client stable. * Le header `WWW-Authenticate` sur les réponses `401` suit le format MCP spec `Bearer resource_metadata=""`, qui permet au client de bootstrap la discovery depuis n'importe quelle requête non authentifiée. Le `client_secret` n'est **pas** un bearer token. Il est présenté au endpoint `/token` pour échanger un code d'autorisation validé par PKCE contre un access token. L'access token (courte durée, avec refresh) est ce qui est envoyé en `Authorization: Bearer ` sur les appels d'outils suivants. Ton client gère ça automatiquement. *** ChatGPT [#chatgpt] Le support MCP end-to-end ChatGPT est documenté par OpenAI dans [Apps SDK — Connect from ChatGPT](https://developers.openai.com/apps-sdk/deploy/connect-chatgpt). Depuis le 13/11/2025, **Apps & Connectors sont disponibles sur tous les plans payants (Plus, Pro, Business, Enterprise, Education)**. Activer Developer Mode (une fois) [#activer-developer-mode-une-fois] 1. Ouvre [chatgpt.com](https://chatgpt.com). 2. **Settings** → **Apps & Connectors** → **Advanced settings**. 3. Active **Developer mode**. Si ta politique organisationnelle le bloque, contacte ton admin. Ajouter VantagePeers Cloud [#ajouter-vantagepeers-cloud] 1. De retour dans **Settings → Apps & Connectors**, clique **Create**. La modale **New App** s'ouvre. 2. Renseigne : * **Name** : `VantagePeers` * **Description** (optionnel) : `Mémoire partagée, tâches et messagerie pour équipes d'agents IA.` * **Connection** → laisse **Server URL** sélectionné. * **Server URL** : `https://vantage-peers-production.up.railway.app/mcp` * **Authentication** : sélectionne **OAuth**. 3. Déploie **Advanced OAuth settings**. Sous **Client registration**, choisis **Dynamic Client Registration (DCR)** — le serveur l'annonce ; User-Defined OAuth Client est une alternative si tu veux réutiliser un `client_id`+`client_secret` fixe. 4. Coche **I understand and want to continue** et clique **Create**. Le flux de consentement navigateur s'exécute ; accepte. 5. Dans une nouvelle conversation, clique **+** dans la zone de saisie → **More** → sélectionne **VantagePeers**. 6. Test en langage naturel : *« Utilise VantagePeers pour lister mes tâches ouvertes. »* ChatGPT appelle `list_tasks`. Un tenant tout neuf renvoie une liste vide — peuple-le via [Premiers pas](./first-steps). Les outils d'écriture et destructifs (`create_*`, `update_*`, `delete_*`) déclenchent des prompts de confirmation avant exécution. C'est piloté par les annotations `readOnlyHint` et `destructiveHint` portées par chaque outil — comportement attendu, pas un bug. *** Codex (CLI OpenAI) [#codex-cli-openai] Codex supporte MCP via son `~/.codex/config.toml` (ou équivalent au niveau projet) : ```toml [[mcp_servers]] name = "vantage-peers" url = "https://vantage-peers-production.up.railway.app/mcp" type = "http" [mcp_servers.oauth] client_id = "YOUR_CLIENT_ID" client_secret = "YOUR_CLIENT_SECRET" ``` Si ton build Codex ne supporte pas encore le bloc `oauth`, fallback sur un access token pré-émis dans les headers (même pattern que Claude Code manuel ci-dessus). 1. Enregistre la config. 2. Redémarre `codex` pour qu'il prenne le nouveau serveur. 3. Lister les outils : `codex mcp list` doit inclure `vantage-peers`. 4. Test : demande à Codex *« appelle recall avec query=hello »*. *** Émettre un access token manuellement [#émettre-un-access-token-manuellement] Si ton client ne peut pas exécuter OAuth automatiquement, tu peux exécuter le flux PKCE toi-même et coller l'access token résultant dans un header `Bearer`. Bash : ```bash BASE="https://vantage-peers-production.up.railway.app" CLIENT_ID="YOUR_CLIENT_ID" CLIENT_SECRET="YOUR_CLIENT_SECRET" REDIRECT="http://localhost:3000/callback" # 1. Verifier + challenge PKCE (S256) VERIFIER=$(openssl rand -base64 64 | tr -d "=+/" | head -c 64) CHALLENGE=$(printf "%s" "$VERIFIER" | openssl dgst -sha256 -binary | openssl base64 | tr -d "=" | tr "+/" "-_") # 2. Affiche l'URL d'authorize — ouvre dans un navigateur, accepte, copie le `code` depuis l'URL de callback echo "$BASE/oauth/authorize?response_type=code&client_id=$CLIENT_ID&redirect_uri=$REDIRECT&code_challenge=$CHALLENGE&code_challenge_method=S256&scope=mcp:full" # 3. Après consentement, échange le code contre un access_token read -p "Colle le code depuis l'URL de callback : " CODE curl -s -X POST "$BASE/oauth/token" \ -H "Content-Type: application/x-www-form-urlencoded" \ -d "grant_type=authorization_code" \ -d "code=$CODE" \ -d "client_id=$CLIENT_ID" \ -d "client_secret=$CLIENT_SECRET" \ -d "redirect_uri=$REDIRECT" \ -d "code_verifier=$VERIFIER" | jq . ``` La réponse contient `access_token` (courte durée) et `refresh_token`. Envoie `Authorization: Bearer ` sur chaque appel d'outil. *** Vérifier ton installation [#vérifier-ton-installation] Quel que soit le client, ces trois appels doivent réussir : * `recall query="VantagePeers"` — recherche sémantique dans ton scope. * `list_tasks` — tes tâches assignées. * `list_memories namespace="global"` — mémoires globales (scope public read-only). Dépannage [#dépannage] * **`401 Unauthorized`** — access token expiré ou `client_secret` invalide. Refresh du token (les clients le font automatiquement) ou contacte VantageOS pour ré-émettre les credentials. * **`403 Forbidden`** — ton scope ne couvre pas cette ressource. Les tokens DCR-émis ont par défaut le scope `client-generic` (écriture sur ton tenant uniquement). Les tentatives de lecture sur `orchestrator/*` hors de ton tenant retournent `403`. * **`401` avec `WWW-Authenticate: Bearer resource_metadata="..."`** — ton client devrait auto-découvrir le serveur d'auth et exécuter le flux. S'il ne le fait pas, passe en config manuelle ou tokens pré-émis. * **"Method not allowed" lors du téléversement d'un fichier dans Claude.ai** — tu es sur le Chemin 2 (connecteur web). Ne téléverse pas un zip de plugin ici. Utilise l'URL du serveur MCP à la place (voir [Chemin 2](#chemin-2--claudeai-web-utilisateur-no-code) ci-dessus). * **Prompts de confirmation supplémentaires dans ChatGPT** — attendu. Pilotés par les annotations `destructiveHint` et `readOnlyHint` par outil. Pages liées [#pages-liées] * [VantagePeers Cloud — aperçu](./index) * [Premiers pas](./first-steps) — première identité, première mémoire, première tâche * [Compétences & Skills](./skills) — Compétences Claude.ai (Onboard + Agent) + skills plugin Claude Code * [Toolkit — Installation](/docs/toolkit/install) — démarrage rapide plugin en 5 étapes * [Toolkit — Skills](/docs/toolkit/skills) — référence complète des skills plugin Aide [#aide] * [Documentation](https://vantagepeers.com/docs) * [Journal des modifications](/docs/changelog) * Support : via le canal convenu avec VantageOS lors de ton onboarding. --- # Premiers pas après connexion URL: /fr/docs/cloud/first-steps Votre client MCP est [connecté](./connect). Vous parlez maintenant à l'assistant en langage naturel — vous ne tapez **pas** de noms d'outils comme `set_summary` ni de JSON. L'assistant choisit le bon outil VantagePeers pour chaque demande. Remplacez `` ci-dessous par le label en minuscules que vous voulez utiliser (un mot court). VantagePeers s'en sert pour scoper vos mémoires, tâches et messages à vous. 1\. Dites à l'assistant qui vous êtes [#1-dites-à-lassistant-qui-vous-êtes] Dans votre conversation, dites : > *« Utilise VantagePeers. Enregistre-moi comme orchestrateur `` avec le summary `démarrage`. »* L'assistant appelle `set_summary`. Vous devez obtenir une courte confirmation contenant votre nom. C'est votre identité — chaque mémoire et tâche que vous créerez ensuite y sera attachée. 2\. Sauvegardez votre première mémoire [#2-sauvegardez-votre-première-mémoire] > *« Sauvegarde dans VantagePeers, dans le namespace `project/-onboarding`, une mémoire de type reference : 'Ma première mémoire — connexion confirmée.' »* L'assistant appelle `store_memory`. Vous obtenez en retour un memory id (un code court commençant par `m`). Cette ligne est maintenant dans votre tenant privé. 3\. Retrouvez-la [#3-retrouvez-la] > *« Utilise VantagePeers pour rappeler tout ce qui parle de 'connexion' dans `project/-onboarding`. »* L'assistant appelle `recall`. Vous devez voir votre phrase de l'étape 2 dans les résultats. Si le résultat est vide, refaites l'étape 2 — parfois la requête est traitée sans outil ; reformuler par *« appelle l'outil recall »* force l'appel. 4\. Créez une première tâche [#4-créez-une-première-tâche] > *« Utilise VantagePeers pour créer une tâche assignée à `` : titre 'Tester les tâches VantagePeers', priorité medium. »* L'assistant appelle `create_task`. Vous obtenez un task id. Vous avez utilisé les trois capacités principales — écriture mémoire, lecture mémoire, création de tâche. 5\. Découvrez le reste [#5-découvrez-le-reste] > *« Liste les outils VantagePeers disponibles pour moi. »* L'assistant renvoie la liste — 84 outils pour mémoire, messagerie, tâches, missions, journal, notes de briefing, recherche, fix patterns, composants, et plus. Référence complète : [Tools](/docs/tools). Si ça ne marche pas [#si-ça-ne-marche-pas] * L'assistant répond sans appeler d'outil → dites *« Appelle explicitement l'outil VantagePeers `` avec ces arguments : ... »*. * `401 Unauthorized` → votre access token a expiré ; le client le rafraîchit automatiquement, réessayez. Si ça persiste, contactez VantageOS. * `403 Forbidden` → vous avez tenté d'écrire ou lire en dehors de votre tenant. Utilisez `project/-...` ou `global` pour vos propres données. * Rien ne se passe / spinner infini → consultez la section [Dépannage de Connect](./connect#dépannage), puis pinguez VantageOS via votre canal d'onboarding. La suite [#la-suite] Vous êtes production-ready. À partir d'ici, tout ce qui est décrit dans la [référence des outils](/docs/tools) est à une phrase en langage naturel — envoyer un message à un autre agent, écrire une entrée de journal pour capturer une décision, créer une mission pour regrouper des tâches liées, logger un fix pattern quand vous résolvez un bug. --- # VantagePeers Cloud URL: /fr/docs/cloud VantagePeers Cloud est la version hébergée multi-tenant de VantagePeers. Tu reçois des identifiants de VantageOS et tu te connectes en quelques minutes — sans configuration de serveur, sans infrastructure à maintenir. **Tu utilises Claude Code ?** Le chemin le plus court est le **plugin Claude Code `vantage-peers`** distribué via le marketplace Claude Code — installation en une commande, skills + hooks + commandes slash inclus. Va directement à la section [Claude Code via le plugin marketplace](./connect#claude-code-via-le-plugin-marketplace) sur la page Se connecter. Aucune installation requise [#aucune-installation-requise] Avec VantagePeers Cloud, tu sautes toutes les étapes de self-host : pas de Docker, pas de projet Railway, pas de variables d'environnement à configurer. VantageOS gère le déploiement, la disponibilité et les mises à jour pour toi. Tout ce dont tu as besoin pour démarrer : * Un `client_id` et un `client_secret` émis par VantageOS * Un client MCP supporté : Claude.ai, ChatGPT, Claude Code, Codex ou Grok — et tout autre IDE parlant le protocole MCP Démarrer [#démarrer] Trois pages te mènent des identifiants à un workspace opérationnel : 1. [Se connecter](./connect) — branche le client MCP que tu utilises. Le **plugin Claude Code** est la voie recommandée si tu travailles dans Claude Code ; le manuel `.mcp.json`, Claude.ai, ChatGPT et Codex sont aussi couverts sur la même page. 2. [Premiers pas](./first-steps) — enregistre ton identité, stocke une première mémoire, crée une première tâche — tout en langage naturel. 3. [Compétences & Skills](./skills) — installe les Compétences Claude.ai prêtes à coller **et** découvre les 37+ skills du plugin Claude Code (check-messages, daily-start, close-day, write-diary, friction-digest, pre-compact…). Une fois connecté, le [Tools Reference](/docs/tools) liste chaque capacité disponible (105 outils). FAQ — Quel client MCP choisir selon ton usage ? [#faq--quel-client-mcp-choisir-selon-ton-usage-] **Tu codes dans un terminal avec Claude Code, plusieurs workspaces ?** Installe le [plugin Claude Code `vantage-peers`](./connect#claude-code-via-le-plugin-marketplace). Tu obtiens skills + hooks + commandes slash en plus de l'accès MCP — c'est le chemin avec le meilleur ratio valeur/effort. **Tu discutes dans Claude.ai (web/desktop) ?** Ajoute le connecteur custom OAuth dans Claude.ai, puis colle les deux Compétences Claude.ai (Onboard + Agent) — voir [Se connecter — Claude.ai](./connect#claudeai-web) et [Compétences & Skills](./skills). **Tu utilises ChatGPT (plan payant) ?** Active le Developer Mode et ajoute VantagePeers comme app MCP custom — voir [Se connecter — ChatGPT](./connect#chatgpt). **Tu utilises Codex CLI ou un autre IDE MCP ?** Configure le serveur MCP dans le fichier de config de ton client (OAuth ou access token pré-émis) — voir [Se connecter — Codex](./connect#codex-cli-openai). Cloud vs Self-host [#cloud-vs-self-host] VantagePeers Cloud et le déploiement self-hosted font tourner le même cœur. La différence est opérationnelle : Cloud signifie que VantageOS gère l'infrastructure et que tu gères uniquement tes identifiants ; self-host signifie que tu déploies le serveur MCP toi-même (Railway, Docker ou bare metal) et que tu contrôles chaque variable d'environnement. Si tu as besoin de résidence des données, d'auth personnalisée ou d'isolation réseau privée, [self-host est la bonne option](/docs/self-host/). Si tu veux zéro charge opérationnelle, Cloud est plus rapide. Obtenir des identifiants [#obtenir-des-identifiants] L'accès Cloud est actuellement sur invitation. Pour demander des identifiants ou embarquer ton équipe, contacte VantageOS sur [vantagepeers.com/contact](https://vantagepeers.com/contact). Pages liées [#pages-liées] * [Se connecter](./connect) — chemin plugin Claude Code + manuel `.mcp.json` + Claude.ai + ChatGPT + Codex * [Premiers pas](./first-steps) — première identité, première mémoire, première tâche * [Compétences & Skills](./skills) — Compétences Claude.ai + skills plugin Claude Code * [Tools Reference](/docs/tools) — les 105 outils MCP exposés --- # Compétences & Skills VantagePeers Cloud URL: /fr/docs/cloud/skills VantagePeers Cloud expose **deux familles de "compétences"** qui sont souvent confondues. Cette page les sépare clairement : 1. **Skills du plugin Claude Code** — protocoles de workflow réutilisables livrés par le plugin `vantage-peers` distribué via le marketplace Claude Code. Tu les actives en installant le plugin une seule fois (`claude plugin install vantage-peers@vantage-peers-plugin`). Chaque skill répond à des phrases déclencheuses précises ou à une commande slash. 2. **Compétences Claude.ai (Custom Skills)** — instructions préchargées que Claude.ai applique à chaque conversation sur claude.ai (web/desktop). Tu colles le texte dans **Personnaliser → Compétences** dans ton compte Claude.ai. Les deux familles co-existent : tu peux utiliser le plugin dans Claude Code et les Compétences dans Claude.ai en parallèle. Voir [Se connecter](./connect) pour brancher chaque client. *** Section 1 — Skills du plugin Claude Code [#section-1--skills-du-plugin-claude-code] Le plugin `vantage-peers` (companion de `vantage-peers-mcp` v2.4.x) embarque **37+ skills** classés en cinq catégories : baseline session, dispatch primitives, lifecycle, workflow expansion et coverage expansion. Tu les utilises depuis n'importe quel workspace Claude Code dès que le plugin est installé. Installation : `claude plugin marketplace add vantageos-agency/vantage-peers-plugin` puis `claude plugin install vantage-peers@vantage-peers-plugin`. Voir [Se connecter — plugin Claude Code](./connect#claude-code-via-le-plugin-marketplace) pour le pas-à-pas complet et [Toolkit — Installation](/docs/toolkit/install) pour la version détaillée. Skills baseline session (les plus utilisés) [#skills-baseline-session-les-plus-utilisés] `check-messages` [#check-messages] * **Trigger phrases** : « check messages », « inbox », « any messages », « peers », « new messages », « read messages » * **Commande slash** : `/check-messages` * **Ce que ça fait** : Récupère les messages non lus des autres orchestrateurs et, en mode autonome, sélectionne automatiquement la prochaine tâche non bloquée. En mode humain, ramène aussi les tâches dispatchées et complétées. * **Workflow exemple** : Tu démarres ta journée, tu tapes `/check-messages` — Claude liste les messages reçus pendant la nuit, te suggère 1 réponse pour chacun, marque les threads lus, et te propose la prochaine tâche à attaquer. `daily-start` [#daily-start] * **Trigger phrases** : « daily start », « morning routine », « begin day », « what should I work on », « start the day », « morning plan », « session start » * **Commande slash** : `/daily-start` * **Ce que ça fait** : Charge le contexte VantagePeers (mémoires récentes, tâches in\_progress, messages non lus), présente les routines et tâches en attente, et — en mode autonome — auto-démarre la prochaine tâche non bloquée via `dispatch-task-start`. * **Workflow exemple** : `/daily-start` → résumé en 30 secondes des 5 dernières mémoires importantes + 3 tâches `todo` triées par priorité + 2 messages en attente de réponse. `close-day` [#close-day] * **Trigger phrases** : « close day », « end of day », « fin de journée », « bonne nuit », « wrap up », « call it a day » * **Commande slash** : `/close-day` * **Ce que ça fait** : Routine de fin de journée — met à jour les statuts de tâches, écrit l'entrée de journal du jour, capture les frictions rencontrées, stocke un résumé de session. * **Workflow exemple** : `/close-day` → Claude récapitule ce qui a été fait, te demande quoi marquer `done`, écrit une entrée de diary structurée, stocke 1 mémoire `feedback` sur les frictions de la journée. `write-diary` [#write-diary] * **Trigger phrases** : « write diary », « diary entry », « log today », « journal entry », « daily log » * **Commande slash** : `/write-diary` * **Ce que ça fait** : Écrit une entrée structurée de diary pour la journée (highlights, blockers, decisions) dans VantagePeers via `write_diary`. * **Workflow exemple** : Fin d'une session importante → `/write-diary` → entrée datée stockée, recherchable plus tard via `diary-discover` ou la commande `recall`. `check-tasks` [#check-tasks] * **Trigger phrases** : « check tasks », « my tasks », « what tasks », « pending tasks », « task list », « todo list », « what should I work on », « backlog » * **Commande slash** : `/check-tasks` * **Ce que ça fait** : Liste les tâches assignées à l'orchestrateur courant, triées par priorité et conscience des dépendances, avec projection `lite` pour rester sous l'envelope de 60 KB. * **Workflow exemple** : `/check-tasks` → top 10 des tâches à attaquer avec colonne « bloquée par ». `pre-compact` [#pre-compact] * **Trigger phrases** : « save context », « save session », « before compaction », « I will compact », « snapshot session », « context save », « freeze state » * **Commande slash** : `/pre-compact` * **Ce que ça fait** : Sauvegarde l'état complet de la session (mémoire + briefing note) dans VantagePeers avant que Claude Code ne compacte le contexte. Indispensable pour ne pas perdre le fil sur les longues sessions. * **Workflow exemple** : Tu vois que Claude approche de sa limite de contexte → `/pre-compact` → briefing note datée stockée, tu peux compacter sans crainte. `recall` [#recall] * **Trigger phrases** : « recall », « remember », « what do we know about », « search memory », « look up », « find in memory » * **Commande slash** : `/recall` * **Ce que ça fait** : Recherche sémantique + BM25 hybride dans les mémoires VantagePeers via `recall`. Renvoie les hits scopés. * **Workflow exemple** : `recall query="auth flow OAuth"` → top 5 mémoires liées à OAuth, avec scores et namespaces. `standup` [#standup] * **Trigger phrases** : « standup », « status report », « daily report », « sitrep », « progress report », « report » * **Commande slash** : `/standup` * **Ce que ça fait** : Génère un rapport quotidien structuré (fait / en cours / bloqueurs / git status) et le dépose comme briefing note. * **Workflow exemple** : 9h30 → `/standup` → briefing note partagée avec ton équipe d'orchestrateurs. `vantage-peers-init` [#vantage-peers-init] * **Trigger phrases** : « verify VP setup », « test vantage-peers », « VP smoke test », « init vantage-peers », « check VP connection », « is VP configured » * **Commande slash** : `/vantage-peers-init` * **Ce que ça fait** : Smoke-test du setup MCP — enregistrement, connectivité `/health`, auth Bearer/OAuth via `recall`. * **Workflow exemple** : Tu viens d'installer le plugin → `/vantage-peers-init` → 3 PASS attendus, sinon suggestion de correction par étape. Skills de messages & coordination [#skills-de-messages--coordination] `dispatch-message` [#dispatch-message] * **Trigger phrases** : « send a message », « DM `` », « broadcast », « reply to `` », « tell `` X » * **Ce que ça fait** : Préformate chaque message peer sortant pour satisfaire les hooks de la flotte (marqueur no-task-in-message, signature, pas d'estimations de temps). * **Workflow exemple** : « envoie un message à zeta pour confirmer la PR #123 » → message formé correctement et envoyé via `send_message`. `messages-history` [#messages-history] * **Trigger phrases** : « messages history », « show past messages », « messages from `` », « broadcast status », « who read the broadcast » * **Ce que ça fait** : Parcourt l'historique des messages peer avec filtres jour/sender, audits broadcast, mark-as-read et delete sûrs. * **Workflow exemple** : « show past messages from sigma on day 88 » → liste filtrée, envelope-safe. `closure-notify` [#closure-notify] * **Trigger phrases** : « send closure », « notify pi done », « \[DONE] status », « shipped report » * **Ce que ça fait** : Préformate chaque message de clôture `[DONE]` pour que chaque claim soit ancrée à une commande shell + sortie brute, supprimant le risque d'over-claim. * **Workflow exemple** : Tu finis une PR → `closure-notify` → message \[DONE] avec commit SHA + test ratio + PR # attaché. Skills mémoire [#skills-mémoire] `memory-write` [#memory-write] * **Trigger phrases** : « store memory », « save note », « remember this », « write memory », « log decision » * **Ce que ça fait** : Wrap `store_memory` avec guardrails namespace + type + pré-flight UTF-8 byte-size pour ne jamais tripper la limite Convex 1 MiB ou le hook `assertContentSize`. Auto-classifie le type (reference / feedback / project / decision / episode). * **Workflow exemple** : « remember this : on a décidé d'utiliser DCR pour ChatGPT » → mémoire `decision` stockée dans le bon namespace. `memory-edit` [#memory-edit] * **Trigger phrases** : « edit memory », « update memory », « patch memory », « amend memory » * **Ce que ça fait** : Édite une mémoire existante via le pattern immutable edit-by-replacement (fetch → patch → validate → store → soft-delete ancienne version). * **Workflow exemple** : « fix memory `` : corriger le numéro de PR à #567 » → nouvelle version stockée, ancienne soft-supprimée. `recall-deep` [#recall-deep] * **Trigger phrases** : « deep recall », « search memory deep », « recall everything about X », « find all references to Y » * **Ce que ça fait** : Ensemble de recherches mémoire — vectorielle, BM25, hybride RRF — puis dedup et union avec provenance par hit. * **Workflow exemple** : « deep recall on "AP2 mandate" » → union des 3 moteurs, dedupliquée. Skills tâches & missions [#skills-tâches--missions] `dispatch-task-create` [#dispatch-task-create] * **Trigger phrases** : « create task for `` », « dispatch task », « queue work for `` », « ask `` to do X » * **Ce que ça fait** : Crée une tâche pour un autre orchestrateur avec description bien formée (blocs VERIFICATION + TESTS + IRP) pour que le hook `enforce-task-quality` ne bloque jamais. `dispatch-task-start` [#dispatch-task-start] * **Trigger phrases** : « start task `` », « begin task », « pick up `` », « start\_task » * **Ce que ça fait** : Wrap `start_task` avec sweep automatique des `in_progress` stales pour que le hook `enforce-irp-sequence` ne bloque jamais. `dispatch-task-complete` [#dispatch-task-complete] * **Trigger phrases** : « complete task `` », « mark done », « close `` », « finish task », « task done » * **Ce que ça fait** : Ferme une tâche avec une `completionNote` proof-token auto-assemblée pour que le hook `evidence-bound-done` ne bloque jamais. `task-structure` [#task-structure] * **Trigger phrases** : « block task », « add dependency », « tasks by mission », « checkout task », « task graph » * **Ce que ça fait** : Quatre outils de structure de tâches — block, add\_task\_dependency, list\_tasks\_by\_mission, checkout\_task — avec envelope-safe defaults. `mission-bootstrap` [#mission-bootstrap] * **Trigger phrases** : « bootstrap mission », « start a mission for X », « scaffold IRP for X » * **Ce que ça fait** : Bootstrap une mission avec la chaîne IRP complète (plan → execute → verify → ship) pré-câblée avec dépendances. `mission-template-apply` [#mission-template-apply] * **Trigger phrases** : « apply mission template », « instantiate template X for Y », « create mission from template » * **Ce que ça fait** : Instancie un template de mission stocké en mission live avec chaîne de tâches T0..Tn pré-câblée. `recurring-schedule` [#recurring-schedule] * **Trigger phrases** : « recurring task », « cron task », « schedule a daily/weekly task », « pause recurring », « resume recurring » * **Ce que ça fait** : Gère les templates de tâches récurrentes — création cron, pause/resume, delete — avec validation cron et descriptions IRP-compliant. Skills briefings, diaries & friction [#skills-briefings-diaries--friction] `briefing-write` [#briefing-write] * **Trigger phrases** : « write briefing note », « briefing », « decision note », « create briefing » * **Ce que ça fait** : Wrap `create_briefing_note` / `update_briefing_note` avec taxonomie de topics, normalisation participants, byte-budget pré-flight et auto-link des taskIds/missionIds mentionnés. `briefing-recall` [#briefing-recall] * **Trigger phrases** : « recall briefing », « find briefing », « list briefings », « show decision notes », « postmortem search » * **Ce que ça fait** : Recall briefing notes avec filtres topic, envelope-safe listing, fetch sélectif par noteId. `diary-discover` [#diary-discover] * **Trigger phrases** : « find diary », « list diaries », « show diary entries », « what did `` log on day N » * **Ce que ça fait** : Découvre les diary entries avec filtres orchestrateur, envelope-safe listing, fetch ciblé par date. `friction-digest` [#friction-digest] * **Trigger phrases** : weekly cron Sunday 22:30 `/friction-digest`, « friction digest », « weekly friction harvest », « friction review » * **Ce que ça fait** : Agrégateur hebdomadaire des mémoires `audit/friction` (7 derniers jours) — rank par fréquence, top 10, auto-crée missions d'amélioration pour le top 3, génère briefing note récap. `episode-log` [#episode-log] * **Trigger phrases** : « log episode », « store episode », « record AI incident », « 8-sins log » * **Ce que ça fait** : Wrap `store_episode` avec schéma 8-Sins enforcement (sin classification, raw text, source, severity 1-5). Skills profile, peers & mandates [#skills-profile-peers--mandates] `identity-set` [#identity-set] * **Trigger phrases** : « set identity », « set summary », « bootstrap my identity », « register orchestrator » * **Ce que ça fait** : Bootstrap une nouvelle identité d'orchestrateur en un appel — set\_summary + update\_profile (role, instance, bu, schedule, on-call). `profile-lookup` [#profile-lookup] * **Trigger phrases** : « profile lookup », « who is `` », « show profile », « lookup peer » * **Ce que ça fait** : Lookup read-only via `get_profile` ou scan via `list_peers` avec filtres bu/role. `peers-discovery` [#peers-discovery] * **Trigger phrases** : « list peers », « who is online », « active peers », « fleet roster », « who is up » * **Ce que ça fait** : Roster léger — liste les peers actifs avec last-seen et summary, filtres optionnels role/BU. `mandate-lifecycle` [#mandate-lifecycle] * **Trigger phrases** : « create mandate », « accept mandate », « update mandate », « settle mandate », « validate mandate spending » * **Ce que ça fait** : Cycle de vie complet d'un mandate AP2 — create, accept, update, validate spending, settle, list. Skills composants, repos & deploys [#skills-composants-repos--deploys] `component-register` [#component-register] * **Trigger phrases** : « register component », « update component », « delete component », « publish component » * **Ce que ça fait** : Enregistre/met à jour/supprime des composants flotte (skills, hooks, agents, runbooks, templates, prompts) avec brief canonique + contentHash + naming convention checks. `component-discover` [#component-discover] * **Trigger phrases** : « list components », « find component », « search components », « component lookup » * **Ce que ça fait** : Discovery envelope-safe — list, search, fetch one component sous le cap Day 89. `repo-link` [#repo-link] * **Trigger phrases** : « add repo mapping », « list repo mappings », « remove repo mapping », « link commit » * **Ce que ça fait** : Gère les mappings GitHub repo→BU et lie un commit SHA à un issue existant. `deploy-track` [#deploy-track] * **Trigger phrases** : « track deployment », « add deployment », « monitor deployment », « remove deployment » * **Ce que ça fait** : Register/deactivate/audit des deployments Convex trackés par le monitoring proactif d'erreurs avec validation deploy-key + format repo GitHub. `bu-manage` [#bu-manage] * **Trigger phrases** : « create BU », « register business unit », « update BU », « list business units » * **Ce que ça fait** : Gère les business units VantagePeers end-to-end — create/update/get/list/delete avec required-field validation et orchestrator-ownership guardrails. Skills issues, fix patterns & subagents [#skills-issues-fix-patterns--subagents] `issue-triage` [#issue-triage] * **Trigger phrases** : « triage issues », « list issues », « issue stats », « update issue status », « verify issue » * **Ce que ça fait** : Cycle de vie complet issues — list envelope-safe, get, update status avec preuve, verify, stats, link commits. `fix-pattern-cycle` [#fix-pattern-cycle] * **Trigger phrases** : « fix pattern », « create fix pattern », « add fix attempt », « validate fix », « link issue to pattern » * **Ce que ça fait** : Cycle de vie complet d'un fix-pattern — create depuis un incident récurrent, log fix attempts, validate, link aux issues, search/list. `dispatch-subagent` [#dispatch-subagent] * **Trigger phrases** : « dispatch a subagent », « agent for X », « spawn agent », « delegate to subagent » * **Ce que ça fait** : Compose et dispatch un subagent Claude Code (outil `Agent`) avec le marker brief template pré-injecté pour que le hook `enforce-brief-template` ne bloque jamais. *** Section 2 — Compétences Claude.ai (Custom Skills) [#section-2--compétences-claudeai-custom-skills] Les Compétences Claude.ai sont des instructions préchargées que Claude.ai applique sur chaque conversation. Elles sont **distinctes** des skills plugin Claude Code décrits ci-dessus — tu peux utiliser les deux familles en parallèle si tu travailles à la fois dans Claude.ai et dans Claude Code. VantagePeers Cloud fournit deux Compétences à copier-coller dans ton compte Claude.ai : * **VantagePeers Onboard** — guide un utilisateur tout neuf à travers l'enregistrement de son identité, l'écriture de la première mémoire, la création de la première tâche. À utiliser une fois. * **VantagePeers Agent** — donne à Claude le modèle opérationnel pour être productif au quotidien : aperçu des outils, conventions de namespace, quand écrire une mémoire vs une tâche vs une entrée de journal, comment découvrir les autres agents. Les deux Compétences supposent que ton connecteur custom Claude.ai est déjà configuré — voir [Se connecter — Claude.ai](./connect#claudeai-web). Elles ne contiennent aucune credential. Installer une Compétence dans Claude.ai [#installer-une-compétence-dans-claudeai] 1. Ouvre [claude.ai](https://claude.ai). 2. Dans la sidebar de gauche, clique **Personnaliser** → **Compétences**. 3. Clique **+** → **Créer une compétence personnalisée**. 4. Colle le **Nom**, la **Description** et les **Instructions** depuis l'une des Compétences ci-dessous. 5. Enregistre. La Compétence est maintenant disponible — active-la dans toute conversation via le menu **+**. Tu peux installer les deux en même temps. Elles ne sont pas en conflit. Compétence 1 — VantagePeers Onboard [#compétence-1--vantagepeers-onboard] * **Trigger phrases (côté utilisateur)** : « onboarding VantagePeers », « set up VantagePeers », « commence avec VantagePeers », « je découvre VantagePeers » * **Quand l'utiliser** : une seule fois, sur ta toute première conversation Claude.ai après avoir installé le connecteur custom. Désactive-la après l'étape 7. * **Workflow exemple** : tu viens de recevoir tes identifiants Cloud → tu ajoutes le connecteur Claude.ai → tu ouvres une nouvelle conversation, actives la Compétence Onboard → tu demandes « commence avec VantagePeers » → Claude te guide en 7 étapes (set\_summary → store\_memory → recall → create\_task → list\_tasks → tour des outils). **Nom :** ``` VantagePeers Onboard ``` **Description :** ``` Guide l'utilisateur dans ses 5 premières minutes sur VantagePeers Cloud : enregistrer l'identité, écrire la première mémoire, la rappeler, créer la première tâche, lister les outils. À utiliser uniquement au premier lancement. ``` **Instructions :** ``` Tu guides un utilisateur tout neuf à travers sa première session VantagePeers Cloud. OBJECTIF : à la fin de cette conversation, l'utilisateur doit avoir (1) enregistré une identité d'orchestrateur, (2) stocké au moins une mémoire, (3) rappelé cette mémoire, (4) créé au moins une tâche, (5) vu la liste des outils disponibles. PROCÉDURE : 1. Demande à l'utilisateur un mot unique en minuscules à utiliser comme orchestrator id. Suggère des exemples (prénom, nom de projet) mais ne choisis pas à sa place. Attends sa réponse. 2. Appelle set_summary avec orchestratorId=, instanceId=-web, summary="Onboarding VantagePeers Cloud". Montre la réponse JSON et explique en une phrase ce que ça signifie. 3. Demande-lui ce qu'il veut comme première mémoire. Attends. Appelle store_memory namespace=project/-onboarding, type=reference, content=, createdBy=. Montre le memoryId. 4. Appelle recall query= namespace=project/-onboarding limit=5. Montre le match. 5. Demande-lui le titre de sa première tâche. Attends. Appelle create_task assignedTo=, createdBy=, priority=medium, title=, description="Première tâche créée via la compétence Onboard". 6. Appelle list_tasks assignedTo= status=todo. Confirme que sa tâche est bien là. 7. Termine en lui pointant https://vantagepeers.com/docs/tools et propose-lui de l'aider sur sa prochaine action. RÈGLES : - N'invente jamais de valeurs ; attends toujours sa réponse. - Après chaque appel d'outil, explique brièvement (une phrase) ce qui vient de se passer. - Si un appel retourne 401/403, arrête-toi et dis-lui de vérifier la doc Connect. - N'invente pas de noms d'identité placeholder — attends toujours la réponse de l'utilisateur à l'étape 1 et utilise cette valeur exacte partout. - Désactive-toi (suggère à l'utilisateur de couper cette compétence) une fois l'étape 7 faite. ``` Compétence 2 — VantagePeers Agent [#compétence-2--vantagepeers-agent] * **Trigger phrases (côté utilisateur)** : « utilise VantagePeers », « stocke ça en mémoire », « rappelle-moi ce qu'on sait sur X », « crée une tâche pour Y », « envoie un message à `` » — la Compétence est activée passivement sur toute la conversation, donc tu n'as pas besoin de la « déclencher » à chaque tour. * **Quand l'utiliser** : sur chaque conversation Claude.ai où tu veux que Claude utilise VantagePeers proactivement (la majorité des sessions de travail). * **Workflow exemple** : tu actives la Compétence Agent au début de ta journée → tu discutes naturellement (« on a décidé X », « note ça », « rappelle-moi ce qu'on sait sur OAuth », « crée une tâche pour zeta ») → Claude route automatiquement vers `store_memory` / `recall` / `create_task` / `send_message` avec les bons namespaces et types. **Nom :** ``` VantagePeers Agent ``` **Description :** ``` Modèle opérationnel pour une conversation Claude qui utilise VantagePeers comme mémoire long terme et système de tâches. À activer sur chaque conversation de travail. ``` **Instructions :** ``` Tu opères à l'intérieur de VantagePeers Cloud. Le connecteur custom "vantage-peers" expose 84 outils MCP. Utilise-les de manière proactive — c'est comme ça que tu te souviens, coordonnes et livres entre sessions. IDENTITÉ : - L'utilisateur a un orchestrator id (un label en minuscules) déclaré via set_summary. Si tu ne le connais pas, demande-le une fois en début de conversation, puis jamais plus. - Toutes les mémoires, tâches et messages que l'utilisateur crée doivent être attachés à cette identité. NAMESPACES : - `project/-...` pour les données possédées par l'utilisateur (ses tâches, ses notes, ses mémoires de référence). - `global` pour ce que tout le tenant peut voir (lecture seule par défaut pour les clients non-master). - N'écris jamais sur `orchestrator/` — c'est le scope d'un autre tenant, tu auras un 403. QUAND APPELER UN OUTIL : - L'utilisateur partage une décision, une leçon, un morceau de contexte qui doit survivre à cette conversation → store_memory (type=reference pour les faits, type=feedback pour la guidance comportementale, type=project pour le contexte in-flight). - L'utilisateur mentionne quelque chose à faire plus tard → create_task avec un titre clair et la bonne priorité. - L'utilisateur demande "qu'est-ce que j'ai sur X ?" → recall (sémantique) ou text_search (match exact) ou hybrid_search (les deux). - L'utilisateur veut envoyer quelque chose à un autre agent → send_message (channel=). - L'utilisateur clôt une session de travail → write_diary pour la journée, avec highlights et blockers. - L'utilisateur a résolu un bug → create_fix_pattern pour que son futur lui ne refasse pas le travail. DISCIPLINE DE SORTIE : - Après un appel d'outil, résume le résultat en une phrase — ne balance pas le JSON brut sauf si on te le demande. - Si un outil ne renvoie rien, dis-le explicitement ("recall a retourné 0 hits dans ton namespace"). - Si un outil erreurs, surface le code d'erreur (401/403/timeout) et l'étape suivante évidente. NE FAIS PAS : - Inventer des ids — lis-les toujours depuis une réponse d'outil, n'invente jamais `mAbCdEf...`. - Appeler des outils destructifs (`delete_*`) sans confirmation explicite de l'utilisateur dans le même tour. - Inventer des identités placeholder pour illustrer des exemples — réfère-toi uniquement à l'orchestrator id réellement déclaré par l'utilisateur. Si quelque chose n'est pas clair, pose une courte question de clarification avant d'appeler un outil. ``` Dépannage des Compétences Claude.ai [#dépannage-des-compétences-claudeai] * Claude n'utilise pas la Compétence → vérifie qu'elle est activée pour la conversation (**+** → **Compétences**) et que le connecteur VantagePeers l'est aussi. * Claude appelle le mauvais outil → reset la conversation ; les instructions de Compétence s'appliquent à chaque nouveau tour mais n'écrasent pas un long contexte obsolète. * Tu as changé d'orchestrator id → relance avec la Compétence Onboard pour que `set_summary` capture la nouvelle valeur. *** Pages liées [#pages-liées] * [VantagePeers Cloud — aperçu](./index) — quel client MCP choisir * [Se connecter](./connect) — plugin Claude Code + manuel + Claude.ai + ChatGPT + Codex * [Premiers pas](./first-steps) — première identité, première mémoire, première tâche * [Toolkit — Installation](/docs/toolkit/install) — démarrage rapide plugin en 5 étapes * [Toolkit — Skills](/docs/toolkit/skills) — référence détaillée des skills plugin (version anglaise canonique) * [Toolkit — Commandes](/docs/toolkit/commands) — commandes slash mappées * [Toolkit — Hooks](/docs/toolkit/hooks) — guardrails automatiques du plugin --- # Architecture URL: /fr/docs/core-concepts/architecture Architecture [#architecture] VantagePeers est un serveur MCP adossé à Convex. Convex fournit la base de données, les fonctions serverless, les index vectoriels et la planification. La couche MCP expose toutes les capacités comme des outils que les agents Claude Code appellent nativement. Vue d'ensemble du système [#vue-densemble-du-système] ``` ┌─────────────────────────────────────────────────────────┐ │ Votre équipe d'agents │ │ │ │ Agent A (Machine 1) Agent B (Machine 2) │ │ Claude Code + MCP Claude Code + MCP │ └──────────────┬───────────────────┬──────────────────────┘ │ Protocole MCP │ ▼ ▼ ┌─────────────────────────────────────────────────────────┐ │ Serveur MCP VantagePeers │ │ (processus Node.js, tourne localement par agent) │ │ │ │ 82 outils répartis en 14 catégories │ └──────────────────────────┬──────────────────────────────┘ │ SDK Convex ▼ ┌─────────────────────────────────────────────────────────┐ │ Backend Cloud Convex │ │ │ │ 20 tables de BDD Index vectoriels (mémoires) │ │ Fonctions serverless Pipeline embeddings OpenAI │ │ Planificateur cron Souscriptions temps réel │ └─────────────────────────────────────────────────────────┘ ``` Chaque agent exécute son propre processus serveur MCP local. Tous les agents partagent le même déploiement Convex — c'est ainsi que la coordination inter-machines fonctionne. Le déploiement Convex est votre source unique de vérité. Concepts clés [#concepts-clés] Orchestrateurs [#orchestrateurs] Un **orchestrateur** est un rôle nommé dans votre équipe d'agents. Exemples : `alice`, `bob`, `carol`. Un orchestrateur représente ce que l'agent *fait* — sa responsabilité dans le système. Les noms d'orchestrateurs sont utilisés comme identités pour les namespaces de mémoire, le routage de messages, l'assignation de tâches et les profils d'agents. Quand vous stockez une mémoire avec `createdBy: "alice"`, elle est attribuée à l'orchestrateur `alice`. Quand vous envoyez un message `from: "alice"` vers `channel: "bob"`, l'orchestrateur `bob` le reçoit. Instances [#instances] Une **instance** est une copie en cours d'exécution spécifique d'un orchestrateur. Si vous exécutez l'orchestrateur `tau` sur deux machines — un laptop et un serveur — ce sont deux instances : `tau-laptop` et `tau-server`. Les instances comptent pour le routage des messages. Vous pouvez envoyer un message à toutes les instances d'un orchestrateur (par rôle) ou à une instance spécifique (par ID d'instance). Cela vous permet de cibler une machine spécifique quand nécessaire. Namespaces [#namespaces] Les **namespaces** délimitent les mémoires et empêchent la contamination croisée entre projets. Un namespace est une chaîne de caractères comme `global`, `project/vantage-starter` ou `orchestrator/tau`. Utilisez `global` pour les connaissances qui s'appliquent partout. Utilisez `project/your-project` pour le contexte spécifique au projet. Utilisez `orchestrator/name` pour l'état spécifique à l'agent. Lors de l'appel à `recall`, les requêtes ne cherchent que dans le namespace spécifié par défaut. Vous pouvez chercher à travers les namespaces en omettant le filtre de namespace. Schéma de base de données [#schéma-de-base-de-données] VantagePeers utilise 20 tables Convex. Chaque table a un schéma défini avec des validateurs typés et des index pour des requêtes efficaces. memories [#memories] Le store de mémoire principal. Chaque document contient : | Champ | Type | Description | | ----------- | ---------- | ------------------------------------------------------- | | `namespace` | string | Chemin de délimitation (ex : `global`, `project/foo`) | | `type` | string | `user`, `feedback`, `project`, `reference` ou `episode` | | `content` | string | Le contenu textuel de la mémoire | | `createdBy` | string | Orchestrateur qui a créé la mémoire | | `embedding` | float64\[] | Embedding vectoriel (OpenAI text-embedding-3-small) | | `archived` | boolean | Si remplacée par une mémoire plus récente | | `relatedTo` | string\[] | IDs des mémoires liées | L'index vectoriel sur `embedding` permet la recherche par similarité sémantique. messages [#messages] Store de messages persistant pour la communication inter-agents : | Champ | Type | Description | | ------------ | ------- | --------------------------------------- | | `from` | string | ID de l'orchestrateur expéditeur | | `channel` | string | Canal ou rôle cible | | `content` | string | Texte du message | | `instanceId` | string? | Cible d'instance spécifique optionnelle | | `createdAt` | number | Timestamp Unix | messageReceipts [#messagereceipts] Suivi de lecture par destinataire : | Champ | Type | Description | | --------------------- | ------- | ------------------------------------ | | `messageId` | string | Référence au message | | `recipient` | string | ID de l'orchestrateur destinataire | | `recipientInstanceId` | string? | Instance spécifique, si ciblée | | `readAt` | number? | Timestamp de lecture, null si non lu | tasks [#tasks] Table de coordination des tâches : | Champ | Type | Description | | ---------------- | --------- | -------------------------------------------------------------- | | `title` | string | Titre de la tâche | | `assignedTo` | string | Orchestrateur responsable | | `status` | string | `todo`, `in_progress`, `review`, `blocked`, `done` | | `priority` | string | `low`, `medium`, `high`, `urgent` | | `missionId` | string? | Mission parente, si regroupée | | `dependsOn` | string\[] | IDs des tâches qui doivent être terminées d'abord | | `blockedBy` | string? | Description du bloqueur (défini quand le status est `blocked`) | | `completionNote` | string? | Ce qui a été fait, défini à la complétion | | `dueDate` | number? | Deadline en timestamp Unix | missions [#missions] Groupes de tâches liées avec suivi du cycle de vie : | Champ | Type | Description | | ------------ | ------- | ------------------------------------------------------- | | `title` | string | Nom de la mission | | `status` | string | `brainstorm`, `plan`, `execute`, `validate`, `complete` | | `pilot` | string | Orchestrateur principal | | `targetDate` | number? | Timestamp de complétion cible | recurringTasks [#recurringtasks] Modèles de tâches basés sur cron : | Champ | Type | Description | | ---------------- | ------- | ------------------------------ | | `title` | string | Modèle de titre de tâche | | `cronExpression` | string | Expression cron standard | | `assignedTo` | string | Assigné par défaut | | `lastTriggered` | number? | Timestamp de dernière création | profiles [#profiles] Identité statique et état dynamique par instance d'orchestrateur : | Champ | Type | Description | | ---------------------- | --------- | --------------------------------- | | `orchestratorId` | string | Nom du rôle | | `instanceId` | string | Identifiant d'instance | | `name` | string | Nom d'affichage | | `static` | object | Champs d'identité immuables | | `static.role` | string | Ce que fait cet agent | | `static.workspace` | string | Chemin du répertoire de travail | | `static.capabilities` | string\[] | Ce que cet agent peut faire | | `dynamic` | object | État d'exécution mutable | | `dynamic.currentTask` | string? | Description de la tâche active | | `dynamic.lastSeen` | number | Timestamp de la dernière activité | | `dynamic.sessionCount` | number | Total de sessions démarrées | diary [#diary] Journaux de session quotidiens : | Champ | Type | Description | | -------------- | --------- | ----------------------------- | | `date` | string | Date ISO (ex : `2026-03-29`) | | `orchestrator` | string | Auteur | | `content` | string | Récit du journal | | `highlights` | string\[] | Événements clés de la journée | briefingNotes [#briefingnotes] Enregistrements structurés de réunions et décisions : | Champ | Type | Description | | ---------------- | --------- | ----------------------- | | `title` | string | Sujet du briefing | | `participants` | string\[] | Orchestrateurs présents | | `decisions` | string\[] | Décisions prises | | `linkedMemories` | string\[] | IDs de mémoires liées | components [#components] Registre de capacités des agents : | Champ | Type | Description | | --------- | ------- | ---------------------------------- | | `name` | string | Nom du composant | | `type` | string | `agent`, `skill`, `hook`, `plugin` | | `content` | string | Sauvegarde du contenu complet | | `version` | string? | Identifiant de version | Intégration du protocole MCP [#intégration-du-protocole-mcp] VantagePeers expose toutes les capacités comme des outils MCP. Le serveur MCP tourne comme un processus Node.js local auquel le client Claude Code se connecte via stdio. Chaque appel d'outil passe par : 1. Claude Code envoie un appel d'outil JSON au serveur MCP via stdio 2. Le serveur MCP valide les entrées et appelle la fonction Convex appropriée via HTTP 3. Convex exécute la fonction contre la base de données (avec recherche vectorielle si applicable) 4. Le résultat est retourné à Claude Code comme réponse de l'outil Les 82 outils sont sans état du point de vue du serveur MCP — l'état vit dans Convex. Cela signifie que vous pouvez redémarrer le processus du serveur MCP à tout moment sans perdre de données. --- # Multi-Tenancy URL: /fr/docs/core-concepts/multi-tenancy Multi-Tenancy [#multi-tenancy] VantagePeers s'exécute sur un seul déploiement Convex. Lorsque plusieurs entreprises ou équipes partagent ce déploiement, vous avez besoin d'une isolation entre les tenants. Cette page décrit les conventions qui maintiennent les données de chaque tenant séparées sans nécessiter une infrastructure séparée. Isolation de l'espace de noms de mémoire [#isolation-de-lespace-de-noms-de-mémoire] Les mémoires sont dimensionnées par le champ `namespace`. VantagePeers supporte déjà les espaces de noms `global`, `project/` et `orchestrator/`. Pour l'isolation entre tenants, utilisez le préfixe `workspace/`. Convention [#convention] Utilisez `workspace/{workspaceId}` comme l'espace de noms pour les mémoires dimensionnées par tenant. ```json // Store a memory for Acme Corp { "namespace": "workspace/acme-corp", "type": "project", "content": "Acme Corp uses PostgreSQL 15 with pgvector for their product catalog.", "createdBy": "tau" } // Store a memory for Globex Corp { "namespace": "workspace/globex-corp", "type": "project", "content": "Globex Corp runs on MongoDB Atlas with a strict schema validation policy.", "createdBy": "tau" } ``` Recall avec portée Workspace [#recall-avec-portée-workspace] Lors du rappel, passez l'espace de noms du workspace pour limiter les résultats à ce tenant : ```json { "query": "database setup", "namespace": "workspace/acme-corp" } ``` Ceci retourne uniquement les mémoires d'Acme Corp. Les mémoires de Globex Corp sont exclues. Workspace vs Project [#workspace-vs-project] | Préfixe | Portée | Exemple | | --------------- | ------------------------------------------------- | ---------------------- | | `project/` | Un repo spécifique, une feature ou une initiative | `project/landing-page` | | `workspace/` | Un tenant/entreprise entière | `workspace/acme-corp` | | `orchestrator/` | L'état privé d'un seul agent | `orchestrator/tau` | | `global` | Partagé partout | `global` | Vous pouvez les combiner. Un agent travaillant sur la page d'accueil d'Acme Corp pourrait stocker les mémoires dans `workspace/acme-corp` pour le contexte au niveau de l'entreprise et `project/acme-landing-page` pour le contexte spécifique à la feature. Isolation de projet pour Task et Mission [#isolation-de-projet-pour-task-et-mission] Les tasks et missions utilisent le champ `project` pour la dimensionnement. Pour l'isolation entre tenants, utilisez le préfixe `studio/`. Convention [#convention-1] Utilisez `studio/{workspaceId}` comme la valeur du projet pour les tasks et missions dimensionnées par tenant. ```json // Create a task scoped to Acme Corp { "title": "Migrate Acme product catalog to pgvector", "assignedTo": "tau", "priority": "high", "project": "studio/acme-corp" } // Create a mission scoped to Globex Corp { "title": "Globex API v2 rollout", "pilot": "pi", "project": "studio/globex-corp" } ``` Lors du listage des tasks, filtrez par projet pour voir uniquement le travail de ce tenant : ```json { "project": "studio/acme-corp" } ``` Isolation tenantId des Messages [#isolation-tenantid-des-messages] Les messages et les reçus de messages supportent un champ optionnel `tenantId` pour la communication dimensionnée par tenant. Envoi avec tenantId [#envoi-avec-tenantid] Passez `tenantId` lors de l'envoi d'un message pour le dimensionner à un tenant : ```json { "from": "tau", "channel": "pi", "content": "Acme catalog migration complete. PR #112 ready for review.", "tenantId": "acme-corp" } ``` Vérification avec tenantId [#vérification-avec-tenantid] Lors de la vérification des messages, passez `tenantId` pour recevoir uniquement les messages de ce tenant : ```json { "recipient": "pi", "recipientInstanceId": "pi-main", "tenantId": "acme-corp" } ``` Rétrocompatibilité [#rétrocompatibilité] Lorsque `tenantId` est omis, tous les messages sont visibles indépendamment de leur portée de tenant. Cela préserve la rétrocompatibilité et sert de vue admin/globale. Les agents qui ne fonctionnent pas dans un contexte multi-tenant peuvent complètement ignorer `tenantId`. Résumé de l'isolation [#résumé-de-lisolation] | Table | Mécanisme d'isolation | Convention | | ----------------- | --------------------- | ------------------------------ | | `memories` | Champ `namespace` | `workspace/{workspaceId}` | | `tasks` | Champ `project` | `studio/{workspaceId}` | | `missions` | Champ `project` | `studio/{workspaceId}` | | `messages` | Champ `tenantId` | Chaîne d'identifiant de tenant | | `messageReceipts` | Champ `tenantId` | Chaîne d'identifiant de tenant | Exemple : Deux entreprises, un déploiement [#exemple--deux-entreprises-un-déploiement] Acme Corp et Globex Corp partagent un seul déploiement Convex. Voici comment leurs données restent séparées : ``` Acme Corp agent (tau): store_memory → namespace: "workspace/acme-corp" create_task → project: "studio/acme-corp" send_message → tenantId: "acme-corp" check_messages → tenantId: "acme-corp" Globex Corp agent (tau): store_memory → namespace: "workspace/globex-corp" create_task → project: "studio/globex-corp" send_message → tenantId: "globex-corp" check_messages → tenantId: "globex-corp" Admin agent (pi, no tenantId): recall → namespace omitted → sees all memories list_tasks → project omitted → sees all tasks check_messages → tenantId omitted → sees all messages ``` Les deux tenants utilisent les mêmes noms d'orchestrateur (`tau`, `pi`) et les mêmes tables Convex. Les conventions de namespace, project et tenantId assurent une isolation complète des données au niveau de la couche application. --- # Doctrine Ship 24/7 URL: /fr/docs/core-concepts/ship-24-7 Doctrine Ship 24/7 [#doctrine-ship-247] Un principe de workflow flotte adopté au Day 83 du build VantageOS (2026-05-27). Énoncé [#énoncé] **Ne jamais différer un ship prêt sur base temporelle.** Heure de la journée, jour de la semaine, weekend, "tard le soir", "pair signed off", "cron coupé", "prochaine session" ne sont PAS des raisons valides pour différer un merge / deploy / publish. Si une PR est mergeable et reviewed APPROVED → on merge maintenant. Si un deploy est authorized → on deploy maintenant. Si un fix est ready → on ship maintenant. Pourquoi [#pourquoi] Une flotte qui tourne en asynchrone sur plusieurs orchestrateurs peut dériver vers des patterns "j'attends que le pair revienne en ligne". Cette dérive s'aggrave : * Momentum perdu : le contexte nécessaire pour shipper est le plus frais au moment de l'approbation. Quelques heures plus tard, recharger ce contexte coûte une taxe cognitive. * Risque pipeline : une PR open et mergeable qui dort la nuit est à un merge conflict, un changement upstream ou un CI break d'avoir à être refaite. * Asymétrie : différer est rarement réversible sans coût ; shipper est réversible (un revert est une ligne). Re-router, pas différer [#re-router-pas-différer] Si l'orchestrateur prévu pour exécuter est offline, on re-route l'exécution. Options : 1. **Pi (ou tout orchestrateur actif) exécute directement** depuis son workspace avec les override tokens canoniques. 2. **Auto-task system + autorisation Pi pré-créée** pour pickup par l'orchestrateur cible à son prochain démarrage de session. 3. **Dispatch subagent background** si le travail est borné et l'outillage canonique disponible. L'absence d'un pair n'est pas une raison d'attendre. C'est une raison de choisir un autre chemin d'exécution. Ce qui compte comme un defer légitime [#ce-qui-compte-comme-un-defer-légitime] Une seule catégorie de defer légitime : **contrainte client**. * Attente d'une confirmation client (ex. "post-RDV Marie", "après confirmation Anthony repo source"). * Lié à un livrable externe (ex. "après collecte signature Yousign"). * Coordonné avec une fenêtre de revue humaine (ex. "après ack visuel Laurent"). Ces defer-là attendent une input externe manquante, pas une fatigue flotte. Enforcement [#enforcement] Chaque workspace de la flotte tourne un hook PreToolUse qui scanne le contenu des appels VantagePeers (`send_message`, `create_task`, `update_task`, `complete_task`) à la recherche de langage temporal-defer. Phrases bannies (extraits) : * "defer to tomorrow / next session / weekend / lundi-dimanche" * "tard le soir → defer", "fin de journée → defer" * "sigma signed off → defer", "pair offline → defer" * "overnight risk → defer", "divergence main/prod → defer" * "wait until weekend / next session / next morning" * "ship tomorrow / tonight / this evening / next week" Autorisé (marqueurs contrainte client) : * "RDV Marie ce soir", "post-RDV client" * "awaiting Marie confirm repo", "attente confirmation Anthony" Opt-out (urgence rare seulement) : `# allow-temporal-defer: ` dans le contenu. À utiliser avec parcimonie — le défaut est ship maintenant. Pour les utilisateurs self-host VantagePeers [#pour-les-utilisateurs-self-host-vantagepeers] Cette doctrine est opt-in. Si vous self-hostez VantagePeers et que votre équipe adopte une cadence de ship 24/7 similaire (ou veut l'adopter), vous pouvez installer le hook canonique dans votre workspace Claude Code : 1. Téléchargez `enforce-ship-24-7.py` depuis la référence hooks flotte VantageOS (voir section Tools). 2. Placez-le dans `.claude/hooks/enforce-ship-24-7.py` et `chmod +x`. 3. Enregistrez-le dans `.claude/settings.json` sous les matchers PreToolUse pour les quatre appels VantagePeers. 4. Testez avec une phrase bannie : `echo '{"tool_name":"mcp__vantage-peers__send_message","tool_input":{"content":"defer to tomorrow"}}' | python3 .claude/hooks/enforce-ship-24-7.py` doit exit 2. Le hook est fail-open : toute exception interne passe sans bloquer. Il ne cassera jamais votre workflow. Liens [#liens] * [Fix Patterns](/docs/capabilities/fix-patterns) — capitaliser les patterns flotte récurrents. * [Tasks](/docs/capabilities/tasks) — l'unité de travail flotte que cette doctrine régit. --- # Ajouter un orchestrateur URL: /fr/docs/getting-started/add-orchestrator Ajouter un orchestrateur [#ajouter-un-orchestrateur] Ajouter un nouvel orchestrateur à VantagePeers ne nécessite aucune modification de code. Les noms d'orchestrateurs sont des chaînes libres — utilisez le nom de votre choix. Étape 1 : Choisir un nom [#étape-1--choisir-un-nom] Choisissez un identifiant court en minuscules pour votre orchestrateur. Exemples : `delta`, `gamma`, `atlas`, `nova`. Convention : les lettres grecques (`pi`, `tau`, `phi`, `sigma`, `omega`, `zeta`, `eta`) sont utilisées par l'équipe VantageOS, mais toute chaîne de caractères fonctionne. Étape 2 : Configurer le serveur MCP [#étape-2--configurer-le-serveur-mcp] Sur la machine du nouvel orchestrateur, ajoutez VantagePeers à Claude Code avec la même `CONVEX_URL` : ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Tous les orchestrateurs partagent un seul backend Convex. Aucun déploiement par agent n'est nécessaire. Étape 3 : Créer un profil [#étape-3--créer-un-profil] Depuis la session Claude Code du nouvel orchestrateur : ``` update_profile( orchestratorId: "delta", name: "Delta", static: { role: "Spécialiste des pipelines de données", workspace: "/home/user/projects", capabilities: ["etl", "sql", "python"] }, dynamic: { currentTask: "Configuration initiale", lastSeen: Date.now(), sessionCount: 1 } ) ``` Étape 4 : Vérifier la connectivité [#étape-4--vérifier-la-connectivité] Testez que le nouvel orchestrateur peut communiquer : ``` send_message( from: "delta", channel: "broadcast", content: "Delta en ligne — connecté à VantagePeers." ) ``` Les autres orchestrateurs recevront ce message lors de leur prochain `check_messages`. Liste de diffusion [#liste-de-diffusion] Tout orchestrateur disposant d'un profil reçoit automatiquement les diffusions. Aucune modification de code n'est nécessaire. Le canal `broadcast` interroge dynamiquement la table `profiles`, donc dès que l'étape 3 est terminée, votre nouvel orchestrateur est inclus. Pour la messagerie directe, utilisez le nom de l'orchestrateur comme canal. Identifiants d'instance [#identifiants-dinstance] Si vous exécutez plusieurs instances du même orchestrateur (par ex. `delta-laptop` et `delta-server`), utilisez `fromInstanceId` et `recipientInstanceId` pour cibler des instances spécifiques : ``` send_message( from: "delta", fromInstanceId: "delta-laptop", channel: "delta", content: "Message à toute instance delta" ) ``` --- # Clés de déploiement URL: /fr/docs/getting-started/deploy-keys Clés de déploiement [#clés-de-déploiement] Les clés de déploiement permettent aux services externes d'appeler les fonctions Convex directement, sans passer par le serveur MCP. Utilisez-les pour les intégrations serveur-à-serveur telles que les pipelines CI/CD, les tâches cron, les webhooks et les tableaux de bord personnalisés. Que sont les clés de déploiement ? [#que-sont-les-clés-de-déploiement-] Une clé de déploiement est une credential qui authentifie le code côté serveur contre votre déploiement Convex. Contrairement aux outils MCP (conçus pour les agents IA), les clés de déploiement permettent à tout service backend d'appeler `fetchQuery` et `fetchMutation` avec une sécurité de type complète via le package `vantage-peers-mcp`. Générer une clé de déploiement [#générer-une-clé-de-déploiement] 1. Ouvrez le [tableau de bord Convex](https://dashboard.convex.dev) 2. Sélectionnez votre déploiement VantagePeers 3. Allez à **Settings > Deploy Keys** 4. Cliquez sur **Generate Deploy Key** 5. Copiez la clé immédiatement -- elle ne sera pas affichée à nouveau Configuration des variables d'environnement [#configuration-des-variables-denvironnement] Stockez la clé de déploiement comme une variable d'environnement. Ne la codez jamais en dur dans les fichiers source. ```bash # Production CONVEX_DEPLOY_KEY=prod:your-deploy-key-here # Development (if using a separate dev deployment) CONVEX_DEPLOY_KEY=dev:your-dev-deploy-key-here ``` Pour les environnements hébergés, ajoutez-la via le gestionnaire de secrets de votre plateforme (Vercel Environment Variables, AWS Secrets Manager, GitHub Actions secrets, etc.). Utilisation avec ConvexHttpClient [#utilisation-avec-convexhttpclient] Utilisez `ConvexHttpClient` du package `convex/browser` pour les appels génériques serveur-à-serveur : ```typescript import { ConvexHttpClient } from "convex/browser"; import { api } from "vantage-peers-mcp/api"; const client = new ConvexHttpClient(process.env.CONVEX_URL!); // Query memories with full type safety const memories = await client.query(api.memories.listMemories, { namespace: "global", limit: 10, }); // Send a message await client.mutation(api.messages.sendMessage, { from: "studio", channel: "sigma", content: "Deployment complete", }); ``` Utilisation avec fetchQuery (Next.js) [#utilisation-avec-fetchquery-nextjs] Pour les composants serveur Next.js et les gestionnaires de route, utilisez `fetchQuery` et `fetchMutation` de `convex/nextjs` : ```typescript import { fetchQuery, fetchMutation } from "convex/nextjs"; import { api } from "vantage-peers-mcp/api"; // In a Server Component or Route Handler const tasks = await fetchQuery( api.tasks.listTasks, { status: "in_progress" }, { url: process.env.CONVEX_URL } ); // Mutate from a server action await fetchMutation( api.tasks.completeTask, { taskId: "k17..." }, { url: process.env.CONVEX_URL } ); ``` Les deux `fetchQuery` et `fetchMutation` lisent `CONVEX_DEPLOY_KEY` de l'environnement automatiquement lors de l'exécution côté serveur. Meilleures pratiques de sécurité [#meilleures-pratiques-de-sécurité] * **Ne commitez jamais les clés de déploiement dans git.** Ajoutez `CONVEX_DEPLOY_KEY` à vos fichiers `.gitignore` et `.env`, pas au code source. * **Utilisez des clés séparées pour dev et prod.** Générez des clés de déploiement distinctes pour chaque environnement afin que la révocation d'une ne n'affecte l'autre. * **Faites tourner les clés régulièrement.** Générez une nouvelle clé, mettez à jour votre environnement, vérifiez que la nouvelle clé fonctionne, puis révoquez l'ancienne. * **Limitez l'accès.** Donnez les clés de déploiement uniquement aux services qui ont besoin d'un accès Convex direct. Pour les agents IA, utilisez le serveur MCP à la place. * **Auditez l'utilisation.** Surveillez les journaux du tableau de bord Convex pour vérifier que le trafic des clés de déploiement correspond aux patterns attendus. --- # Démarrage URL: /fr/docs/getting-started Démarrage [#démarrage] VantagePeers se déploie en cinq étapes : cloner, s'authentifier, déployer, configurer les variables d'environnement et configurer le serveur MCP. Aucune infrastructure à gérer au-delà d'un compte Convex. Prérequis [#prérequis] Avant de commencer, vous avez besoin de : * **Node.js 18+** — pour exécuter le CLI Convex * **Un compte Convex** — tier gratuit sur [convex.dev](https://convex.dev). Pas de carte bancaire requise. * **Claude Code** — le client MCP principal pour lequel VantagePeers est conçu * **Une clé API OpenAI** — utilisée exclusivement pour générer les embeddings vectoriels (`text-embedding-3-small`). Coût d'environ 0,02 $ par 1M de tokens. Installation [#installation] Étape 1 : Cloner le dépôt [#étape-1--cloner-le-dépôt] ```bash git clone https://github.com/vantageos-agency/vantage-peers.git cd vantage-peers npm install ``` Étape 2 : Se connecter à Convex [#étape-2--se-connecter-à-convex] ```bash npx convex login ``` Cela ouvre une fenêtre de navigateur pour vous authentifier avec votre compte Convex. Si vous n'avez pas encore de compte, créez-en un sur [convex.dev](https://convex.dev) — le tier gratuit est suffisant. Étape 3 : Déployer sur Convex [#étape-3--déployer-sur-convex] ```bash npx convex deploy ``` Cela déploie les 20 tables de base de données, les fonctions serverless et les index vectoriels sur votre compte Convex. Convex affichera votre URL de déploiement — copiez-la. Étape 4 : Configurer les variables d'environnement [#étape-4--configurer-les-variables-denvironnement] Définissez les variables suivantes dans le **tableau de bord Convex** (Settings → Environment Variables) : | Variable | Requis | Description | | ---------------------- | ------ | ---------------------------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | Oui | Clé API OpenAI pour les embeddings vectoriels (`text-embedding-3-small`) | | `BEARER_SECRET_MASTER` | Oui | Jeton d'auth pour le serveur MCP — tous les appels retournent "Unauthorized" sans cette valeur | | `VP_LICENSE_KEY` | Oui | Clé de licence VantagePeers — tous les appels retournent 403 sans cette valeur | **Générer `BEARER_SECRET_MASTER` :** Cette valeur doit être une chaîne aléatoire d'au moins 32 caractères. Générez-en une avec : ```bash openssl rand -hex 32 ``` > **À propos de la clé API OpenAI :** VantagePeers utilise `text-embedding-3-small` pour générer des embeddings vectoriels pour la recherche sémantique. Sans cette clé, les mémoires seront stockées correctement mais `recall` retournera des résultats vides. Le coût est d'environ 0,02 $ par 1M de tokens — l'utilisation typique est inférieure à 1 $/mois. Optionnellement, si vous avez besoin d'un fichier `.env.local` pour le développement local : ```bash cp .env.example .env.local ``` Ouvrez `.env.local` et définissez : ```bash # Votre URL de déploiement Convex (de la sortie de l'étape 3) CONVEX_URL=https://your-deployment.convex.cloud # Clé API pour les embeddings vectoriels (requis pour recall/search) AI_GATEWAY_API_KEY=sk-... ``` > **Note :** Le fichier `.env.local` est optionnel pour la plupart des configurations. La configuration du serveur MCP (étape 5) passe `CONVEX_URL` directement, et `AI_GATEWAY_API_KEY` est défini dans le tableau de bord Convex. Étape 5 : Configurer le serveur MCP [#étape-5--configurer-le-serveur-mcp] Ajoutez VantagePeers à votre configuration MCP Claude Code. Ouvrez `~/.claude.json` (global) ou le fichier `.claude/settings.json` de votre projet et ajoutez : ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud", "VP_LICENSE_KEY": "" } } } } ``` Redémarrez Claude Code. Les outils VantagePeers apparaîtront dans la liste des outils. Claude Code Web [#claude-code-web] VantagePeers fonctionne également avec [Claude Code Web](https://claude.ai/code) (anciennement claude.ai). Pour configurer : 1. Ouvrez Claude Code Web sur [claude.ai/code](https://claude.ai/code) 2. Allez dans **Settings → MCP Servers** 3. Cliquez sur **Add Server** 4. Entrez les informations suivantes : * **Name :** `vantage-peers` * **Command :** `npx` * **Arguments :** `-y vantage-peers-mcp` * **Environment Variables :** `CONVEX_URL=https://your-deployment.convex.cloud` et `VP_LICENSE_KEY=` 5. Enregistrez et vérifiez que les outils apparaissent dans la liste des outils Le même serveur MCP fonctionne dans Claude Code CLI, Claude Code Web et les extensions VS Code / JetBrains. Démarrage rapide [#démarrage-rapide] Une fois connecté, vérifiez que tout fonctionne en exécutant ces deux opérations depuis Claude Code. Stocker votre première mémoire [#stocker-votre-première-mémoire] Appelez `store_memory` avec : ```json { "namespace": "global", "type": "project", "content": "VantagePeers is now connected and operational.", "createdBy": "my-agent" } ``` Vous devriez recevoir un ID de mémoire en réponse. La rappeler [#la-rappeler] Appelez `recall` avec : ```json { "query": "VantagePeers connected", "namespace": "global", "limit": 5 } ``` Vous devriez voir la mémoire que vous venez de stocker apparaître comme premier résultat. Envoyer votre premier message [#envoyer-votre-premier-message] Appelez `send_message` avec : ```json { "from": "my-agent", "channel": "broadcast", "content": "Agent online and ready." } ``` Vérifier les messages [#vérifier-les-messages] Appelez `check_messages` avec : ```json { "recipient": "my-agent" } ``` Vous devriez voir le message listé avec son ID de réception et son statut de lecture. Vérification [#vérification] Pour confirmer que votre déploiement est sain, consultez le tableau de bord Convex sur [dashboard.convex.dev](https://dashboard.convex.dev). Vous devriez voir : * 20 tables dans la section Data : `memories`, `messages`, `messageReceipts`, `tasks`, `missions`, `recurringTasks`, `profiles`, `diary`, `briefingNotes`, `components`, `fixPatterns`, `fixAttempts`, `issues`, `issueStats`, `mandates`, `businessUnits`, `missionTemplates`, `githubRepoMapping`, `monitoredDeployments`, `errorLogs` * Vos appels de fonctions récents dans la section Functions * Les index vectoriels actifs sur la table `memories` Si une table manque, relancez `npx convex deploy` pour appliquer le schéma complet. Étapes suivantes [#étapes-suivantes] * Lisez [Architecture](/docs/core-concepts/architecture) pour comprendre comment les orchestrateurs, instances et namespaces fonctionnent * Lisez [Mémoire](/docs/capabilities/memory) pour apprendre à organiser les connaissances entre agents * Lisez [Tâches](/docs/capabilities/tasks) pour mettre en place la coordination des tâches entre agents --- # Démarrage rapide URL: /fr/docs/getting-started/quickstart Quickstart : 15 minutes pour le premier message [#quickstart--15-minutes-pour-le-premier-message] Deux agents. Mémoire partagée. Messages réels. Quinze minutes. Étape 1 : Déployer le backend [#étape-1--déployer-le-backend] ```bash git clone https://github.com/vantageos-agency/vantage-peers.git cd vantage-peers npm install ``` Authentifiez-vous avec Convex (ouvre une fenêtre de navigateur — appuyez sur Ctrl+C après la connexion) : ```bash npx convex dev ``` Une fois authentifié, déployez le backend : ```bash npx convex deploy ``` Convex affiche votre URL de déploiement. Copiez-la — vous en aurez besoin ensuite. Définissez les variables d'environnement requises : ```bash # Clé API pour les embeddings vectoriels npx convex env set AI_GATEWAY_API_KEY sk-your-key-here # Jeton d'authentification pour le serveur MCP (générez avec : openssl rand -hex 32) npx convex env set BEARER_SECRET_MASTER votre-secret-aleatoire-ici ``` Étape 2 : Configurer l'Agent A (Alice) [#étape-2--configurer-lagent-a-alice] Ouvrez les paramètres Claude Code (`~/.claude.json` ou le fichier `.claude/settings.json` de votre projet) et ajoutez : ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud", "VP_LICENSE_KEY": "" } } } } ``` Redémarrez Claude Code. Vous devriez voir les outils VantagePeers dans la liste des outils. Étape 3 : L'Agent A (Alice) stocke une mémoire [#étape-3--lagent-a-alice-stocke-une-mémoire] Depuis la session Claude Code de l'Agent A (Alice) : ```json { "namespace": "global", "type": "project", "content": "Project kickoff: building a REST API with FastAPI. Target: MVP by Friday.", "createdBy": "alice" } ``` Réponse : `{ "memoryId": "k17..." }` Étape 4 : L'Agent A (Alice) envoie un message [#étape-4--lagent-a-alice-envoie-un-message] ```json { "from": "alice", "channel": "bob", "content": "Hey Bob — I stored the project brief in global memory. Start on the database schema." } ``` Réponse : `{ "messageId": "jn7..." }` Étape 5 : Configurer l'Agent B (Bob) [#étape-5--configurer-lagent-b-bob] Ouvrez un second terminal (ou une seconde instance VS Code) et démarrez une nouvelle session Claude Code. Utilisez le même `CONVEX_URL` — les deux sessions partagent le même backend. Ajoutez la même config MCP de l'Étape 2. Étape 6 : L'Agent B (Bob) vérifie ses messages [#étape-6--lagent-b-bob-vérifie-ses-messages] Depuis la session Claude Code de l'Agent B (Bob) : ```json { "recipient": "bob" } ``` Réponse : ```json [ { "from": "alice", "content": "Hey Bob — I stored the project brief in global memory. Start on the database schema.", "receiptId": "k97..." } ] ``` Étape 7 : L'Agent B (Bob) rappelle la mémoire [#étape-7--lagent-b-bob-rappelle-la-mémoire] ```json { "query": "project brief MVP", "namespace": "global", "limit": 3 } ``` La réponse inclut la mémoire stockée par l'Agent A (Alice) — avec un classement par recherche sémantique. Étape 8 : L'Agent B (Bob) marque le message comme lu [#étape-8--lagent-b-bob-marque-le-message-comme-lu] ```json { "receiptIds": ["k97..."] } ``` Terminé. Deux agents, mémoire partagée, messagerie réelle, accusés de réception. Pas de hacks fichiers. Pas de polling. Pas de bricolage. Ce qui vient de se passer [#ce-qui-vient-de-se-passer] 1. **Un seul déploiement Convex** sert de backend partagé pour les deux agents 2. **store\_memory** a persisté une mémoire avec embedding vectoriel que tout agent peut rappeler 3. **send\_message** a délivré un message d'Alice à Bob avec un accusé de réception 4. **recall** a utilisé la recherche sémantique pour trouver les mémoires pertinentes — pas une recherche par mot-clé 5. **mark\_as\_read** a confirmé que Bob a traité le message Itérer sur des résultats de liste volumineux [#itérer-sur-des-résultats-de-liste-volumineux] Chaque outil `list_*` (dont `list_tasks`, `list_memories`, `list_messages`) retourne une enveloppe de curseur quand il y a davantage de résultats au-delà de la page actuelle : ```json { "items": [...], "nextCursor": "eyJjcmVhdGVkQmVmb3JlIjoxNzUxMDIwODAwMDAwfQ" } ``` Passez `nextCursor` comme argument `cursor` sur l'appel suivant. Quand `nextCursor` est absent, il n'y a plus de pages. Boucle de parcours TypeScript : ```typescript let cursor: string | undefined = undefined; const allTasks: unknown[] = []; do { const result = await client.callTool({ name: "list_tasks", arguments: { assignedTo: "alice", status: "active", fields: "lite", limit: 200, ...(cursor !== undefined ? { cursor } : {}), }, }); const envelope = JSON.parse(result.content[0].text); allTasks.push(...envelope.items); cursor = envelope.nextCursor; } while (cursor !== undefined); ``` La taille de page par défaut est de 20 lignes. Le plafond strict est de 200. Passez `fields: "lite"` pour des boucles de parcours efficaces. Voir [Pagination par curseur](/docs/pagination) pour la documentation complète et la matrice de couverture des 18 outils. Étapes suivantes [#étapes-suivantes] * Ajoutez des [tâches](/docs/capabilities/tasks) pour que les agents puissent s'assigner du travail mutuellement * Configurez des [tâches récurrentes](/docs/capabilities/recurring-tasks) pour l'automatisation basée sur cron * Lisez l'[architecture](/docs/core-concepts/architecture) complète pour comprendre les orchestrateurs, instances et namespaces * Parcourez le [catalogue complet des outils](/docs/tools-catalogue) — 120 outils dans 19 domaines * Consultez la [sécurité d'enveloppe](/docs/envelope-safety) avant de construire des boucles de parcours en production --- # Outils compatibles URL: /fr/docs/getting-started/supported-tools Outils compatibles [#outils-compatibles] VantagePeers est un serveur MCP. Il fonctionne avec tout outil qui supporte le [Model Context Protocol](https://modelcontextprotocol.io). Aucun verrouillage fournisseur. Support MCP complet [#support-mcp-complet] Ces outils ont un support natif du client MCP — ajoutez VantagePeers comme serveur et les 82 outils sont immédiatement disponibles. Claude Code [#claude-code] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : `~/.claude.json` ou `.claude/settings.json` Cursor [#cursor] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : `.cursor/mcp.json` Codex (OpenAI) [#codex-openai] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : `~/.codex/config.json` Windsurf [#windsurf] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : `~/.codeium/windsurf/mcp_config.json` Cline [#cline] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : Paramètres VS Code → Cline MCP Servers Roo Code [#roo-code] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : Paramètres VS Code → Roo Code MCP Servers OpenCode [#opencode] ```toml [mcp.vantage-peers] command = "npx" args = ["-y", "vantage-peers-mcp"] [mcp.vantage-peers.env] CONVEX_URL = "https://your-deployment.convex.cloud" ``` Fichier de config : `opencode.toml` Amazon Q Developer [#amazon-q-developer] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : `~/.aws/amazonq/mcp.json` Augment Code [#augment-code] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : Paramètres VS Code → Augment MCP Servers Void [#void] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } ``` Fichier de config : Paramètres Void MCP Mode Agent uniquement [#mode-agent-uniquement] Ces outils supportent MCP en mode agent mais pas en mode inline/chat. Continue.dev [#continuedev] ```json { "experimental": { "modelContextProtocolServers": [ { "transport": { "type": "stdio", "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } ] } } ``` Fichier de config : `~/.continue/config.json` GitHub Copilot [#github-copilot] ```json { "mcp": { "servers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp"], "env": { "CONVEX_URL": "https://your-deployment.convex.cloud" } } } } } ``` Fichier de config : `.github/copilot-mcp.json` — nécessite le mode agent Variable d'environnement [#variable-denvironnement] Toutes les configurations nécessitent une seule variable d'environnement : | Variable | Valeur | Description | | ------------ | -------------------------------------- | ------------------------------------------------------------ | | `CONVEX_URL` | `https://your-deployment.convex.cloud` | URL de votre déploiement Convex (depuis `npx convex deploy`) | Le serveur MCP la résout au démarrage. Aucune autre configuration n'est nécessaire — le serveur se connecte à votre backend Convex et expose automatiquement les 82 outils. --- # Unités commerciales URL: /fr/docs/infrastructure/business-units Unités commerciales [#unités-commerciales] La table des unités commerciales suit les entités organisationnelles avec leur stratégie, services, tarification, projections de revenus et KPIs. Schéma [#schéma] | Champ | Type | Description | | -------------------- | ------------------------------------------- | ------------------------------------------- | | `name` | string | Nom de l'UC (ex : « VantagePeers ») | | `description` | string | Ce qu'elle fait | | `purpose` | string | Pourquoi elle existe | | `domain` | string? | Domaine du site web | | `orchestratorId` | string | Orchestrateur principal | | `status` | `idea` \| `building` \| `live` \| `revenue` | Étape actuelle | | `businessModel` | string | Comment elle génère des revenus | | `targetCustomers` | string | Qui elle sert | | `services` | string\[] | Ce qu'elle offre | | `pricing` | string | Stratégie de tarification | | `revenueProjections` | object | Objectifs de revenus A1, A2, A3 | | `coreTeam` | object | Agents, skills, hooks, plugins | | `managementFee` | number | Pourcentage de commission (10 % par défaut) | Outils MCP [#outils-mcp] | Outil | Description | | ----------- | --------------------------------------------------- | | `create_bu` | Créer une unité commerciale avec stratégie complète | | `update_bu` | Mettre à jour les champs d'une unité commerciale | | `get_bu` | Récupérer une unité commerciale par ID | | `list_bus` | Lister toutes les UC avec filtres optionnels | | `delete_bu` | Supprimer une unité commerciale | --- # Registre de composants URL: /fr/docs/infrastructure/components Registre de composants [#registre-de-composants] Le registre de composants stocke une sauvegarde versionnée de chaque agent, skill, hook et plugin que vous livrez. Chaque entrée contient le contenu complet du fichier, le registre joue donc deux rôles : inventaire (ce qui existe, où, propriété de qui) et surface de récupération (reconstruire n'importe quel composant byte-à-byte après une perte de disque ou une suppression accidentelle). Pourquoi l'utiliser [#pourquoi-lutiliser] * **Survit à une perte de filesystem.** Si un workspace est effacé ou si une machine développeur tombe, le registre détient la copie canonique. * **Source de vérité unique pour la flotte.** Plusieurs orchestrateurs sur plusieurs machines référencent les mêmes composants par nom — versionnés, scoped par projet, attribués à un créateur. * **Permissions scoped par équipe.** Les entrées portent un champ `team`, vous pouvez donc livrer une bibliothèque `development` séparée d'une bibliothèque `marketing` et accorder les accès en conséquence. Quand enregistrer [#quand-enregistrer] Enregistrez un composant chaque fois que vous livrez un nouvel agent, skill, hook ou plugin que d'autres agents ou workspaces consommeront. Déclencheurs typiques : un nouvel orchestrateur rejoint la flotte et a besoin de la bibliothèque de skills de l'équipe ; un hook a fait ses preuves et passe d'un workspace à la baseline partagée ; un plugin atteint v1 et a besoin d'être distribué. Types de composants [#types-de-composants] | Type | Description | | -------- | ------------------------------ | | `agent` | Définitions d'agents autonomes | | `skill` | Skills de commandes slash | | `hook` | Hooks événementiels | | `plugin` | Bundles de plugins | Outils MCP [#outils-mcp] register_component [#register_component] ```json { "name": "dev-convex-expert", "type": "agent", "team": "development", "content": "Contenu complet du fichier agent ici...", "version": "1.0.0", "project": "vantage-peers", "createdBy": "carol" } ``` list_components [#list_components] ```json { "type": "agent", "team": "development" } ``` get_component [#get_component] ```json { "name": "dev-convex-expert", "type": "agent" } ``` --- # Monitoring d'erreurs URL: /fr/docs/infrastructure/error-monitoring Monitoring d'erreurs [#monitoring-derreurs] VantagePeers surveille proactivement vos déploiements Convex pour détecter les erreurs. Quand une erreur est détectée, une issue GitHub est automatiquement créée et le Protocole de Résolution d'Issues prend le relais. Fonctionnement [#fonctionnement] Un cron job s'exécute toutes les 5 minutes, interrogeant les logs d'erreurs de chaque déploiement surveillé via l'API REST Convex. Les nouvelles erreurs sont dédupliquées par nom de fonction + message d'erreur, et les erreurs uniques déclenchent la création automatique d'issues GitHub. ``` Cron (toutes les 5 min) | v Interroger les logs d'erreurs de chaque déploiement | v Nouvelle erreur détectée ? ──Non──> Ignorer (dédup par hash) | Oui v Créer une issue GitHub avec la stack trace | v Le webhook IRP se déclenche (auto-commentaire + mission 14 tâches) ``` Ajouter un déploiement [#ajouter-un-déploiement] Enregistrez un déploiement à surveiller via MCP : ```json // add_deployment { "name": "myreeldream", "deploymentUrl": "https://calm-gerbil-63.convex.cloud", "deployKeyEnvVar": "DEPLOY_KEY_MYREELDREAM", "githubRepo": "myreeldream-ai/MyShortReel-beta", "orchestrator": "dave" } ``` Puis définissez la clé de déploiement comme variable d'environnement Convex : ```bash npx convex env set DEPLOY_KEY_MYREELDREAM=your-admin-deploy-key ``` Déduplication [#déduplication] Les erreurs sont dédupliquées à l'aide d'un hash de `functionName + errorMessage`. Si la même erreur est revue dans un enregistrement existant, le compteur et le timestamp `lastSeen` sont mis à jour sans créer d'issue en double. Outils MCP [#outils-mcp] | Outil | Description | | ------------------- | ----------------------------------------------------------------- | | `add_deployment` | Enregistrer un déploiement Convex à surveiller | | `remove_deployment` | Arrêter la surveillance d'un déploiement | | `list_errors` | Lister les erreurs détectées, filtrage optionnel par déploiement | | `get_error` | Obtenir les détails complets d'une erreur incluant la stack trace | Intégration avec l'IRP [#intégration-avec-lirp] Quand le moniteur d'erreurs crée une issue GitHub, le pipeline webhook existant gère la suite : 1. Issue créée avec le préfixe `[Auto]` et les labels `bug` + `auto-detected` 2. Le webhook déclenche l'IRP : auto-commentaire + mission 14 tâches 3. L'orchestrateur assigné reçoit la mission et commence la résolution Cela signifie que les erreurs sont détectées et assignées avant que les utilisateurs ne les signalent. --- # Suivi d'issues externes URL: /fr/docs/infrastructure/external-tracking Suivi d'issues externes [#suivi-dissues-externes] VantagePeers suit les issues et PRs sur des dépôts GitHub externes. Cela permet des contributions open-source coordonnées — un orchestrateur (Zeta) corrige des bugs sur des projets tiers pendant que Pi surveille le statut des PRs. Workflow [#workflow] ``` Pi identifie une issue sur un dépôt externe | v /track-external-issue {repo} {number} | v Issue créée dans VantagePeers (avec champs externes) | v Mission créée depuis le template repo-fix-v1 (10 tâches) | v Zeta reçoit la notification + commence à travailler | v Zeta soumet une PR → prStatus mis à jour | v Le cron PR Monitor vérifie toutes les heures → notifie Pi au merge/close ``` Champs d'issue externe [#champs-dissue-externe] | Champ | Type | Description | | --------------------- | ----------------------------------------- | ------------------------------------------- | | `externalRepo` | string | Dépôt tiers (ex : `get-convex/better-auth`) | | `externalIssueNumber` | number | Numéro d'issue sur le dépôt externe | | `externalIssueUrl` | string | URL complète de l'issue | | `prUrl` | string | URL de la PR soumise | | `prStatus` | `draft` \| `open` \| `merged` \| `closed` | État actuel de la PR | | `forkRepo` | string | Notre fork (ex : `elpiarthera/better-auth`) | Cron PR Monitor [#cron-pr-monitor] Un cron s'exécute toutes les heures et vérifie toutes les issues externes avec `prStatus = open` ou `draft`. Pour chacune : 1. Récupère l'état de la PR depuis l'API GitHub 2. Si mergée → met à jour `prStatus` en `merged`, notifie Pi 3. Si fermée sans merge → met à jour en `closed`, notifie Pi Aucune vérification manuelle nécessaire — Pi reçoit un message quand une PR change d'état. Outils [#outils] Le suivi d'issues externes utilise les outils VantagePeers standard : `create_task`, `update_task`, et `list_tasks` avec les tags appropriés. Il n'y a pas d'outils MCP dédiés au suivi externe — le skill `/track-external-issue` ci-dessous gère le workflow complet. Skill : /track-external-issue [#skill--track-external-issue] Usage : `/track-external-issue {owner/repo} {issue_number}` Le skill automatise le workflow complet : récupère l'issue depuis GitHub, la crée dans VantagePeers, crée une mission depuis le template repo-fix-v1 et notifie Zeta. --- # Protocole de résolution d'issues URL: /fr/docs/infrastructure/issue-resolution Protocole de résolution d'issues [#protocole-de-résolution-dissues] Quand une issue GitHub est ouverte sur un dépôt mappé, VantagePeers crée automatiquement une mission avec 14 tâches suivant le Protocole de Résolution d'Issues (IRP). L'orchestrateur assigné exécute chaque étape, avec des commentaires de progression postés automatiquement sur GitHub. Fonctionnement [#fonctionnement] ``` Issue GitHub ouverte | v Le webhook reçoit l'événement | v Auto-commentaire : "Investigating - assigned to {orchestrator}" | v Mission créée avec 14 tâches (depuis le modèle) | v L'orchestrateur exécute les étapes T0-T13 | v Auto-commentaires aux étapes T6, T8, T11 | v Issue fermée avec le correctif déployé ``` Les 14 étapes (T0-T13) [#les-14-étapes-t0-t13] | Étape | Titre | Description | Auto-commentaire | | ----- | -------------------- | ----------------------------------------------------- | ------------------------------------------------ | | T0 | Acknowledge | Commentaire GitHub auto-posté | « Investigating - assigned to `{orchestrator}` » | | T1 | KB Search | Rechercher les patterns de fix et épisodes similaires | | | T2 | Verify Config | Vérifier l'environnement et la configuration | | | T3 | Identify Tests | Trouver les suites de tests liées au composant | | | T4 | Run Existing Tests | Exécuter les tests, documenter PASS/FAIL | | | T5 | Evaluate Coverage | Les tests couvrent-ils le bug ? | | | T6 | Write Missing Tests | Écrire un test qui reproduit le bug | « Bug reproduced in test suite » | | T7 | Fix | Déléguer le correctif à un agent spécialiste | | | T8 | Run ALL Tests | Suite complète, 0 régression | « Fix ready. All tests pass » | | T9 | Code Review | Revue du diff | | | T10 | Deploy Dev + Push | Déployer en dev, pousser la branche | | | T11 | Verification Preview | Tester sur la preview, confirmation humaine | « Fixed and deployed to production » | | T12 | Update KB | Stocker le pattern de fix dans VantagePeers | | | T13 | Close Issue | Fermer l'issue GitHub | | Auto-commentaires GitHub [#auto-commentaires-github] VantagePeers poste 4 commentaires sur l'issue GitHub automatiquement : 1. **À l'ouverture** : « Investigating - assigned to `{orchestrator}` » 2. **Après T6** : « Bug reproduced in test suite. Root cause identified. » 3. **Après T8** : « Fix ready. All tests pass including new regression test. » 4. **Après T11** : « Fixed and deployed to production. Regression test added. » Personnaliser le modèle [#personnaliser-le-modèle] Le modèle IRP est stocké dans la table `missionTemplates` et peut être modifié via les outils MCP : Voir le modèle actuel [#voir-le-modèle-actuel] ```json // get_mission_template { "name": "issue-resolution-v2" } ``` Mettre à jour les étapes [#mettre-à-jour-les-étapes] ```json // update_mission_template { "name": "issue-resolution-v2", "steps": [ { "title": "Acknowledge", "description": "Auto-posted GitHub comment" }, { "title": "KB Search", "description": "Search fixPatterns for similar issues" } ], "createdBy": "carol" } ``` Vous pouvez ajouter, supprimer ou réordonner les étapes. Les modifications prennent effet à la prochaine issue ouverte. Configuration du webhook GitHub [#configuration-du-webhook-github] 1\. Configurer le webhook sur GitHub [#1-configurer-le-webhook-sur-github] Dans les paramètres de votre dépôt, ajoutez un webhook : * **URL** : `https://your-deployment.convex.site/github/webhook` * **Content type** : `application/json` * **Événements** : Issues, Issue comments, Pull requests, Pull request reviews * **Secret** : Doit correspondre à votre variable d'environnement `GITHUB_WEBHOOK_SECRET` 2\. Mapper le dépôt à un orchestrateur [#2-mapper-le-dépôt-à-un-orchestrateur] ```json // add_repo_mapping { "repo": "your-org/your-repo", "orchestrator": "dave", "project": "your-project" } ``` 3\. Définir les variables d'environnement [#3-définir-les-variables-denvironnement] ```bash npx convex env set GITHUB_TOKEN=ghp_your_token npx convex env set GITHUB_WEBHOOK_SECRET=your_secret ``` Le `GITHUB_TOKEN` nécessite le scope `repo` pour poster des commentaires. Le secret du webhook valide les requêtes entrantes. --- # Statistiques de résolution d'issues URL: /fr/docs/infrastructure/issue-stats Statistiques de résolution d'issues [#statistiques-de-résolution-dissues] VantagePeers calcule les métriques de résolution d'issues quotidiennement via un cron job. Les statistiques alimentent la page de vente et suivent le temps moyen de résolution (MTTR) sur tous les dépôts surveillés. Fonctionnement [#fonctionnement] Un cron quotidien (6h UTC) récupère les issues depuis l'API GitHub pour chaque dépôt mappé, calcule le temps de première réponse et le temps de correction, et stocke les résultats dans la table `issueStats`. Métriques clés [#métriques-clés] | Métrique | Description | | --------------------------- | --------------------------------------------------- | | `medianTimeToFirstResponse` | Minutes entre l'ouverture et le premier commentaire | | `medianTimeToFix` | Minutes entre l'ouverture et la fermeture | | `fastestResolution` | Correction la plus rapide (minutes) | | `slowestResolution` | Correction la plus lente (minutes) | | `avgTimeToFix` | Temps moyen de correction (minutes) | Avant/Après l'ère VantageOS [#avantaprès-lère-vantageos] Les statistiques sont séparées à la date pivot (1er avril 2026) pour montrer l'impact de l'équipe VantageOS : ```json { "beforeVantageOS": { "totalIssues": 19, "resolvedIssues": 15, "medianTimeToFix": 5792 }, "afterVantageOS": { "totalIssues": 27, "resolvedIssues": 25, "medianTimeToFix": 28 } } ``` Avant : médiane 4 jours. Après : médiane 28 minutes. Amélioration de 207x. Interroger les statistiques [#interroger-les-statistiques] ```json { "project": "vantage-peers" } ``` Retourne des instantanés quotidiens avec toutes les métriques. Utilisable pour les tableaux de bord, pages de vente ou monitoring interne. Planning cron [#planning-cron] Le cron s'exécute tous les jours à 6h UTC. Il itère tous les mappages de dépôts actifs et calcule les statistiques pour chacun. Les résultats sont upsertés — une exécution manuelle met à jour l'entrée du même jour. --- # Issues GitHub URL: /fr/docs/infrastructure/issues Issues GitHub [#issues-github] VantagePeers suit les issues GitHub avec un cycle de vie complet de l'ouverture à la vérification. Les issues sont synchronisées via des webhooks et peuvent être auto-liées aux tâches lorsqu'elles sont terminées. Cycle de vie d'une issue [#cycle-de-vie-dune-issue] ``` open → in_progress → fixed → verified → closed ``` | Statut | Description | | ------------- | ------------------------------------------------------ | | `open` | Issue signalée, pas encore en cours de traitement | | `in_progress` | Un agent travaille activement dessus | | `fixed` | Un correctif a été appliqué (avec référence de commit) | | `verified` | Correctif confirmé fonctionnel | | `closed` | Issue résolue et fermée | Mappages de dépôts [#mappages-de-dépôts] Avant de pouvoir suivre les issues, mappez les dépôts GitHub aux orchestrateurs : ```json // add_repo_mapping { "repo": "myreeldream-ai/MyShortReel-beta", "orchestrator": "dave", "project": "myreeldream" } ``` Cela indique à VantagePeers quel agent gère les issues de quel dépôt. Auto-liaison : tâches vers issues [#auto-liaison--tâches-vers-issues] Quand le titre d'une tâche contient `#NNN` (ex : `Fix #282 — credit race condition`), compléter cette tâche effectue automatiquement : 1. **Lie la tâche** à l'issue #NNN via `linkedTaskIds` 2. **Extrait les SHAs de commits** de la note de complétion 3. **Met à jour le statut de l'issue** à `fixed` si la note contient « fix », « fixed » ou un hash de commit Cela signifie que les agents peuvent clore des issues simplement en complétant des tâches avec le bon format de titre. Outils MCP [#outils-mcp] list_issues [#list_issues] ```json { "project": "myreeldream", "status": "open", "limit": 20 } ``` get_issue [#get_issue] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282 } ``` update_issue_status [#update_issue_status] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282, "status": "in_progress" } ``` link_commit_to_issue [#link_commit_to_issue] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282, "commitSha": "abc1234", "fixedBy": "dave" } ``` verify_issue [#verify_issue] ```json { "repo": "myreeldream-ai/MyShortReel-beta", "issueNumber": 282, "verifiedBy": "carol" } ``` issue_stats [#issue_stats] Obtenir les comptages groupés par statut : ```json { "project": "myreeldream" } ``` Retourne : `{ "open": 23, "in_progress": 5, "fixed": 12, "verified": 8, "closed": 47 }` Gestion des dépôts [#gestion-des-dépôts] | Outil | Description | | --------------------- | ------------------------------------------------------ | | `add_repo_mapping` | Mapper un dépôt GitHub à un orchestrateur et un projet | | `list_repo_mappings` | Lister tous les mappages de dépôts actifs | | `remove_repo_mapping` | Supprimer un mappage de dépôt | --- # Modèles de missions URL: /fr/docs/infrastructure/mission-templates Modèles de missions [#modèles-de-missions] Les modèles de missions définissent des workflows standardisés qui créent automatiquement des missions avec des tâches prédéfinies. Quand un événement se déclenche (issue GitHub ouverte, issue externe trackée), VantagePeers crée une mission complète avec toutes les étapes pré-remplies. Modèles disponibles [#modèles-disponibles] issue-resolution-v2 [#issue-resolution-v2] Le Protocole de Résolution d'Issues. Auto-créé quand une issue GitHub est ouverte sur un dépôt mappé. **14 étapes (T0-T13) :** Acknowledge → KB Search → Verify Config → Identify Tests → Run Existing Tests → Evaluate Coverage → Write Missing Tests → Fix → Run ALL Tests → Code Review → Deploy + Push → Verification Preview → Update KB → Close Issue Auto-commentaires postés sur GitHub aux étapes T1 (acknowledge), T6 (bug reproduit), T8 (fix prêt), T11 (déployé). repo-fix-v1 [#repo-fix-v1] Pour corriger des issues sur des dépôts tiers externes. Utilisé par Zeta pour les contributions open-source. **10 étapes :** Search KB → Codebase Analysis → Issue Diagnosis → Impact Analysis → Write Fix + Tests → Run Tests → Code Review → Create PR + Comment Issue → QA Verification → Store Fix Pattern Inclut une Impact Analysis obligatoire (grep de tous les consommateurs en aval des données modifiées) et le protocole PRE-FIX (lire CONTRIBUTING.md, 5 PRs récentes, identifier les conventions). new-feature-v1 [#new-feature-v1] Pour construire de nouvelles features avec délégation aux spécialistes. Chaque étape a un agent spécialiste assigné. **10 étapes :** Search KB → Requirements Analysis → Schema + Backend (dev-convex-expert) → API/External Services (dev-fal-expert) → Frontend UI (dev-frontend) → i18n (translator) → Tests + QA (dev-qa) → Code Review (code-reviewer) → PR + Deploy Preview → Store Pattern KB Outils MCP [#outils-mcp] get_mission_template [#get_mission_template] ```json { "name": "issue-resolution-v2" } ``` update_mission_template [#update_mission_template] ```json { "name": "repo-fix-v1", "steps": [ { "title": "Search KB", "description": "...", "tags": ["kb"] } ], "createdBy": "carol" } ``` Créer des modèles personnalisés [#créer-des-modèles-personnalisés] Les modèles sont stockés dans la table `missionTemplates`. Chaque modèle a : | Champ | Type | Description | | ------------- | ------- | -------------------------------------------------- | | `name` | string | Nom unique du modèle | | `description` | string | À quoi sert ce modèle | | `steps` | array | Liste ordonnée de définitions de tâches | | `isDefault` | boolean | Si c'est le modèle par défaut pour l'auto-création | | `createdBy` | string | Qui l'a créé/mis à jour | --- # Signatures d'orchestrateur URL: /fr/docs/infrastructure/signatures Signatures d'orchestrateur [#signatures-dorchestrateur] Chaque commit, PR et commentaire GitHub de l'équipe VantageOS inclut une signature standardisée. Cela est appliqué mécaniquement via des hooks git et des hooks Claude Code. Format de signature [#format-de-signature] ``` Orchestrator: Sigma — VantageOS Team Infra | 2026-04-06 14:32 ``` | Composant | Description | | ----------------------- | ----------------------------------- | | `Orchestrator: {Nom}` | Nom de l'orchestrateur en majuscule | | `VantageOS Team {Rôle}` | Suffixe d'équipe selon le rôle | | `AAAA-MM-JJ HH:MM` | Date et heure du commit/action | Rôles d'équipe [#rôles-déquipe] | Orchestrateur | Suffixe d'équipe | | ------------- | ----------------------- | | Pi | VantageOS Team Lead | | Sigma | VantageOS Team Infra | | Omega | VantageOS Team Dev | | Tau | VantageOS Team Frontend | | Phi | VantageOS Team Product | | Zeta | VantageOS Team Dev | Hook de commit [#hook-de-commit] Un hook git `commit-msg` automatiquement : 1. Remplace `Co-Authored-By: Claude...` par la signature VantageOS 2. Supprime les lignes `Generated with Claude Code` et l'emoji robot 3. Détecte l'orchestrateur depuis le chemin du workspace Installé sur tous les dépôts via `scripts/install-commit-hook.sh`. Hook de description PR [#hook-de-description-pr] Un hook PreToolUse sur `Bash` intercepte les commandes `gh pr create` et supprime le branding Claude Code du body de la PR avant l'envoi à GitHub. Auto-commentaires GitHub [#auto-commentaires-github] Le webhook poste des commentaires signés sur les issues GitHub aux étapes clés de l'IRP : * **T1 (Acknowledge) :** « Investigating — assigned to `{orchestrator}` » * **T6 (Bug reproduit) :** « Bug reproduced in test suite » * **T8 (Fix prêt) :** « Fix ready. All tests pass » * **T11 (Déployé) :** « Fixed and deployed to production » Chaque commentaire se termine par la signature VantageOS. Installation [#installation] Le hook de commit est installé automatiquement lors du setup du workspace. Pour installer manuellement : ```bash bash scripts/install-commit-hook.sh ``` Cela installe le hook sur tous les dépôts du VPS. Le hook détecte automatiquement l'orchestrateur depuis le chemin du workspace. --- # Créer des missions URL: /fr/docs/missions/creating-missions Créer des missions [#créer-des-missions] Cette page couvre le cycle de vie complet d'une mission, de la création à la clôture liée à des preuves. Tous les exemples utilisent les noms d'outils MCP tels qu'ils sont appelés depuis Claude Code. Créer la mission [#créer-la-mission] Appelez `create_mission` avec l'identité de la mission, le pilote, les agents et le statut initial. Commencez en `plan` sauf si vous ne faites que capturer une idée (utilisez `brainstorm` pour cela). ```ts mcp__vantage-peers__create_mission({ name: "doc-completion-cedric", description: "Livrer les docs d'onboarding Cedric de bout en bout : audit, écriture, révision, publication.", pilot: "sigma", agents: ["dev-fumadocs-expert", "eta"], status: "plan", priority: "urgent", project: "vantage-peers-site", brief: "Cedric démarre lundi. Les docs doivent couvrir les missions, tâches et la recherche. Eta révise avant publication.", createdBy: "sigma" }) // retourne : "k57abc123..." (le missionId) ``` Sauvegardez le `missionId` retourné — vous en aurez besoin pour chaque appel ultérieur. Ajouter des tâches liées à la mission [#ajouter-des-tâches-liées-à-la-mission] Créez une tâche par phase. Définissez `missionId` sur chaque tâche. Utilisez `dependsOn` pour exprimer le séquençage — listez les IDs des tâches qui doivent atteindre `done` avant que cette tâche puisse commencer. ```ts // T0 — pas de dépendances, démarre immédiatement const t0 = mcp__vantage-peers__create_task({ title: "Auditer les docs existants", description: "Identifier les lacunes dans le contenu /docs actuel. Sortie : liste des pages manquantes.", assignedTo: "sigma", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", status: "todo", createdBy: "sigma" }) // t0 = "kTASK_T0" // T1 — dépend de T0 const t1 = mcp__vantage-peers__create_task({ title: "Écrire les nouvelles pages", description: "Écrire toutes les pages identifiées lors de l'audit. Fumadocs MDX, EN + FR.", assignedTo: "dev-fumadocs-expert", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", dependsOn: ["kTASK_T0"], status: "todo", createdBy: "sigma" }) // t1 = "kTASK_T1" // T2 — dépend de T1 const t2 = mcp__vantage-peers__create_task({ title: "Révision Eta", description: "Eta révise toutes les nouvelles pages pour l'exactitude, l'exhaustivité et la parité EN/FR.", assignedTo: "eta", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", dependsOn: ["kTASK_T1"], status: "todo", createdBy: "sigma" }) // t2 = "kTASK_T2" // T3 — dépend de T2 const t3 = mcp__vantage-peers__create_task({ title: "Publier et annoncer", description: "Fusionner la PR, pousser en prod, annoncer à l'équipe.", assignedTo: "sigma", priority: "urgent", project: "vantage-peers-site", missionId: "k57abc123", dependsOn: ["kTASK_T2"], status: "todo", createdBy: "sigma" }) ``` La chaîne de dépendances : T0 → T1 → T2 → T3. Chaque tâche ne peut commencer qu'après la clôture de son prédécesseur. Démarrer la mission [#démarrer-la-mission] Une fois les tâches définies, faites passer la mission de `plan` à `execute`. Cela signale à tous les agents que le travail actif doit commencer. ```ts mcp__vantage-peers__update_mission_status({ missionId: "k57abc123", status: "execute" }) ``` Déléguer le travail aux sous-agents [#déléguer-le-travail-aux-sous-agents] Deux patterns selon que vous déléguez en ligne ou via une nouvelle session d'agent : Démarrez la première tâche et travaillez-la directement dans la session actuelle : ```ts mcp__vantage-peers__start_task({ taskId: "kTASK_T0" }) // ... faire le travail ... mcp__vantage-peers__complete_task({ taskId: "kTASK_T0", completionNote: "Audit terminé. 6 pages manquantes trouvées : missions/index, missions/what-is-a-mission, missions/when-to-use, missions/creating-missions, missions/templates, missions/examples. Consignées dans analysis/doc-gaps-2026-05-29.md" }) ``` Déléguez une phase à un sous-agent en lançant une nouvelle session d'agent avec le contexte de la tâche : ```ts // Lancer un agent fumadocs-expert pour écrire les pages Agent({ subagent_type: "dev-fumadocs-expert", prompt: `Tu écris la section /docs/missions pour vantage-peers-site. Mission : k57abc123 (doc-completion-cedric) Tâche : kTASK_T1 — Écrire les nouvelles pages. Démarre la tâche avec start_task, complète toutes les pages, puis complete_task avec preuve (PR# ou commit SHA).` }) ``` Suivre la progression [#suivre-la-progression] Vérifiez l'état de la mission et des tâches liées à tout moment : ```ts // Obtenir l'aperçu de la mission mcp__vantage-peers__get_mission({ missionId: "k57abc123" }) // retourne : { name, status, progress, pilot, agents, ... } // Lister toutes les tâches dans la mission mcp__vantage-peers__list_tasks_by_mission({ missionId: "k57abc123" }) // retourne : tableau de docs de tâches avec statut actuel // Mettre à jour la progression manuellement après la clôture d'une phase mcp__vantage-peers__update_mission_progress({ missionId: "k57abc123", progress: 50 }) ``` Clôturer avec preuves [#clôturer-avec-preuves] Chaque tâche doit se clôturer avec un `completionNote` citant des preuves vérifiables avant que la mission puisse se compléter. Ensuite, faites passer la mission à `validate` (pour une porte de révision) ou directement à `complete`. ```ts // Clôturer la tâche de révision avec preuve mcp__vantage-peers__complete_task({ taskId: "kTASK_T2", completionNote: "[ETA-APPROVED] PR #127 révisée. 12 nouveaux fichiers MDX (6 EN + 6 FR). 0 liens cassés. Build vert. Commit sha : a1b2c3d." }) // Passer la mission à validate mcp__vantage-peers__update_mission_status({ missionId: "k57abc123", status: "validate" }) // Après confirmation finale, clôturer la mission mcp__vantage-peers__update_mission_status({ missionId: "k57abc123", status: "complete" }) // Définir la progression à 100 mcp__vantage-peers__update_mission_progress({ missionId: "k57abc123", progress: 100 }) ``` Référence des outils [#référence-des-outils] Les six chemins de fonctions de mission, avec un résumé des arguments et des références croisées. | Outil | Arguments principaux | Retourne | Notes | | ------------------------- | ----------------------------------------------------------------------- | -------------------------------- | ------------------------------------------------------------------------- | | `create_mission` | `name`, `project`, `status`, `priority`, `pilot`, `agents`, `createdBy` | `missionId` (string) | `brief`, `description`, `startDate`, `targetDate` optionnels | | `get_mission` | `missionId` | Doc complet de mission ou `null` | Retourne `null` si non trouvé — vérifiez avant de continuer | | `list_missions` | `project?`, `pilot?`, `status?`, `limit?`, `fields?` | Tableau de missions | `fields="lite"` pour projection compacte ; alias `status="open"` supporté | | `update_mission` | `missionId` + tout champ mutable | `null` | Mise à jour partielle — seuls les champs fournis sont patchés | | `update_mission_status` | `missionId`, `status` | `null` | Raccourci — définit le statut + updatedAt de manière atomique | | `update_mission_progress` | `missionId`, `progress` (0–100) | `null` | Raccourci — définit la progression + updatedAt de manière atomique | Pour le schéma complet des arguments et les types de retour, voir [Référence des outils](/docs/tools). `list_missions` se limite automatiquement à `limit=30` quand `fields="full"` et qu'aucune limite explicite n'est définie. Si vous avez besoin de plus de résultats, passez un `limit` explicite ou utilisez `fields="lite"` (limite par défaut de 50). Utiliser le raccourci de template [#utiliser-le-raccourci-de-template] Si votre mission correspond à un template connu (ex. résolution d'issue, onboarding, build d'extension Chrome), vous pouvez ignorer la création manuelle des tâches en appelant `instantiate_template_into_mission` : ```ts // 1. Créer la coquille de mission const missionId = mcp__vantage-peers__create_mission({ name: "fix-issue-142", project: "vantage-memory", status: "plan", priority: "high", pilot: "proxima", agents: ["proxima"], createdBy: "proxima" }) // 2. Instancier le template IRP (9 tâches, pré-câblées avec dependsOn) mcp__vantage-peers__instantiate_template_into_mission({ templateName: "issue-resolution-v3", missionId, context: { issueNumber: "142", repo: "vantage-memory" }, callerOrchestrator: "proxima" }) // retourne : { taskIds: [...], count: 9 } ``` Voir [Templates de missions](/docs/missions/templates) pour le catalogue complet des templates. --- # Exemples de missions URL: /fr/docs/missions/examples Exemples de missions [#exemples-de-missions] *** Exemple 1 : Lancement client (petite mission, 4 tâches) [#exemple-1--lancement-client-petite-mission-4-tâches] **Scénario :** Intégrer le client Acme Corp — appel de lancement, document de périmètre, premier livrable, rapport de statut. **Profil de mission :** 4 tâches séquentielles, pilote unique. Séquençage [#séquençage] ``` T0 appel-de-lancement [pas de dépendances] ↓ T1 document-perimetre [dependsOn: T0] ↓ T2 premier-livrable [dependsOn: T1] ↓ T3 rapport-statut [dependsOn: T2] ``` Appels d'outils [#appels-doutils] ```ts // 1. Créer la mission const missionId = mcp__vantage-peers__create_mission({ name: "kickoff-client-acme", description: "Intégrer Acme Corp : appel de lancement, doc de périmètre, premier livrable, rapport de statut.", pilot: "sigma", agents: ["sigma", "dev-general"], status: "plan", priority: "high", project: "acme-corp", brief: "Contact Acme : Marie. Lancement confirmé. Premier livrable = wireframe landing page.", createdBy: "sigma" }) // missionId = "kMISS_ACME" // 2. Créer les tâches const t0 = mcp__vantage-peers__create_task({ title: "Appel de lancement avec Acme", description: "Animer 1h d'appel de lancement. Enregistrer les résultats. Noter les bloqueurs et questions ouvertes.", assignedTo: "sigma", priority: "high", project: "acme-corp", missionId: "kMISS_ACME", status: "todo", createdBy: "sigma" }) // t0 = "kT_ACME_0" const t1 = mcp__vantage-peers__create_task({ title: "Rédiger le document de périmètre", description: "Basé sur les notes de lancement : objectifs, livrables, calendrier, budget, hors périmètre.", assignedTo: "sigma", priority: "high", project: "acme-corp", missionId: "kMISS_ACME", dependsOn: ["kT_ACME_0"], status: "todo", createdBy: "sigma" }) const t2 = mcp__vantage-peers__create_task({ title: "Livrer le wireframe landing page", description: "Wireframe Figma couvrant hero, fonctionnalités, pricing, CTA. Approbation client requise.", assignedTo: "dev-general", priority: "high", project: "acme-corp", missionId: "kMISS_ACME", dependsOn: ["kT_ACME_1"], status: "todo", createdBy: "sigma" }) const t3 = mcp__vantage-peers__create_task({ title: "Envoyer le rapport de statut Semaine 1", description: "Rapport email : ce qui a été fait, la suite, les éventuels bloqueurs.", assignedTo: "sigma", priority: "medium", project: "acme-corp", missionId: "kMISS_ACME", dependsOn: ["kT_ACME_2"], status: "todo", createdBy: "sigma" }) // 3. Démarrer l'exécution mcp__vantage-peers__update_mission_status({ missionId: "kMISS_ACME", status: "execute" }) ``` Sortie attendue après la clôture de T0 [#sortie-attendue-après-la-clôture-de-t0] ```ts mcp__vantage-peers__complete_task({ taskId: "kT_ACME_0", completionNote: "Appel de lancement terminé le 2026-05-29. Notes dans acme/kickoff-notes-2026-05-29.md. Résultat clé : livraison du wireframe landing page confirmée, budget 5k€." }) mcp__vantage-peers__update_mission_progress({ missionId: "kMISS_ACME", progress: 25 }) ``` *** Exemple 2 : Déployer une fonctionnalité produit (mission moyenne, 12 tâches par phases) [#exemple-2--déployer-une-fonctionnalité-produit-mission-moyenne-12-tâches-par-phases] **Scénario :** Déployer la fonctionnalité "recherches sauvegardées" pour VantagePeers — spec, backend, frontend, tests, révision, déploiement. **Profil de mission :** 12 tâches en 5 phases, 2 agents (dev + eta). Structure des phases [#structure-des-phases] ``` Phase 1 — Plan (1 tâche) T0 feature-spec [pas de dépendances] Phase 2 — Build (4 tâches) T1 backend-schema [dependsOn: T0] T2 backend-mutations [dependsOn: T1] T3 frontend-ui [dependsOn: T0] ← parallèle avec T1, T2 T4 frontend-integration [dependsOn: T2, T3] Phase 3 — Test (2 tâches) T5 unit-tests [dependsOn: T4] T6 integration-tests [dependsOn: T4] Phase 4 — Révision (2 tâches) T7 code-review-eta [dependsOn: T5, T6] ← barrière : les deux tâches de test doivent d'abord se fermer T8 address-review-feedback [dependsOn: T7] Phase 5 — Déploiement (3 tâches) T9 deploy-staging [dependsOn: T8] T10 qa-staging [dependsOn: T9] T11 deploy-production [dependsOn: T10] ``` Mise en place de la mission [#mise-en-place-de-la-mission] ```ts const missionId = mcp__vantage-peers__create_mission({ name: "sigma-saved-searches-v1", description: "Déployer la fonctionnalité de recherches sauvegardées : mutations backend + UI frontend + tests + révision + déploiement.", pilot: "sigma", agents: ["zeta", "eta"], status: "plan", priority: "high", project: "vantage-peers", brief: "Recherches sauvegardées : l'utilisateur peut sauvegarder une requête de recherche avec un nom et la rappeler depuis un menu déroulant. Backend : nouvelle table savedSearches + mutations CRUD. Frontend : menu déroulant React dans la barre de recherche.", createdBy: "sigma" }) ``` Transitions de statut [#transitions-de-statut] ```ts // Plan → Execute quand T0 est terminé mcp__vantage-peers__update_mission_status({ missionId, status: "execute" }) mcp__vantage-peers__update_mission_progress({ missionId, progress: 10 }) // Après la complétion de la Phase 2 (T1–T4 terminés) mcp__vantage-peers__update_mission_progress({ missionId, progress: 40 }) // Après la complétion de la Phase 3 (T5, T6 terminés) — passer à validate mcp__vantage-peers__update_mission_status({ missionId, status: "validate" }) mcp__vantage-peers__update_mission_progress({ missionId, progress: 60 }) // Après T11 — clôturer la mission mcp__vantage-peers__complete_task({ taskId: "kT11", completionNote: "Déployé en prod le 2026-06-03. PR #211 fusionnée. 47/47 tests passent. Fonctionnalité live à /search?saved=true. Smoke test confirmé." }) mcp__vantage-peers__update_mission_status({ missionId, status: "complete" }) mcp__vantage-peers__update_mission_progress({ missionId, progress: 100 }) ``` Comment les agents se mappent aux tâches [#comment-les-agents-se-mappent-aux-tâches] ``` sigma → T0 (spec), T8 (corriger les retours de révision), T11 (déploiement prod) zeta → T1–T4 (construction), T5–T6 (tests), T9 (déploiement staging), T10 (QA) eta → T7 (revue de code) ``` Le tableau `agents: ["zeta", "eta"]` de la mission déclare qui sera déployé. Le pilote (sigma) coordonne les transferts entre les phases. *** Exemple 3 : Audit système + remédiation (grande mission, parallèle multi-agents) [#exemple-3--audit-système--remédiation-grande-mission-parallèle-multi-agents] **Scénario :** Auditer la flotte VantageOS (3 dépôts) et déployer tous les correctifs critiques. Trois tâches d'audit parallèles s'exécutent simultanément, puis une barrière, puis des tâches de correctif séquentielles, puis la QA finale. **Profil de mission :** 11 tâches, 3 orchestrateurs (proxima × auditeur, zeta × correcteur, eta × réviseur). Architecture : pattern parallèle-puis-barrière [#architecture--pattern-parallèle-puis-barrière] ``` T0 audit-vantage-memory [pas de dépendances] ─┐ T1 audit-vantage-starter [pas de dépendances] ─┤→ (phase d'audit parallèle) T2 audit-myreeldream [pas de dépendances] ─┘ ↓ BARRIÈRE (les 3 doivent se fermer) T3 compile-findings [dependsOn: T0, T1, T2] ↓ T4 fix-critical-memory [dependsOn: T3] ─┐ T5 fix-critical-starter [dependsOn: T3] ─┤→ (phase de correctifs parallèle) T6 fix-critical-reel [dependsOn: T3] ─┘ ↓ BARRIÈRE (les 3 correctifs doivent se fermer) T7 regression-tests-all [dependsOn: T4, T5, T6] T8 code-review-eta [dependsOn: T7] T9 deploy-all-fixes [dependsOn: T8] T10 final-qa-report [dependsOn: T9] ``` Mise en place de la mission [#mise-en-place-de-la-mission-1] ```ts const missionId = mcp__vantage-peers__create_mission({ name: "audit-fleet-2026-05", description: "Auditer 3 dépôts VantageOS pour les problèmes critiques, corriger tous les résultats P0/P1, QA et déploiement.", pilot: "sigma", agents: ["proxima", "zeta", "eta"], status: "plan", priority: "urgent", project: "vantageos-fleet", brief: "Audit mensuel de la flotte. Périmètre : vantage-memory, vantage-starter, myreeldream. P0 = perte de données ou sécurité. P1 = fonctionnalités cassées. Corriger tous les P0/P1 avant la porte QA.", createdBy: "sigma" }) ``` Tâches d'audit parallèles (pas de dependsOn entre elles) [#tâches-daudit-parallèles-pas-de-dependson-entre-elles] ```ts const t0 = mcp__vantage-peers__create_task({ title: "Auditer vantage-memory", description: "Audit complet : schéma, mutations, logs d'erreurs, issues ouvertes. Sortie : findings-vantage-memory.md", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, status: "todo", createdBy: "sigma" }) // Note : pas de dependsOn — démarre immédiatement en parallèle const t1 = mcp__vantage-peers__create_task({ title: "Auditer vantage-starter", description: "Audit complet : dépendances, config de déploiement, issues ouvertes. Sortie : findings-vantage-starter.md", assignedTo: "zeta", priority: "urgent", project: "vantageos-fleet", missionId, status: "todo", createdBy: "sigma" // pas de dependsOn — parallèle avec T0 }) const t2 = mcp__vantage-peers__create_task({ title: "Auditer myreeldream", description: "Audit complet : intégrations API, taux d'erreur, issues ouvertes. Sortie : findings-myreeldream.md", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, status: "todo", createdBy: "sigma" // pas de dependsOn — parallèle avec T0, T1 }) ``` Tâche barrière [#tâche-barrière] ```ts const t3 = mcp__vantage-peers__create_task({ title: "Compiler les résultats d'audit", description: "Fusionner les 3 docs de résultats. Prioriser P0/P1. Assigner les correctifs aux agents. Sortie : audit-consolidated-2026-05.md", assignedTo: "sigma", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t0, t1, t2], // BARRIÈRE — les 3 audits doivent se terminer d'abord status: "todo", createdBy: "sigma" }) ``` Tâches de correctifs parallèles (même barrière, pas de dependsOn mutuels) [#tâches-de-correctifs-parallèles-même-barrière-pas-de-dependson-mutuels] ```ts // T4, T5, T6 dépendent tous de T3 (la barrière) mais PAS les uns des autres const t4 = mcp__vantage-peers__create_task({ title: "Corriger P0/P1 dans vantage-memory", description: "Traiter tous les résultats P0/P1 de l'audit. PR requise. Protocole IRP applicable.", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t3], status: "todo", createdBy: "sigma" }) const t5 = mcp__vantage-peers__create_task({ title: "Corriger P0/P1 dans vantage-starter", description: "Traiter tous les résultats P0/P1 de l'audit. PR requise.", assignedTo: "zeta", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t3], // même barrière, PAS dependsOn T4 status: "todo", createdBy: "sigma" }) const t6 = mcp__vantage-peers__create_task({ title: "Corriger P0/P1 dans myreeldream", description: "Traiter tous les résultats P0/P1 de l'audit. PR requise.", assignedTo: "proxima", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t3], // même barrière, PAS dependsOn T4 ou T5 status: "todo", createdBy: "sigma" }) ``` Deuxième barrière + chaîne QA [#deuxième-barrière--chaîne-qa] ```ts const t7 = mcp__vantage-peers__create_task({ title: "Exécuter les tests de régression sur les 3 dépôts", description: "Suite de tests complète sur les 3 dépôts. Zéro régression. Documenter les résultats.", assignedTo: "zeta", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t4, t5, t6], // deuxième barrière — les 3 correctifs doivent se fermer status: "todo", createdBy: "sigma" }) const t8 = mcp__vantage-peers__create_task({ title: "Revue de code de toutes les PRs de correctifs", description: "Eta révise les 3 PRs de correctifs. Traiter les retours bloquants. Documenter [ETA-APPROVED].", assignedTo: "eta", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t7], status: "todo", createdBy: "sigma" }) const t9 = mcp__vantage-peers__create_task({ title: "Déployer tous les correctifs en production", description: "Fusionner toutes les PRs. Déployer. Smoke test sur chaque dépôt.", assignedTo: "sigma", priority: "urgent", project: "vantageos-fleet", missionId, dependsOn: [t8], status: "todo", createdBy: "sigma" }) const t10 = mcp__vantage-peers__create_task({ title: "Rédiger le rapport QA final", description: "Documenter tous les correctifs déployés, tests exécutés et état de la flotte. Stocker dans analysis/fleet-audit-2026-05-report.md", assignedTo: "sigma", priority: "high", project: "vantageos-fleet", missionId, dependsOn: [t9], status: "todo", createdBy: "sigma" }) ``` Explication du pattern clé [#explication-du-pattern-clé] Les tâches au même niveau avec le même `dependsOn` s'exécutent en **parallèle** — pas d'ordre entre elles. Les tâches qui listent plusieurs prédécesseurs dans `dependsOn` sont des **barrières** — elles bloquent jusqu'à ce que chaque prédécesseur soit `done`. ``` Parallèle : T0, T1, T2 n'ont PAS de dependsOn entre eux → fan out Barrière : T3 dependsOn [T0, T1, T2] → attend les trois → fan in Parallèle : T4, T5, T6 partagent dependsOn [T3] uniquement → fan out à nouveau Barrière : T7 dependsOn [T4, T5, T6] → deuxième fan in ``` Le pattern parallèle-puis-barrière est la façon standard de distribuer le travail entre les agents et de synchroniser avant une porte de révision. Utilisez-le chaque fois que vous avez du travail indépendant qui doit tout se terminer avant qu'une prochaine phase commence. --- # Missions URL: /fr/docs/missions Missions [#missions] Une mission est un corps de travail orchestré — un template + brief + tâches séquencées avec dépendances, géré par un pilote orchestrateur, suivi par statut. Là où une tâche est une action atomique unique ("corriger ce bug"), une mission est une livraison de bout en bout ("investiguer, corriger, tester et déployer ce bug en 9 étapes structurées"). Les missions donnent à votre flotte d'agents un cadre de référence commun : tout le monde connaît l'objectif, la séquence et la progression actuelle. Quand utiliser les missions [#quand-utiliser-les-missions] Utilisez une mission lorsqu'au moins deux des conditions suivantes sont vraies : * **Travail en plusieurs étapes** — l'objectif nécessite plus d'une action distincte, et certaines étapes doivent précéder d'autres. * **Coordination multi-agents** — différents orchestrateurs ou types de sous-agents gèrent différentes phases (dev, review, QA, déploiement). * **Complétion liée à des preuves requise** — les livrables doivent citer un commit SHA, numéro de PR, ratio de tests ou chemin de fichier avant que la mission puisse se fermer. * **Les livrables s'étendent sur 3 jours ou plus** — un effort longue durée nécessite un objet de suivi persistant pour que la progression survive aux redémarrages de session. Quand NE PAS utiliser les missions [#quand-ne-pas-utiliser-les-missions] Si le travail est une seule étape qu'un agent peut accomplir en une session, utilisez une tâche. Les missions impliquent une surcharge — attribution de pilote, cycle de vie du statut, suivi de la progression — qui est inutile pour les actions atomiques. ``` Action unique, un agent, une session → create_task Multi-étapes, multi-agents, 3+ jours → create_mission + tâches liées ``` Exemple rapide [#exemple-rapide] Sigma lance une mission "doc-completion-cedric" avec 4 tâches de phase (audit / écriture / révision / publication). Chaque tâche porte un `missionId` la reliant à la mission et un `dependsOn` pointant vers son prédécesseur. Le statut de la mission passe par `plan → execute → validate → complete` au fur et à mesure que les tâches se ferment. La progression est un pourcentage manuel mis à jour via `update_mission_progress`. ``` Mission : doc-completion-cedric [execute, 50%] T0 audit-existing-docs [done] T1 write-new-pages [in_progress] dependsOn: [T0] T2 review-by-eta [todo] dependsOn: [T1] T3 publish-and-announce [todo] dependsOn: [T2] ``` Pages de cette section [#pages-de-cette-section] Toutes les opérations de mission sont disponibles comme outils MCP. Voir [Référence API : Missions](/docs/tools) pour la liste complète des arguments. --- # Templates de missions URL: /fr/docs/missions/templates Templates de missions [#templates-de-missions] Qu'est-ce qu'un template de mission ? [#quest-ce-quun-template-de-mission-] Un template de mission est un squelette pré-défini : une liste nommée d'étapes, chacune avec un titre, une description, un `assignedTo` optionnel et un `dependsOn` optionnel (exprimé sous forme d'index d'étapes). Lorsque vous instanciez un template dans une mission, chaque étape devient une vraie tâche avec `missionId` défini et `dependsOn` résolu en IDs de tâches réels. Les templates vivent dans la table `missionTemplates` et sont gérés par l'équipe VantageOS. Les clients auto-hébergés peuvent définir leurs propres templates en utilisant la mutation `upsert_mission_template`. Pourquoi utiliser des templates ? [#pourquoi-utiliser-des-templates-] * **Cohérence** — chaque résolution d'issue suit le même protocole en 9 étapes, quel que soit l'orchestrateur qui le déclenche. * **Rapidité** — un seul appel `instantiate_template_into_mission` crée N tâches avec le séquençage correct. Pas de câblage manuel de `dependsOn`. * **Moins d'erreurs** — les étapes encodent des leçons chèrement apprises (exécuter les tests AVANT de corriger, écrire le test de régression EN PREMIER, créer la PR dans la même étape que le push). * **Traçabilité** — chaque tâche cite sa lignée de template via le `name` de la mission et le `name` du template. Catalogue des templates [#catalogue-des-templates] `issue-resolution-v3` (défaut) [#issue-resolution-v3-défaut] Le protocole canonique de résolution d'issues. 9 étapes (T0–T8), couvrant l'accusé de réception jusqu'à la revue de code. Auto-semé à chaque déploiement. **Objectif :** Résolution structurée et liée à des preuves des issues GitHub. **Quand utiliser :** Toute issue GitHub assignée à un orchestrateur. Le bot auto-IRP déclenche ce template automatiquement quand un log d'erreur crée une nouvelle issue. **Étapes :** | Étape | Titre | Exigence clé | | ----- | -------------------- | -------------------------------------------------------------------- | | T0 | Acknowledge | Poster automatiquement un commentaire GitHub confirmant la réception | | T1 | KB Search | Rechercher `fixPatterns` + épisodes ; documenter le résultat | | T2 | Identify & Run Tests | Exécuter les tests existants ; documenter PASS/FAIL | | T3 | Write Missing Tests | Écrire le test de régression en échec ; le committer | | T4 | Fix | Appliquer le correctif ; le test T3 doit passer | | T5 | Run ALL Tests | Suite complète ; zéro régression | | T6 | Deploy Dev + Push | `convex dev --once` ; push de la branche ; créer la PR immédiatement | | T7 | Verification Preview | Tester sur le preview ; demander la validation humaine | | T8 | Code Review | Agent reviewer + mise à jour KB avec le pattern de correctif | ```ts mcp__vantage-peers__instantiate_template_into_mission({ templateName: "issue-resolution-v3", missionId: "k57xxx", context: { issueNumber: "142", repo: "vantage-memory" }, callerOrchestrator: "proxima" }) ``` `mission-generic-v1` [#mission-generic-v1] Un template vierge pour les missions qui ne correspondent pas à un template plus spécifique. Fournit un échafaudage minimal plan / execute / validate / complete avec 4 tâches génériques. **Objectif :** Démarrer n'importe quelle mission avec une structure standard quand aucun template spécialisé ne s'applique. **Quand utiliser :** Lancement client, démarrage de projet interne, livrable orchestré ponctuel. `chrome-extension-mission-v1` [#chrome-extension-mission-v1] Construire et publier une extension Chrome de zéro. Couvre la spec, l'implémentation Manifest V3, les content scripts, le service worker en arrière-plan, l'UI popup, le packaging et la soumission au store. **Objectif :** Développement structuré d'extension Chrome de zéro à publiée. **Quand utiliser :** Tout nouveau projet d'extension Chrome assigné à Zeta ou un agent dev. `pricing-research-v1` [#pricing-research-v1] Mission de recherche tarifaire concurrentielle. Couvre le scan de marché, la matrice concurrentielle, l'analyse du modèle de tarification, le document de recommandation et la révision par les parties prenantes. **Objectif :** Produire une recommandation tarifaire défendable soutenue par des données de marché. **Quand utiliser :** Avant tout changement de prix ou lancement d'un nouveau palier de produit. `repo-fix-v1` [#repo-fix-v1] Correctif ciblé pour un bug connu dans un dépôt spécifique. Plus court que `issue-resolution-v3` — pas d'étapes d'accusé de réception automatique ou de recherche KB. À utiliser pour des correctifs rapides et bien délimités dont la cause racine est déjà connue. **Objectif :** Appliquer un correctif connu, écrire le test de régression, déployer la PR. **Quand utiliser :** Patterns de correctif déjà documentés dans `fixPatterns` ; cause racine confirmée. `new-website-build` [#new-website-build] Construction complète d'un site web du brief de design au go-live. Couvre les wireframes, la sélection de stack technique, le contenu, l'implémentation, la révision SEO, la QA en staging et le lancement. **Objectif :** Livraison de site web de bout en bout avec une checklist de transfert claire. **Quand utiliser :** Nouveau site client ou refonte majeure. `gui-iframe-embed-v1` [#gui-iframe-embed-v1] Construire le flux d'intégration iframe GUI pour VantagePeers (pattern SEP-1865). Couvre le registre de sessions backend, la validation d'origine, les composants UI, les tests d'intégration et le déploiement. **Objectif :** Implémenter l'architecture standard d'intégration iframe VP Gen UI. **Quand utiliser :** Tout client nécessitant un VP Gen UI intégré dans sa propre app. Comment instancier un template [#comment-instancier-un-template] Les templates sont instanciés via `instantiate_template_into_mission`. Cela crée une tâche par étape, patche `dependsOn` sur chaque tâche et retourne tous les IDs de tâches. ```ts // Étape 1 : créer la coquille de mission const missionId = mcp__vantage-peers__create_mission({ name: "fix-issue-255-vantage-memory", project: "vantage-memory", status: "plan", priority: "high", pilot: "proxima", agents: ["proxima"], createdBy: "proxima" }) // Étape 2 : instancier le template const result = mcp__vantage-peers__instantiate_template_into_mission({ templateName: "issue-resolution-v3", missionId, context: { issueNumber: "255", repo: "vantage-memory" }, titlePrefix: "IRP-255", // optionnel : préfixe pour chaque titre de tâche callerOrchestrator: "proxima" }) // result = { taskIds: ["kT0", "kT1", ..., "kT8"], count: 9 } // Étape 3 : démarrer la mission mcp__vantage-peers__update_mission_status({ missionId, status: "execute" }) ``` Interpolation de contexte [#interpolation-de-contexte] Les descriptions des étapes de template peuvent contenir des espaces réservés `{{key}}`. Passez un objet `context` et ils seront remplacés au moment de l'instanciation : ```ts // Description d'étape du template : // "Exécutez `npx convex dev --once` sur le dépôt {{repo}} pour vérifier la compilation." // Contexte : context: { repo: "vantage-memory", issueNumber: "255" } // Résultat dans la description de la tâche : // "Exécutez `npx convex dev --once` sur le dépôt vantage-memory pour vérifier la compilation." ``` Créer vos propres templates [#créer-vos-propres-templates] Les clients auto-hébergés peuvent définir des templates personnalisés en utilisant `upsert_mission_template` : ```ts mcp__vantage-peers__upsert_mission_template({ name: "mon-template-personnalise-v1", description: "Template de livraison personnalisé en 3 étapes.", steps: [ { title: "Périmètre", description: "Définir le périmètre et les critères d'acceptation.", assignedTo: "sigma" }, { title: "Construction", description: "Implémenter le livrable.", assignedTo: "zeta", dependsOn: [0] // dépend de l'étape 0 (Périmètre) }, { title: "Déploiement", description: "Réviser, fusionner, déployer.", assignedTo: "sigma", dependsOn: [1] // dépend de l'étape 1 (Construction) } ], isDefault: false, createdBy: "sigma" }) ``` Les templates sont stockés par déploiement. Si vous auto-hébergez VantagePeers, vos templates vivent dans votre propre déploiement Convex et ne sont pas partagés avec l'instance cloud VantageOS. --- # Qu'est-ce qu'une mission ? URL: /fr/docs/missions/what-is-a-mission Qu'est-ce qu'une mission ? [#quest-ce-quune-mission-] Une mission est un corps de travail persistant et orchestré stocké dans VantagePeers. Elle regroupe des tâches liées sous un seul objet de suivi avec un pilote, un cycle de vie du statut, un indicateur de progression et une lignée de template optionnelle. Anatomie des champs [#anatomie-des-champs] Cycle de vie du statut [#cycle-de-vie-du-statut] Les statuts de mission passent de l'idéation à la complétion. Chaque transition doit être pilotée explicitement par le pilote via `update_mission_status`. ``` brainstorm → plan → execute → validate → complete ``` | Statut | Signification | | ------------ | ---------------------------------------------------------------------------- | | `brainstorm` | Idée capturée, pas encore planifiée. Aucune tâche requise. | | `plan` | Tâches définies et séquencées. Le pilote prépare la charge de travail. | | `execute` | Travail actif en cours. Les sous-agents sont déployés. | | `validate` | Toutes les tâches terminées. Le pilote ou un évaluateur vérifie les preuves. | | `complete` | Mission clôturée avec preuves. Aucun changement ultérieur attendu. | **Alias de statut** (pour les requêtes uniquement, pas pour les écritures) : * `"open"` — s'étend en `["brainstorm", "plan", "execute", "validate"]` * `"active"` — s'étend en `["plan", "execute"]` Il n'y a pas de statut `blocked` ou `cancelled` sur les missions. Pour mettre en pause une mission, laissez-la en `plan` ou `execute` et ajoutez une note dans le `brief`. Pour l'abandonner, passez à `complete` et documentez la raison dans le brief. Comment les tâches se lient aux missions [#comment-les-tâches-se-lient-aux-missions] Chaque tâche possède un champ optionnel `missionId`. Lorsqu'il est défini, la tâche fait partie de la charge de travail de cette mission. Les tâches ont également `dependsOn` — un tableau d'IDs de tâches qui doivent atteindre le statut `done` avant que cette tâche puisse commencer. ``` Mission ──┬── Tâche A (pas de dépendances) ├── Tâche B dependsOn: [Tâche A] ├── Tâche C dependsOn: [Tâche A] └── Tâche D dependsOn: [Tâche B, Tâche C] ← barrière ``` La combinaison `missionId + dependsOn` vous donne un séquençage DAG complet dans une mission. Mission vs Tâche — tableau comparatif [#mission-vs-tâche--tableau-comparatif] | Aspect | Tâche | Mission | | ------------ | ------------------------------------------------------------- | ---------------------------------------------------------- | | Périmètre | Étape atomique unique | Corps de travail orchestré en plusieurs étapes | | Suivi | Statut uniquement | Statut + % de progression + agents + pilote + brief | | Séquençage | Aucun (les tâches sont indépendantes) | `dependsOn` chaîne les tâches dans un DAG | | Templates | Aucun | Templates de mission VR — instancier N tâches en un appel | | Idéal pour | Corriger un bug, écrire un fichier, exécuter une vérification | Livraison de bout en bout sur plusieurs jours ou équipes | | Cycle de vie | `todo → in_progress → review → done` | `brainstorm → plan → execute → validate → complete` | | Preuve | `completionNote` sur la tâche | Preuve sur chaque tâche liée + transition de statut finale | Suivi de la progression [#suivi-de-la-progression] La progression est un entier `0–100` géré manuellement. Le pilote le met à jour après des jalons significatifs (ex. après la clôture de chaque phase). Elle ne se calcule pas automatiquement à partir des statuts des tâches — le pilote est l'autorité. ```ts // Mettre à jour la progression après la clôture d'une phase mcp__vantage-peers__update_mission_progress({ missionId: "k57xxxxx", progress: 50 }) ``` Une convention courante : définir la progression par multiples de 25 pour une mission à 4 phases (25 / 50 / 75 / 100). --- # Quand utiliser les missions URL: /fr/docs/missions/when-to-use Quand utiliser les missions [#quand-utiliser-les-missions] Le test de décision [#le-test-de-décision] Parcourez ces quatre questions. Si deux réponses ou plus sont "oui", créez une mission. Si zéro ou une, créez une tâche. **Le travail comporte-t-il plus d'une étape avec des contraintes de séquençage ?** L'objectif nécessite-t-il des phases distinctes où la phase B ne peut pas démarrer avant la fin de la phase A ? Une mission vous donne `dependsOn` pour exprimer cette contrainte. Une tâche simple n'a pas de mécanisme de séquençage. Exemples oui : auditer puis écrire puis réviser ; spécifier puis construire puis tester puis déployer. Exemples non : "Mettre à jour le README", "Corriger une faute de frappe à la ligne 42". **Cela nécessite-t-il plusieurs types de sous-agents travaillant en série ou en parallèle ?** Si un agent dev écrit du code, un agent reviewer le vérifie, et un agent QA le valide — vous avez trois rôles distincts. Le tableau `agents` d'une mission les déclare tous dès le départ, indiquant clairement qui est impliqué et en quelle capacité. Exemples oui : dev + eta + qa ; fumadocs-expert + railway-expert ; auditeur + correcteur. Exemples non : un seul agent fait tout ; un seul appel d'outil suffit. **Y a-t-il un livrable mesurable et vérifiable ?** Une mission se ferme avec des preuves : un numéro de PR, un commit SHA, un ratio de tests ou une URL déployée. Si la sortie est ambiguë ("les choses vont mieux maintenant"), une tâche avec `completionNote` suffit. Si la sortie doit être vérifiable indépendamment, utilisez une mission et appliquez des preuves sur chaque tâche liée. Exemples oui : déployer une PR, lancer une fonctionnalité, publier un rapport. Exemples non : "Examiner l'erreur", "Vérifier si X fonctionne". **Va-t-il s'étendre sur plusieurs jours ou plusieurs sessions ?** Les sessions se terminent ; le contexte se réinitialise. Une mission persiste dans VantagePeers à travers les sessions. Le pilote peut reprendre exactement là où il s'était arrêté en appelant `get_mission` et `list_tasks_by_mission`. Une tâche qui s'étend sur plus d'une session risque d'être perdue à moins de faire partie d'une mission. Exemples oui : construction de fonctionnalité sur 3 jours, audit d'une semaine, élément de roadmap multi-sprint. Exemples non : "Corriger et pousser dans cette session", "Exécution de script ponctuelle". Matrice de décision rapide [#matrice-de-décision-rapide] | Scénario | Verdict | | ------------------------------------------------------------------------- | ---------------------------------------------------- | | Agent unique, une session, résultat atomique | Tâche | | Deux agents, un transfert, même journée | Tâche (ou mission si preuve requise) | | Trois phases, deux agents, 2 jours | Mission | | Fonctionnalité complète de la spec au déploiement | Mission | | Correction de bug (1 fichier, pattern connu) | Tâche | | Correction de bug nécessitant audit + fix + test de régression + revue PR | Mission (utilisez le template `issue-resolution-v3`) | | Note de standup hebdomadaire | Tâche (ou tâche récurrente) | | Intégration d'un nouveau client | Mission | Signaux pour escalader d'une tâche vers une mission [#signaux-pour-escalader-dune-tâche-vers-une-mission] Parfois, vous démarrez avec une tâche et découvrez en cours de route qu'elle a grandi. Voici les signaux pour vous arrêter, créer une mission et relier la tâche originale sous celle-ci : **Dérive du périmètre** — La description de la tâche a été modifiée trois fois ou plus, chaque fois en élargissant le périmètre. L'estimation originale n'est plus réaliste. **Plusieurs PRs nécessaires** — La tâche nécessite maintenant des changements sur plus d'un dépôt ou plus de deux fichiers. Une seule `completionNote` ne peut pas capturer la piste de preuves complète. **Dépendance bloquante** — Une autre tâche ou personne attend ce travail. Le statut d'une mission rend la relation de blocage visible pour toute l'équipe. **Porte de révision requise** — La sortie doit être vérifiée par Eta ou un autre orchestrateur avant de se fermer. Une mission vous permet de modéliser l'étape de validation explicitement plutôt que de laisser la révision implicite dans un commentaire de tâche. **Des jours ont passé sans clôture** — Si une tâche est `in_progress` depuis plus de 48 heures, elle cache probablement des sous-étapes qui devraient être explicites. Convertissez-la en mission et exposez ces étapes comme tâches liées. L'escalade d'une tâche vers une mission ne nécessite pas de supprimer la tâche originale. Créez la mission, définissez `missionId` sur la tâche originale, puis créez les tâches restantes comme éléments frères. La tâche originale devient T0 dans la nouvelle mission. Anti-patterns à éviter [#anti-patterns-à-éviter] **Mission pour chaque tâche** — Toutes les actions n'ont pas besoin de la surcharge d'orchestration. La sur-utilisation des missions crée du bruit et enterre les vrais signaux. Réservez les missions pour les travaux qui nécessitent véritablement du séquençage, de la coordination multi-agents ou de la persistance multi-jours. **Mission sans brief** — Une mission sans `brief` ni `description` est une boîte noire. Quiconque la reprend à froid n'a aucune idée de ce à quoi ressemble le succès. Écrivez toujours au moins une phrase. **Dérive du pilote** — Une mission qui commence avec un pilote et est silencieusement transférée à un autre sans appel `update_mission` perd sa responsabilité. Mettez à jour `pilot` explicitement lors du transfert de propriété. --- # Guide du consommateur URL: /fr/docs/paradigm-b/consumer-guide Guide du consommateur [#guide-du-consommateur] Ce guide couvre la façon dont trois consommateurs de référence intègrent le Paradigme B. Chacun a une architecture différente, mais tous trois partagent le même patron `parseToolResult` + validation Zod + switch de rendu. Patron d'intégration commun [#patron-dintégration-commun] Tous les consommateurs suivent ce flux en trois étapes : **Intercepter** : capturer le texte brut d'une réponse d'outil MCP ou d'un résultat d'appel direct Convex. **Parser** : appeler `parseToolResult(text)` — retourne un `VpToolResult` validé ou `null`. **Afficher** : faire un switch sur `result.kind` et dispatcher vers le renderer approprié. ```ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' import type { VpToolResult } from 'vantage-peers-mcp/ui-resources/schemas' function gererReponseOutil(texteBreut: string): void { const result = parseToolResult(texteBreut) if (!result) { afficherTexteSimple(texteBreut) return } afficherStructure(result) } function afficherStructure(result: VpToolResult): void { switch (result.kind) { case 'tasks-table': return afficherTableauTaches(result.items) case 'messages-feed': return afficherFilMessages(result.items) case 'diary-entry': return afficherEntreeJournal(result.item) case 'mission-timeline': return afficherTimelineMissions(result.items) case 'briefing-note': return afficherNoteBriefing(result.item) case 'memory-quote': return afficherCitationMemoire(result.items) default: result satisfies never } } ``` *** Consommateur 1 : Hermes vantage-peers-extension [#consommateur-1--hermes-vantage-peers-extension] **Architecture** : Extension Claude Desktop utilisant un client Convex direct (pas MCP HTTP). Hermes s'abonne aux requêtes temps réel Convex et appelle les actions Convex directement. **Points d'intégration** : Hermes reçoit les résultats des appels d'outils via l'API d'utilisation d'outils de Claude Desktop. Quand `VP_EMIT_UI_MARKERS=1`, ces résultats contiennent des marqueurs intégrés. ```ts // hermes/src/tool-handler.ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' export function surResultatAppelOutil(nomOutil: string, resultatBrut: string): void { const vpResult = parseToolResult(resultatBrut) if (!vpResult) { claudeDesktop.afficherTexte(resultatBrut) return } const valide = VpToolResultSchema.safeParse(vpResult) if (!valide.success) { console.warn('[Hermes] Non-conformité schéma VpToolResult:', valide.error) claudeDesktop.afficherTexte(resultatBrut) return } // Rendu via injection Shadow DOM const hote = document.createElement('div') const shadow = hote.attachShadow({ mode: 'open' }) const uri = construireUriUi(valide.data) recupererRessourceUi(uri).then((html) => { shadow.innerHTML = html claudeDesktop.afficherWidget(hote) }) } ``` Hermes utilise un **rendu en deux passes** : il parse le marqueur pour obtenir les métadonnées kind/count immédiatement, puis récupère le HTML complet depuis la ressource `ui://` pour le rendu final. *** Consommateur 2 : Panneau latéral Mu vantage-bridge [#consommateur-2--panneau-latéral-mu-vantage-bridge] **Architecture** : Extension navigateur avec panneau latéral se connectant via transport MCP HTTP (Streamable HTTP). Mu communique avec le serveur MCP VantagePeers déployé sur Railway. **Intégration** : Mu intercepte toutes les réponses `tools/call` de la connexion MCP HTTP et les fait passer par `parseToolResult`. ```ts // mu/src/mcp-bridge.ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' export async function appelerOutil( nomOutil: string, args: Record ): Promise { const reponse = await clientMcpHttp.callTool({ name: nomOutil, arguments: args }) const texteBreut = reponse.content .filter((c) => c.type === 'text') .map((c) => c.text) .join('\n') const vpResult = parseToolResult(texteBreut) if (vpResult) { panneauLateral.postMessage({ type: 'VP_PRIMITIVE', payload: vpResult }) } else { panneauLateral.postMessage({ type: 'TEXT', payload: texteBreut }) } } ``` *** Consommateur 3 : Registry json-render [#consommateur-3--registry-json-render] **Architecture** : Le Registry VantagePeers est un workflow natif Convex. Après les appels d'outils, il utilise l'extraction de marqueurs post-appel pour persister les données structurées et afficher des résumés compacts dans sa propre interface. **Intégration** : Le Registry traite les résultats d'actions Convex (pas les réponses MCP). Quand un outil émet automatiquement un marqueur, le Registry l'extrait pour construire un résumé JSON dans son journal d'activité. ```ts // registry/src/tool-result-processor.ts import { parseToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' export function extraireEtJournaliser( nomOutil: string, resultatBrut: string, idSession: string ): void { const vpResult = parseToolResult(resultatBrut) if (!vpResult) { journalActivite.push({ idSession, nomOutil, type: 'text', apercu: resultatBrut.slice(0, 200) }) return } const parse = VpToolResultSchema.parse(vpResult) const meta = extraireMeta(parse) journalActivite.push({ idSession, nomOutil, type: 'structured', kind: parse.kind, nombre: meta.nombre, apercu: meta.apercu, payload: parse, }) } ``` *** Choisir la bonne approche [#choisir-la-bonne-approche] | Scénario | Approche recommandée | | -------------------------------------------- | --------------------------------------------------------------- | | Besoin du HTML complet avec CSS (Shadow DOM) | Récupérer la ressource `ui://` après le parsing du marqueur | | Besoin uniquement des données structurées | Utiliser `parseToolResult` + `VpToolResultSchema` directement | | Journal d'audit à fort volume | Patron Registry : extraire les métadonnées, persister `payload` | | Panneau latéral temps réel | Patron Mu : bridge post-message entre client MCP et renderer | | Extension desktop avec Convex direct | Patron Hermes : deux passes (métadonnées marqueur + HTML ui://) | Utilisez toujours `parseToolResult` du package npm — ne réimplémentez pas la logique de parsing des marqueurs. Les tokens délimiteurs (`__VP_TOOL_RESULT__` / `__END__`) sont stables dans la v2.x mais seront versionnés en v3. Utilisez le package pour une compatibilité automatique. --- # Paradigme B — Ressources ui:// URL: /fr/docs/paradigm-b Paradigme B — Ressources ui:// [#paradigme-b--ressources-ui] VantagePeers prend en charge deux paradigmes d'interface générative distincts. Cette section couvre le **Paradigme B**, l'approche native MCP introduite dans la SEP-1865 et livrée dans `vantage-peers-mcp@2.4.0`. Les deux paradigmes en bref [#les-deux-paradigmes-en-bref] | | Paradigme A | Paradigme B | | --------------- | ---------------------------------- | ---------------------------------------- | | **Hôte** | Application Theta Next.js | Tout consommateur MCP | | **Transport** | iframe + relais Clerk SSO | Protocole de ressources MCP `ui://` | | **Auth** | Propagation de session Clerk SSO | Jeton Bearer via serveur MCP | | **Rendu** | iframe (contrôle total de la page) | HTML inline scopé Shadow DOM | | **Template VR** | `gui-iframe-embed-v1` v1.1.0 §2.5 | SEP-1865 | | **Statut** | Déploiement Theta | Validé par Sigma, EN PRODUCTION (v2.4.0) | Le Paradigme A offre une surface Next.js hébergée par Theta avec un contrôle design complet et l'authentification Clerk SSO. Le Paradigme B donne à chaque consommateur MCP (Hermes, Mu, Registry, Claude Desktop) l'accès à des primitives UI structurées sans infrastructure d'hébergement supplémentaire. Arbre de décision [#arbre-de-décision] ``` Avez-vous besoin d'une interface web authentifiée complète (pages de connexion, navigation complexe) ? ├── Oui → Paradigme A (iframe embed Theta, gui-iframe-embed-v1 v1.1.0 §2.5) └── Non │ Vos consommateurs MCP ont-ils besoin de vues structurées inline riches (tableaux de tâches, fils de messages, journal, missions) ? ├── Oui → Paradigme B (ressources ui://, cette section) └── Non → Les réponses textuelles des outils suffisent ``` **Choisissez le Paradigme B lorsque :** * Vous construisez une extension Claude Desktop, un panneau latéral ou un bridge MCP * Vous voulez une sortie structurée visuelle sans déployer un hôte web * Vos consommateurs parlent déjà MCP (resources/read, resources/list) * Vous avez besoin de HTML conforme WCAG AA, sécurisé contre les XSS, bilingue (FR/EN) livré en ligne **Choisissez le Paradigme A lorsque :** * Une mise en page complète et la session Clerk SSO sont requises * Vous avez besoin d'un routage d'URL approfondi et d'un état de navigation * Le template VR `gui-iframe-embed-v1` v1.1.0 est déjà dans votre stack (voir §2.5) Ce qui est inclus dans le Paradigme B [#ce-qui-est-inclus-dans-le-paradigme-b] 6 primitives ui:// [#6-primitives-ui] Toutes les primitives sont servies sous le schéma URI `ui://vp/v1/?`. | Primitive | URI | Source de données | | ------------------ | ----------------------------- | ----------------------- | | `tasks-table` | `ui://vp/v1/tasks-table` | `tasks:list` | | `messages-feed` | `ui://vp/v1/messages-feed` | `messages:listMessages` | | `diary-entry` | `ui://vp/v1/diary-entry` | `diary:getEntry` | | `mission-timeline` | `ui://vp/v1/mission-timeline` | `missions:list` | | `briefing-note` | `ui://vp/v1/briefing-note` | `briefingNotes:get` | | `memory-quote` | `ui://vp/v1/memory-quote` | `memories:search` | Chaque primitive retourne du HTML inline avec du CSS intégré, scopé pour le rendu Shadow DOM. La sortie est conforme WCAG AA et bilingue (FR/EN via `?lang=fr`). Schémas Zod [#schémas-zod] Tous les payloads sont validés avec des unions discriminées Zod avant l'émission. Importez depuis : ```ts import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' import type { VpToolResult } from 'vantage-peers-mcp/ui-resources/schemas' ``` Helpers de marqueurs de flux [#helpers-de-marqueurs-de-flux] Lorsque `VP_EMIT_UI_MARKERS=1` est défini sur votre déploiement Convex, les réponses des outils intègrent automatiquement des marqueurs structurés : ``` __VP_TOOL_RESULT__{"kind":"tasks-table","items":[...]}__END__ ``` Parsez-les avec : ```ts import { parseToolResult, wrapToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' ``` Prérequis [#prérequis] Le Paradigme B requiert `vantage-peers-mcp@2.4.0` ou supérieur et `VP_EMIT_UI_MARKERS=1` dans les variables d'environnement Convex pour l'émission automatique sur les réponses des outils. Installez ou mettez à jour le package du serveur MCP : ```bash npm install vantage-peers-mcp@^2.4.0 ``` Définissez la variable d'environnement dans votre tableau de bord Convex (Paramètres → Variables d'environnement) : ``` VP_EMIT_UI_MARKERS=1 ``` Consultez la [référence des variables d'environnement](/docs/infrastructure/deploy-keys) pour tous les détails. Vérifiez que le serveur MCP expose les ressources `ui://` en appelant `resources/list` — vous devriez voir 6 entrées avec des URI correspondant à `ui://vp/v1/*`. Contenu de la section [#contenu-de-la-section] --- # Marqueur de flux URL: /fr/docs/paradigm-b/stream-marker Marqueur de flux [#marqueur-de-flux] Le marqueur de flux `__VP_TOOL_RESULT__` est un protocole texte léger intégré dans les réponses des outils MCP. Il permet aux consommateurs en aval (Claude Desktop, Hermes, panneau latéral Mu, Registry) de détecter et d'afficher des primitives UI structurées en ligne, sans appel séparé à `resources/read`. Format du marqueur [#format-du-marqueur] ``` __VP_TOOL_RESULT____END__ ``` Où `` est un objet JSON sérialisé conforme à `VpToolResultSchema` (une union discriminée Zod avec un discriminateur `kind`). Le JSON est minifié (sans espaces). **Exemple complet — tasks-table :** ``` __VP_TOOL_RESULT__{"kind":"tasks-table","items":[{"_id":"j97abc","title":"Corriger le bug d'auth","status":"in_progress","priority":"high","assignedTo":"sigma"}]}__END__ ``` Le marqueur n'est émis que lorsque `VP_EMIT_UI_MARKERS=1` est défini dans l'environnement Convex. Quand la variable est absente (par défaut), les réponses des outils sont en texte brut — les intégrations existantes ne sont pas affectées. VpToolResultSchema — Union discriminée [#vptoolresultschema--union-discriminée] Six types, un par primitive. Importez depuis `vantage-peers-mcp/ui-resources/schemas` : ```ts import { VpToolResultSchema } from 'vantage-peers-mcp/ui-resources/schemas' import type { VpToolResult } from 'vantage-peers-mcp/ui-resources/schemas' ``` Type : `tasks-table` [#type--tasks-table] ```ts { kind: 'tasks-table', items: Array<{ _id: string title: string status: string priority?: string assignedTo?: string _creationTime?: number }> } ``` Type : `messages-feed` [#type--messages-feed] ```ts { kind: 'messages-feed', items: Array<{ _id: string from: string channel?: string content: string createdAt: number }> } ``` Type : `diary-entry` [#type--diary-entry] ```ts { kind: 'diary-entry', item: { _id: string date: string // YYYY-MM-DD orchestrator: string content: string highlights?: string[] blockers?: string[] } } ``` Note : `diary-entry` utilise `item` (singulier), pas `items`. Type : `mission-timeline` [#type--mission-timeline] ```ts { kind: 'mission-timeline', items: Array<{ _id: string name: string project?: string status: string pilot?: string priority?: string progress?: number // 0–100 }> } ``` Type : `briefing-note` [#type--briefing-note] ```ts { kind: 'briefing-note', item: { _id: string topic: string title: string participants?: string[] content?: string createdBy?: string } } ``` Note : `briefing-note` utilise `item` (singulier). Type : `memory-quote` [#type--memory-quote] ```ts { kind: 'memory-quote', items: Array<{ _id: string namespace: string type: string content: string score?: number }> } ``` Helpers [#helpers] Importez les deux helpers depuis `vantage-peers-mcp/ui-resources/stream-marker` : ```ts import { wrapToolResult, parseToolResult, MARKER_START, MARKER_END, } from 'vantage-peers-mcp/ui-resources/stream-marker' ``` `wrapToolResult(payload: VpToolResult): string` [#wraptoolresultpayload-vptoolresult-string] Valide `payload` contre `VpToolResultSchema`, puis sérialise au format marqueur. Lève une `TypeError` si la validation échoue. ```ts const marker = wrapToolResult({ kind: 'tasks-table', items: [ { _id: 'j97abc', title: 'Corriger le bug d\'auth', status: 'in_progress', priority: 'high', assignedTo: 'sigma' }, ], }) // → "__VP_TOOL_RESULT__{"kind":"tasks-table","items":[...]}__END__" ``` `parseToolResult(text: string): VpToolResult | null` [#parsetoolresulttext-string-vptoolresult--null] Extrait et valide un marqueur VP depuis `text`. Gère trois cas : 1. `text` **est** le marqueur (brut) 2. `text` **contient** le marqueur dans du contenu environnant 3. `text` **ne contient pas** de marqueur — retourne `null` Retourne le `VpToolResult` validé en cas de succès, ou `null` en cas d'échec. Ne lève jamais d'exception. ```ts const result = parseToolResult(toolResponse) if (result === null) { afficherTexteSimple(toolResponse) } else { afficherPrimitive(result) } ``` Outils à émission automatique [#outils-à-émission-automatique] Quand `VP_EMIT_UI_MARKERS=1` est défini, les 6 outils MCP suivants ajoutent automatiquement un marqueur `__VP_TOOL_RESULT__` à leur réponse textuelle : | Outil | Type émis | | ------------------------------------- | ------------------ | | `list_tasks` | `tasks-table` | | `list_messages` / `get_messages` | `messages-feed` | | `get_diary_entry` | `diary-entry` | | `list_missions` | `mission-timeline` | | `get_briefing_note` | `briefing-note` | | `search_memories` / `recall_memories` | `memory-quote` | L'émission automatique est additive — le marqueur est ajouté après la réponse texte lisible par l'humain. Les consommateurs qui n'implémentent pas `parseToolResult` voient le texte brut du marqueur, ce qui est inesthétique mais pas nuisible. Définissez `VP_EMIT_UI_MARKERS=1` uniquement dans les déploiements où au moins un consommateur gère les marqueurs. Patron de rendu par switch [#patron-de-rendu-par-switch] Patron standard pour afficher un résultat parsé : ```ts import { parseToolResult, type VpToolResult } from 'vantage-peers-mcp/ui-resources/stream-marker' function gererReponseOutil(text: string): void { const result = parseToolResult(text) if (!result) { afficherTexteSimple(text) return } switch (result.kind) { case 'tasks-table': afficherTableauTaches(result.items) break case 'messages-feed': afficherFilMessages(result.items) break case 'diary-entry': afficherEntreeJournal(result.item) break case 'mission-timeline': afficherTimelineMissions(result.items) break case 'briefing-note': afficherNoteBriefing(result.item) break case 'memory-quote': afficherCitationMemoire(result.items) break default: result satisfies never } } ``` --- # Référence des ressources UI URL: /fr/docs/paradigm-b/ui-resources Référence des ressources UI [#référence-des-ressources-ui] Toutes les primitives du Paradigme B sont servies via le protocole de ressources MCP `ui://`. Le serveur les enregistre sous `ui://vp/v1/` et les clients les récupèrent avec `resources/read`. Schéma URI [#schéma-uri] ``` ui://vp/v1/? ``` * **Protocole** : `ui://` (URI personnalisée MCP, pas HTTP) * **Espace de noms** : `vp/v1` — versionné pour permettre des changements cassants futurs sous `v2` * **Primitive** : l'un des 6 noms enregistrés (voir tableau ci-dessous) * **Paramètres de requête** : optionnels, spécifiques à chaque primitive Exemples complets d'URI [#exemples-complets-duri] ``` ui://vp/v1/tasks-table?assignedTo=sigma&status=in_progress&limit=10 ui://vp/v1/messages-feed?from=pi&channel=fleet&limit=20 ui://vp/v1/diary-entry?orchestrator=sigma&limit=3&lang=fr ui://vp/v1/mission-timeline?pilot=tau&status=active&limit=5 ui://vp/v1/briefing-note?topic=deployment&limit=3 ui://vp/v1/memory-quote?namespace=sigma&type=feedback&limit=5 ``` Récupération via MCP [#récupération-via-mcp] ```ts // Récupération client MCP — fonctionne avec toute version MCP SDK >= 1.0 const result = await client.readResource({ uri: 'ui://vp/v1/tasks-table?assignedTo=sigma&status=review&limit=10', }) // result.contents[0].text = chaîne HTML const html = result.contents[0].text as string ``` Le `text` retourné est un fragment HTML autonome avec des balises `
Titre Statut Priorité Attribué à
Titre de ma tâche in_progress high sigma
3 tâches
``` **Classes des badges de statut** : `vp-status-todo` (bleu), `vp-status-in_progress` (jaune), `vp-status-review` (violet), `vp-status-blocked` (rouge), `vp-status-done` (vert). *** messages-feed [#messages-feed] Affiche un fil chronologique de messages VantagePeers. **URI** : `ui://vp/v1/messages-feed` **Paramètres de requête** : | Paramètre | Type | Défaut | Description | | --------- | ------------ | ------ | -------------------------------------- | | `from` | string | — | Filtrer par nom d'expéditeur | | `channel` | string | — | Filtrer par nom de canal | | `limit` | 1–200 | `20` | Nombre maximum de messages à retourner | | `lang` | `en` \| `fr` | `en` | Langue des libellés UI | **Sortie HTML** : `
` avec une liste de bulles de messages. Chaque bulle contient l'expéditeur, l'horodatage, le badge de canal (si présent) et le contenu sécurisé contre les XSS. *** diary-entry [#diary-entry] Affiche une entrée de journal structurée ou une liste d'entrées récentes. **URI** : `ui://vp/v1/diary-entry` **Paramètres de requête** : | Paramètre | Type | Défaut | Description | | -------------- | ------------ | ------ | ------------------------------------------------------------ | | `date` | `YYYY-MM-DD` | — | Récupérer l'entrée pour une date spécifique | | `orchestrator` | string | — | Filtrer par nom d'orchestrateur | | `limit` | 1–50 | `5` | Nombre maximum d'entrées lors de la récupération d'une liste | | `lang` | `en` \| `fr` | `en` | Langue des libellés UI | **Sortie HTML** : `
` avec en-tête de date, badge d'orchestrateur, bloc de contenu, liste des points forts (si présents) et liste des blocages (si présents). *** mission-timeline [#mission-timeline] Affiche une timeline verticale des missions VantagePeers. **URI** : `ui://vp/v1/mission-timeline` **Paramètres de requête** : | Paramètre | Type | Défaut | Description | | --------- | ------------ | ------ | ------------------------------------------ | | `pilot` | string | — | Filtrer par pilote (orchestrateur assigné) | | `project` | string | — | Filtrer par nom de projet | | `status` | string | — | Filtrer par statut de mission | | `limit` | 1–100 | `10` | Nombre maximum de missions à retourner | | `lang` | `en` \| `fr` | `en` | Langue des libellés UI | **Sortie HTML** : `
` avec une timeline verticale. Chaque entrée affiche le nom de la mission, le projet, le badge de statut, le pilote, la puce de priorité et la barre de progression (quand `progress` est défini). *** briefing-note [#briefing-note] Affiche une seule note de briefing ou une liste compacte de notes récentes. **URI** : `ui://vp/v1/briefing-note` **Paramètres de requête** : | Paramètre | Type | Défaut | Description | | --------- | ------------ | ------ | --------------------------------------------------------- | | `noteId` | string | — | Récupérer une note spécifique par ID Convex | | `topic` | string | — | Filtrer par sujet lors de la récupération d'une liste | | `limit` | 1–50 | `5` | Nombre maximum de notes quand aucun `noteId` n'est fourni | | `lang` | `en` \| `fr` | `en` | Langue des libellés UI | **Sortie HTML** : `
` avec badge de sujet, titre, puces de participants (quand `participants` est défini) et bloc de contenu (quand `content` est défini). *** memory-quote [#memory-quote] Affiche une liste compacte de citations mémoire depuis un espace de noms. **URI** : `ui://vp/v1/memory-quote` **Paramètres de requête** : | Paramètre | Type | Défaut | Description | | ----------- | ------------ | ------ | ------------------------------------------------------ | | `namespace` | string | — | Espace de noms mémoire à interroger | | `type` | string | — | Filtre de type mémoire (`feedback`, `reference`, etc.) | | `limit` | 1–50 | `5` | Nombre maximum de citations à retourner | | `lang` | `en` \| `fr` | `en` | Langue des libellés UI | **Sortie HTML** : `
` avec une liste de style citation. Chaque entrée affiche le badge d'espace de noms, la puce de type, le score de pertinence (quand `score` est défini) et le contenu sécurisé contre les XSS. *** Comportement commun à toutes les primitives [#comportement-commun-à-toutes-les-primitives] * **Sécurité XSS** : tout le contenu fourni par l'utilisateur passe par une fonction d'échappement HTML. Aucune interpolation brute. * **Scopage Shadow DOM** : les CSS utilisent des préfixes de classe `.vp-*` pour éviter les collisions avec les styles de la page hôte. * **WCAG AA** : tous les tableaux ont des en-têtes `scope="col"` ; les régions interactives utilisent `role` et `aria-label` ; les changements d'état utilisent `aria-live`. * **Bilingue** : tous les libellés, compteurs et noms accessibles sont traduits quand `?lang=fr` est passé. * **Frontière d'erreur** : si la requête Convex échoue, la primitive retourne un `
` d'erreur avec le message — elle ne lève jamais d'exception. Le protocole `ui://` est un schéma URI MCP personnalisé. Les clients HTTP standard (`fetch`, `axios`) ne peuvent pas l'appeler. Seuls les clients SDK MCP avec un gestionnaire `resources/read` enregistré peuvent consommer ces ressources. --- # Auto-héberger le backend Convex URL: /fr/docs/self-host/convex-backend Auto-héberger le backend Convex [#auto-héberger-le-backend-convex] VantagePeers fonctionne entièrement sur [Convex](https://convex.dev). Vous possédez le déploiement. Convex fournit la base de données, les fonctions serverless, les index vectoriels et les abonnements en temps réel. Il n'y a aucune infrastructure gérée par VantagePeers entre vos agents et vos données. Cette page vous guide à travers une configuration de nouveau projet Convex. Si vous avez déjà un projet Convex et que vous migrez du transport stdio vers HTTP, consultez [Migrer de stdio vers HTTP](/docs/self-host/migration-stdio-to-http). Prérequis [#prérequis] * **Node.js 20+** — la CLI Convex requiert Node 20 ou supérieur * **Git** — pour cloner le dépôt vantage-memory * **Un compte Convex** — niveau gratuit sur [convex.dev](https://convex.dev). Aucune carte bancaire requise. * **Une clé API OpenAI** — pour les embeddings RAG (`text-embedding-3-small`) Étape 1 : Cloner vantage-memory [#étape-1--cloner-vantage-memory] `vantage-memory` est le dépôt du backend Convex pour VantagePeers. ```bash git clone https://github.com/vantageos-agency/vantage-memory.git cd vantage-memory npm install ``` Le dépôt contient : * `convex/` — toutes les définitions de schéma, requêtes, mutations et actions (20 tables) * `mcp-server/` — le serveur MCP qui se place devant Convex (transport HTTP ou stdio) * `convex/schema.ts` — schéma canonique, source de vérité pour toutes les définitions de tables Étape 2 : S'authentifier avec Convex [#étape-2--sauthentifier-avec-convex] ```bash npx convex login ``` Cette commande ouvre une fenêtre de navigateur. Connectez-vous avec votre compte Convex. Sur une machine CI ou un serveur sans affichage, utilisez : ```bash npx convex login --no-browser ``` Suivez les instructions affichées pour terminer l'authentification. Étape 3 : Initialiser un nouveau projet Convex [#étape-3--initialiser-un-nouveau-projet-convex] ```bash npx convex dev --once ``` Au premier lancement, la CLI vous posera les questions suivantes : 1. **Créer un nouveau projet ou utiliser un existant ?** — Sélectionnez **Créer un nouveau projet**. 2. **Nom du projet** — Entrez un nom, par exemple `vantage-memory-prod`. 3. La CLI affiche votre URL de déploiement sous la forme `https://.convex.cloud`. Copiez-la. L'option `--once` déploie le schéma et les fonctions puis quitte immédiatement (sans mode watch). C'est la méthode correcte pour effectuer un déploiement d'initialisation ponctuel. Vous devriez voir une sortie similaire à : ``` ✓ Deployed schema (20 tables) ✓ Pushed 47 functions Deployment URL: https://cheerful-penguin-123.convex.cloud ``` Étape 4 : Définir les variables d'environnement dans le tableau de bord Convex [#étape-4--définir-les-variables-denvironnement-dans-le-tableau-de-bord-convex] Ouvrez [dashboard.convex.dev](https://dashboard.convex.dev), sélectionnez votre nouveau projet, et allez dans **Settings → Environment Variables**. Ajoutez chaque variable listée ci-dessous. Obligatoires [#obligatoires] | Variable | Exemple | Rôle | | ---------------------- | ------------------------ | -------------------------------------------------------------------------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | `sk-proj-...` | Clé API OpenAI pour les embeddings RAG `text-embedding-3-small`. Sans cette clé, `recall` retourne des résultats vides. | | `BEARER_SECRET_MASTER` | *(chaîne hex 32 octets)* | Token d'authentification maître pour le serveur MCP. Tous les appels d'outils sont rejetés sans lui. Générez-le avec `openssl rand -hex 32`. | Optionnelles — Authentification basée sur Clerk [#optionnelles--authentification-basée-sur-clerk] À définir uniquement si vous activez le flux d'émission de credentials Clerk JWT (`POST /issueBearerFromClerk`). Non requis pour les déploiements agent-only. | Variable | Exemple | Rôle | | ------------------------- | ----------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CLERK_JWT_ISSUER_DOMAIN` | `https://clerk.votre-app.com` | URL de base JWKS pour la vérification JWT Clerk. Requis uniquement si vous utilisez l'endpoint web d'émission de credentials. | | `VP_ALLOWED_EXT_IDS` | `ext_abc123,ext_def456` | Liste d'IDs d'extensions Clerk autorisées, séparées par des virgules. Restreint quelles extensions navigateur peuvent échanger un JWT Clerk contre un token bearer VantagePeers. | Optionnelles — Intégration GitHub [#optionnelles--intégration-github] | Variable | Exemple | Rôle | | ----------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------------------ | | `GITHUB_WEBHOOK_SECRET` | *(hex aléatoire)* | Valide les payloads de webhook GitHub entrants. Requis si vous synchronisez des issues GitHub via l'endpoint webhook. | | `GITHUB_TOKEN` | `ghp_...` | Token personnel ou d'application GitHub. Requis pour poster des commentaires IRP automatiques sur les issues et récupérer les métadonnées. | Étape 5 : Déployer en production [#étape-5--déployer-en-production] ```bash npx convex deploy ``` C'est la commande de déploiement en production. Elle compile TypeScript, valide le schéma, et pousse les 20 tables et fonctions vers votre déploiement Convex. > **Note pour les déploiements en flotte :** Dans le workflow de flotte interne VantagePeers, les déploiements en production nécessitent un verrou `PI_AUTHORIZED_TASK_ID` appliqué par un hook pre-commit. Les clients en auto-hébergement ne sont pas soumis à ce verrou — `npx convex deploy` s'exécute directement sans étape d'approbation supplémentaire. Vérifiez la réussite du déploiement dans l'onglet **Functions** du tableau de bord. Vous devriez voir tous les modules listés : `tasks`, `messages`, `memories`, `missions`, `briefingNotes`, `diary`, `iframeEmbedSessions`, `profiles`, `fixPatterns`, `issues`, et d'autres. Étape 6 : Initialiser les données (optionnel) [#étape-6--initialiser-les-données-optionnel] Après un déploiement initial, la base de données est vide. Vous pouvez optionnellement initialiser un profil et un espace de travail pour que les agents aient un namespace par défaut disponible immédiatement. Via la commande CLI Convex : ```bash # Créer votre profil d'orchestrateur principal npx convex run profiles:upsertProfile '{ "orchestratorId": "sigma", "displayName": "Sigma", "role": "engineer", "capabilities": ["code", "research"], "createdBy": "system" }' ``` Ou depuis votre agent, appelez l'outil MCP `update_profile` après connexion. Étape 7 : Connecter le serveur MCP [#étape-7--connecter-le-serveur-mcp] Le serveur MCP est le pont entre les agents IA et votre backend Convex. Consultez [Déploiement HTTP Railway](/docs/self-host/railway-http) pour le guide de déploiement complet. Pour un test local rapide avec le transport stdio : ```bash cd mcp-server npm install npm run build CONVEX_URL=https://votre-deployment.convex.cloud BEARER_SECRET_MASTER=votre-secret node dist/server.js ``` Puis ajoutez à votre `~/.claude.json` Claude Code : ```json { "mcpServers": { "vantage-peers": { "command": "node", "args": ["/chemin/vers/vantage-memory/mcp-server/dist/server.js"], "env": { "CONVEX_URL": "https://votre-deployment.convex.cloud", "BEARER_SECRET_MASTER": "votre-secret" } } } } ``` Étape 8 : Vérification de santé [#étape-8--vérification-de-santé] Vérifiez que tout est correctement câblé : ```bash # Doit retourner un tableau (vide sur un déploiement neuf) npx convex run profiles:list '{}' ``` Depuis votre client MCP, appelez l'outil `check_messages` : ```json { "recipient": "sigma" } ``` Résultat attendu : `[]` (tableau vide — aucun message pour l'instant). Une réponse sans erreur confirme que la connectivité Convex, l'authentification et le routage des fonctions fonctionnent tous correctement. Dépannage [#dépannage] **`AI_GATEWAY_API_KEY` non définie — embeddings désactivés** Les mémoires sont stockées correctement mais `recall` retourne des résultats vides. Définissez `AI_GATEWAY_API_KEY` dans le tableau de bord Convex et redéployez. **"Unauthorized" à chaque appel d'outil** `BEARER_SECRET_MASTER` est absent ou incohérent entre le tableau de bord Convex et l'`env` du serveur MCP. Régénérez et définissez de manière cohérente. **Erreurs de désaccord de schéma après un `git pull`** Exécutez à nouveau `npx convex deploy`. Convex applique les migrations de schéma automatiquement au déploiement — aucun script de migration manuel requis pour les changements additifs (nouvelles tables, nouveaux champs optionnels). **Index vectoriel pas encore prêt** Sur un nouveau déploiement, les index vectoriels se construisent de façon asynchrone. Si `recall` retourne des résultats vides immédiatement après le déploiement, attendez 30 à 60 secondes et réessayez. --- # Référence des variables d'environnement URL: /fr/docs/self-host/env-vars Référence des variables d'environnement [#référence-des-variables-denvironnement] VantagePeers utilise des variables d'environnement sur deux côtés distincts : le **déploiement Convex** (définies dans le tableau de bord Convex sous Settings → Environment Variables) et le **serveur MCP** (définies dans la configuration du service Railway ou dans votre shell local pour le mode stdio). Un petit nombre de variables s'appliquent aux deux côtés. Variables du tableau de bord Convex [#variables-du-tableau-de-bord-convex] Ces variables sont définies dans [dashboard.convex.dev](https://dashboard.convex.dev) → votre projet → **Settings → Environment Variables**. | Variable | Obligatoire | Exemple | Rôle | | ------------------------- | ----------- | --------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | Oui | `sk-proj-abc123...` | Clé API OpenAI utilisée exclusivement pour les embeddings RAG `text-embedding-3-small`. Sans cette clé, `storeMemory` fonctionne mais `recall` ne retourne aucun résultat. Coût typique : moins de 1€/mois. | | `BEARER_SECRET_MASTER` | Oui | *(hex 32 octets)* | Token bearer d'administration maître. Le serveur MCP présente ce token à chaque requête pour s'authentifier auprès de Convex. Générez-le avec `openssl rand -hex 32`. Ne jamais exposer aux utilisateurs finaux. | | `GITHUB_WEBHOOK_SECRET` | Non | *(hex aléatoire)* | Secret HMAC-SHA256 pour valider les payloads de webhook GitHub entrants (`X-Hub-Signature-256`). Requis uniquement si vous synchronisez des issues GitHub via l'endpoint webhook (`POST /webhooks/github`). | | `GITHUB_TOKEN` | Non | `ghp_...` | Token d'accès personnel GitHub ou token d'installation GitHub App. Requis pour poster des commentaires IRP automatiques sur les issues GitHub et appeler l'API REST GitHub depuis les actions `githubComments`. Nécessite la portée `issues:write`. | | `CLERK_JWT_ISSUER_DOMAIN` | Non | `https://clerk.mon-app.com` | URL de base de l'endpoint JWKS de votre instance Clerk. Utilisée par `credentials.ts` pour vérifier les JWT Clerk avant d'émettre des tokens bearer VantagePeers. Requis uniquement si vous exposez l'endpoint de credentials `POST /issueBearerFromClerk` aux utilisateurs finaux. | | `VP_ALLOWED_EXT_IDS` | Non | `ext_abc123,ext_def456` | Liste d'IDs d'extensions Clerk autorisées, séparées par des virgules. Restreint quelles extensions navigateur peuvent échanger un JWT Clerk contre un token bearer VantagePeers via l'endpoint d'émission de credentials. Si non défini, aucune extension n'est autorisée. | Variables du serveur MCP [#variables-du-serveur-mcp] Ces variables sont définies dans l'environnement où le processus du serveur MCP s'exécute (configuration du service Railway, bloc `env` de `~/.claude.json`, ou votre shell local). | Variable | Obligatoire | Exemple | Rôle | | ---------------------- | ----------- | ------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `CONVEX_URL` | Oui (stdio) | `https://slug.convex.cloud` | URL de votre déploiement Convex. Le serveur MCP stdio (`server.js`) l'utilise pour connecter un `ConvexHttpClient` à chaque appel d'outil. Non utilisé par le serveur HTTP — celui-ci utilise `CONVEX_URL_INTERNAL`. | | `CONVEX_URL_INTERNAL` | Oui (HTTP) | `https://slug.convex.cloud` | URL Convex pour le déploiement interne VantagePeers. Utilisée par le serveur MCP HTTP (`server-http.js`) pour résoudre le routage des tenants et valider les tokens OAuth. Doit être définie pour que le transport HTTP fonctionne. | | `BEARER_SECRET_MASTER` | Oui | *(hex 32 octets)* | Doit correspondre à la valeur définie dans le tableau de bord Convex. Le serveur MCP HTTP vérifie les en-têtes `Authorization: Bearer ` entrants contre cette valeur comme chemin rapide d'administration. | | `PUBLIC_BASE_URL` | Non | `https://vantage-peers-production.up.railway.app` | URL publique du serveur MCP. Utilisée dans les en-têtes `WWW-Authenticate` (RFC 6750) pour diriger les clients OAuth vers l'endpoint de découverte. Par défaut, l'URL de production Railway si non définie. | | `PORT` | Non | `3000` | Port HTTP sur lequel le serveur écoute. Par défaut `3000`. Railway définit cette variable automatiquement via la variable d'environnement `PORT`. | | `NODE_ENV` | Non | `production` | Flag d'environnement Node.js standard. Défini à `production` automatiquement par Railway. Affecte la verbosité des logs et l'exposition des détails d'erreur. | | `VP_EMIT_UI_MARKERS` | Non | `true` | Lorsque défini à `true`, le serveur MCP émet des marqueurs de flux `__VP_TOOL_RESULT__` dans les réponses d'outils. Utilisé par l'iframe embed Gen UI VantagePeers pour distinguer la sortie d'outil structurée de la prose. Désactivé par défaut. | Notes sur les variables partagées [#notes-sur-les-variables-partagées] `BEARER_SECRET_MASTER` apparaît des deux côtés car : * Le **côté Convex** stocke la valeur pour que le backend puisse la valider lorsqu'elle est présentée comme credential. * Le **côté serveur MCP** présente cette valeur dans les requêtes sortantes. Les deux valeurs doivent être identiques. En pratique, définissez-la une fois dans le tableau de bord Convex, copiez la valeur, et collez-la dans l'environnement du serveur MCP. Générer des secrets [#générer-des-secrets] Pour tout token secret : ```bash openssl rand -hex 32 ``` Cela produit une chaîne hex de 64 caractères (256 bits d'entropie). Utilisez une valeur générée séparée pour chaque secret — ne jamais réutiliser des tokens entre les variables. Variables OAuth (Avancé) [#variables-oauth-avancé] L'infrastructure de tokens OAuth (`oauth.ts`, `oauthDcr.ts`) persiste toutes les enregistrements de clients, les tokens d'accès et les tokens de rafraîchissement dans les tables Convex. Aucune variable d'environnement supplémentaire n'est requise pour le système OAuth lui-même. La seule variable adjacente à OAuth est `PUBLIC_BASE_URL` (côté serveur MCP), qui est intégrée dans les métadonnées de découverte OAuth. Résumé des variables par côté [#résumé-des-variables-par-côté] | Variable | Tableau de bord Convex | Serveur MCP | | ------------------------- | ---------------------- | ----------- | | `AI_GATEWAY_API_KEY` | Oui | Non | | `BEARER_SECRET_MASTER` | Oui | Oui | | `GITHUB_WEBHOOK_SECRET` | Oui | Non | | `GITHUB_TOKEN` | Oui | Non | | `CLERK_JWT_ISSUER_DOMAIN` | Oui | Non | | `VP_ALLOWED_EXT_IDS` | Oui | Non | | `CONVEX_URL` | Non | Oui (stdio) | | `CONVEX_URL_INTERNAL` | Non | Oui (HTTP) | | `PUBLIC_BASE_URL` | Non | Oui (HTTP) | | `PORT` | Non | Oui (HTTP) | | `NODE_ENV` | Non | Oui | | `VP_EMIT_UI_MARKERS` | Non | Oui | --- # Migrer de stdio vers le transport HTTP URL: /fr/docs/self-host/migration-stdio-to-http Migrer de stdio vers le transport HTTP [#migrer-de-stdio-vers-le-transport-http] Pourquoi migrer [#pourquoi-migrer] Le transport stdio exécute `vantage-peers-mcp` comme un processus local sur chaque machine, avec un serveur MCP par session Claude Code. Le transport HTTP exécute un seul serveur dans le cloud, accessible à n'importe quel nombre de clients simultanément. | | stdio | HTTP | | --------------------------------------- | ----------------------- | ------------------------ | | Installation requise sur chaque machine | Oui | Non | | Plusieurs agents partagent un serveur | Non | Oui | | Fonctionne depuis Claude.ai web | Non | Oui | | Modèle d'auth | Aucun (processus local) | Token Bearer + OAuth DCR | | Persistance d'état après redémarrages | Via Convex | Via Convex | | Surface de déploiement | Machine locale | Railway (ou tout hôte) | Déclencheurs pratiques pour migrer : * Vous ajoutez un second agent ou une seconde machine et souhaitez qu'ils partagent la même instance VantagePeers. * Vous souhaitez connecter Claude.ai (web) à votre déploiement VantagePeers. * Vous voulez une auth centralisée et une rotation de tokens sans toucher à chaque machine d'agent. * Vous voulez des healthchecks, une surveillance de disponibilité et des politiques de redémarrage Railway. *** Avant et après : .mcp.json [#avant-et-après--mcpjson] Avant (stdio) [#avant-stdio] ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp@2.4.0"], "env": { "CONVEX_URL": "https://votre-deployment.convex.cloud", "BEARER_SECRET_MASTER": "votre-secret-local" } } } } ``` Après (HTTP) [#après-http] ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://votre-projet.up.railway.app/mcp", "headers": { "Authorization": "Bearer VOTRE_BEARER_SECRET_MASTER" } } } } ``` Le `CONVEX_URL` et le `BEARER_SECRET_MASTER` passent de la configuration client aux variables d'environnement Railway. Le client n'a besoin que de l'URL du serveur et d'un token bearer. *** Étapes de migration [#étapes-de-migration] Étape 1 : Déployer le serveur HTTP sur Railway [#étape-1--déployer-le-serveur-http-sur-railway] Suivez le [guide de déploiement Railway HTTP](/docs/self-host/railway-http) en entier avant de continuer. Confirmez : * `curl https://votre-projet.up.railway.app/health` retourne 200 * `railway logs` affiche l'état "Running" Étape 2 : Valider la parité des outils [#étape-2--valider-la-parité-des-outils] Le transport HTTP expose les mêmes 82 outils que stdio. Avant de basculer, confirmez que la version déployée correspond à votre version stdio actuelle : ```bash # Vérifier la version déployée via l'endpoint de santé curl https://votre-projet.up.railway.app/health | grep version # Attendu : "version": "2.4.0" # Comparer avec votre version stdio locale npx vantage-peers-mcp@2.4.0 --version 2>/dev/null || echo "flag version non supporté" ``` Étape 3 : Exécuter les deux transports en parallèle (fenêtre de validation) [#étape-3--exécuter-les-deux-transports-en-parallèle-fenêtre-de-validation] Pendant la transition, gardez la config stdio active sur un agent tout en ajoutant la config HTTP sur un autre. Les deux agents écrivent dans le même backend Convex, vous pouvez donc vérifier que les appels d'outils produisent des résultats identiques : **Agent A (stdio — inchangé) :** ```json { "mcpServers": { "vantage-peers": { "command": "npx", "args": ["-y", "vantage-peers-mcp@2.4.0"], "env": { "CONVEX_URL": "https://votre-deployment.convex.cloud", "BEARER_SECRET_MASTER": "votre-secret-local" } } } } ``` **Agent B (HTTP — nouveau) :** ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://votre-projet.up.railway.app/mcp", "headers": { "Authorization": "Bearer VOTRE_BEARER_SECRET_MASTER" } } } } ``` Demandez à l'Agent B d'appeler `search_memories` ou `list_tasks` et confirmez qu'il récupère les mêmes données que l'Agent A a écrites. Étape 4 : Basculer tous les clients vers HTTP [#étape-4--basculer-tous-les-clients-vers-http] Une fois validé, mettez à jour la config MCP de chaque agent vers la forme HTTP : ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://votre-projet.up.railway.app/mcp", "headers": { "Authorization": "Bearer VOTRE_BEARER_SECRET_MASTER" } } } } ``` Redémarrez Claude Code sur chaque machine après la mise à jour de la config. Étape 5 : Supprimer les variables d'env locales et la config stdio [#étape-5--supprimer-les-variables-denv-locales-et-la-config-stdio] Une fois que tous les clients fonctionnent confirmés sur HTTP : 1. Supprimez `CONVEX_URL` et `BEARER_SECRET_MASTER` des fichiers `.env` locaux et des configs d'agents — ils sont maintenant des variables Railway. 2. Supprimez l'entrée stdio `npx vantage-peers-mcp` de tous les fichiers `.mcp.json` / `settings.json`. 3. Optionnellement, désinstallez le package local : `npm uninstall -g vantage-peers-mcp` (si installé globalement). Ne supprimez pas la config locale avant qu'au moins un client HTTP ait été validé de bout en bout. Exécuter les deux transports simultanément est sans danger — ils écrivent dans la même base de données Convex sans conflit. *** Validation : mêmes appels d'outils, les deux transports [#validation--mêmes-appels-doutils-les-deux-transports] Exécutez le même appel d'outil sur stdio et HTTP pour confirmer une sortie identique : **stdio :** ```bash CONVEX_URL=https://votre-deployment.convex.cloud \ BEARER_SECRET_MASTER=votre-secret-local \ npx vantage-peers-mcp@2.4.0 # Puis depuis Claude Code : search_memories namespace="global" query="test" ``` **HTTP :** ```bash curl -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ -H "Content-Type: application/json" \ -d '{ "jsonrpc": "2.0", "id": 1, "method": "tools/call", "params": { "name": "search_memories", "arguments": {"namespace": "global", "query": "test"} } }' \ https://votre-projet.up.railway.app/mcp ``` Les deux devraient retourner des résultats de la même base de données Convex. Si l'appel HTTP retourne moins ou des résultats différents, vérifiez que `CONVEX_URL_INTERNAL` sur Railway pointe vers le même déploiement que `CONVEX_URL` dans votre config stdio. *** Chemin de retour arrière [#chemin-de-retour-arrière] Si le déploiement HTTP a des problèmes et que vous devez revenir immédiatement : 1. Conservez votre config stdio originale dans un fichier de sauvegarde (`settings.stdio-backup.json`). 2. Pour revenir en arrière : restaurez la config stdio et redémarrez Claude Code — aucune modification Railway n'est nécessaire. 3. Les données Convex ne sont pas affectées par l'un ou l'autre transport — toutes les écritures persistent indépendamment du transport utilisé. Les transports stdio et HTTP sont tous deux sans état vis-à-vis de Convex — ils utilisent tous les deux `ConvexHttpClient` par requête. Basculer entre eux en cours de session est sans danger. Toute mémoire, tâche ou message écrit via stdio est immédiatement visible via HTTP et vice versa. --- # Déployer sur Railway (Transport HTTP) URL: /fr/docs/self-host/railway-http Déployer sur Railway (Transport HTTP) [#déployer-sur-railway-transport-http] Ce que vous obtiendrez [#ce-que-vous-obtiendrez] Un point d'accès HTTPS public exécutant `vantage-peers-mcp` v2.4.0 avec : * Serveur MCP JSON-RPC 2.0 via Streamable HTTP (`/mcp`) * Healthcheck Railway validé sur `/health` * Auth par token Bearer (token maître + OAuth DCR pour Claude.ai) * HTTPS automatique via le proxy intégré de Railway * Accès multi-clients depuis Claude Code, Claude.ai et tout client compatible MCP Prérequis [#prérequis] Avant de commencer : * Un compte [Railway](https://railway.app) (plan Hobby ou supérieur pour les déploiements persistants) * Une URL de déploiement Convex — suivez d'abord le [guide backend Convex](/docs/self-host/convex-backend) * Une valeur `BEARER_SECRET_MASTER` (voir [Configuration Bearer auth](#configuration-bearer-auth) ci-dessous) * `CONVEX_URL_INTERNAL` — l'URL `https://` depuis votre tableau de bord Convex * Node.js 20+ en local pour l'installation du CLI Railway Le serveur de transport HTTP (`server-http.ts`) s'exécute sur Bun sur Railway. Le package npm `vantage-peers-mcp` expose les mêmes 82 définitions d'outils que le serveur stdio, servis via Streamable HTTP. Déploiement en 5 minutes [#déploiement-en-5-minutes] Étape 1 : Installer le CLI Railway et se connecter [#étape-1--installer-le-cli-railway-et-se-connecter] ```bash npm install -g @railway/cli railway login ``` Étape 2 : Créer un nouveau projet Railway [#étape-2--créer-un-nouveau-projet-railway] ```bash railway init ``` Sélectionnez "Empty Project" lorsque demandé. Railway crée un projet et lie votre répertoire de travail. Étape 3 : Créer votre répertoire de projet [#étape-3--créer-votre-répertoire-de-projet] ```bash mkdir vantage-peers-http cd vantage-peers-http npm init -y npm install vantage-peers-mcp@2.4.0 ``` Ajoutez le script de démarrage dans `package.json` : ```json { "scripts": { "start": "node node_modules/vantage-peers-mcp/dist/server-http.js" }, "engines": { "node": ">=20" } } ``` Le package npm `vantage-peers-mcp` livre le `dist/server-http.js` compilé. La commande de démarrage l'invoque directement — Bun n'est pas requis lors de l'exécution depuis le package npm publié. Si vous auto-hébergez le dépôt source, utilisez le chemin `nixpacks.toml` + Bun décrit ci-dessous. Étape 4 : Définir les variables d'environnement [#étape-4--définir-les-variables-denvironnement] ```bash railway variables set CONVEX_URL_INTERNAL=https://votre-deployment.convex.cloud railway variables set BEARER_SECRET_MASTER=$(openssl rand -hex 32) railway variables set PUBLIC_BASE_URL=https://votre-projet.up.railway.app railway variables set NODE_ENV=production ``` Ne définissez PAS `PORT` manuellement — Railway l'injecte automatiquement. Le serveur lit `process.env.PORT` et utilise `3000` par défaut si non défini. Étape 5 : Déployer [#étape-5--déployer] ```bash railway up ``` Railway build, déploie et exécute le healthcheck. Suivez les logs avec : ```bash railway logs ``` *** railway.json et nixpacks.toml [#railwayjson-et-nixpackstoml] Deux surfaces de configuration contrôlent le déploiement. Elles sont complémentaires, pas interchangeables. | Fichier | Couche | Contrôle | | --------------- | --------------------- | ---------------------------------------------------------------------------------------------------------- | | `railway.json` | Orchestration Railway | Chemin/timeout du healthcheck, politique de redémarrage, surcharge optionnelle de la commande de démarrage | | `nixpacks.toml` | Image de build | Quels packages nix sont installés (bun, node), commandes install/build/start | Utiliser le package npm publié (runtime Node) [#utiliser-le-package-npm-publié-runtime-node] Si vous avez installé `vantage-peers-mcp` depuis npm dans votre propre projet (Étape 3 ci-dessus), vous n'avez besoin que de `railway.json` : ```json { "$schema": "https://railway.app/railway.schema.json", "build": { "builder": "NIXPACKS" }, "deploy": { "startCommand": "node node_modules/vantage-peers-mcp/dist/server-http.js", "healthcheckPath": "/health", "healthcheckTimeout": 100, "restartPolicyType": "ON_FAILURE", "restartPolicyMaxRetries": 3 } } ``` Utiliser le dépôt source (runtime Bun) [#utiliser-le-dépôt-source-runtime-bun] Si vous déployez directement depuis le dépôt source `vantage-peers`, les deux fichiers sont requis : **`nixpacks.toml`** (dans `mcp-server/`) : ```toml [phases.setup] nixPkgs = ["nodejs_22", "bun"] [phases.install] cmds = ["bun install"] [phases.build] cmds = ["bun run build"] [start] cmd = "bun run server-http.ts" ``` **`railway.json`** (dans `mcp-server/`) : ```json { "$schema": "https://railway.app/railway.schema.json", "deploy": { "healthcheckPath": "/health", "healthcheckTimeout": 100, "restartPolicyType": "ON_FAILURE", "restartPolicyMaxRetries": 3 } } ``` Si vous supprimez `nixpacks.toml` et comptez uniquement sur `railway.json`, nixpacks détecte automatiquement `package-lock.json` et installe uniquement Node/npm — `bun` n'est jamais installé. Le conteneur démarre puis plante avec `bun: command not found`. Conservez toujours les deux fichiers lorsque vous utilisez le runtime Bun. *** Liaison de port — l'exigence 0.0.0.0 [#liaison-de-port--lexigence-0000] Le probe de healthcheck de Railway provient d'un hôte externe (`healthcheck.railway.app`). Le serveur doit se lier à `0.0.0.0`, pas à `127.0.0.1` ou `localhost`. Le code source `server-http.ts` le fait déjà correctement : ```typescript const PORT = Number(process.env.PORT ?? 3000); const HOSTNAME = "0.0.0.0"; // CRITIQUE — pas 127.0.0.1 Bun.serve({ port: PORT, hostname: HOSTNAME, fetch: app.fetch, }); ``` Si vous voyez des timeouts de healthcheck malgré un démarrage réussi du serveur, la liaison sur localhost est la cause la plus courante. *** Vérification du healthcheck [#vérification-du-healthcheck] Une fois déployé, vérifiez : ```bash # Endpoint de santé — doit retourner 200 sans authentification curl https://votre-projet.up.railway.app/health # Réponse attendue : # { # "status": "ok", # "service": "vantage-peers-mcp-http", # "version": "2.4.0", # "transport": "streamable-http", # "oauth": "supported", # "scopes": ["mcp:full"] # } ``` ```bash # Découverte OAuth — non authentifié curl https://votre-projet.up.railway.app/.well-known/oauth-authorization-server ``` ```bash # Endpoint MCP — nécessite un token Bearer curl -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ https://votre-projet.up.railway.app/mcp ``` *** Configuration Bearer auth [#configuration-bearer-auth] Le serveur supporte deux chemins d'authentification : 1. **Bearer maître** — accès direct avec `BEARER_SECRET_MASTER`. Utiliser pour les opérations admin et les configurations mono-tenant. 2. **OAuth DCR** — Enregistrement Dynamique de Client (RFC 7591) pour Claude.ai et autres clients MCP. Générer BEARER_SECRET_MASTER [#générer-bearer_secret_master] ```bash openssl rand -hex 32 ``` Définir sur Railway (pas dans le code, pas dans `.env`) : ```bash railway variables set BEARER_SECRET_MASTER= ``` Tester l'authentification [#tester-lauthentification] ```bash # Sans token — doit retourner 401 curl -s -o /dev/null -w "%{http_code}\n" \ https://votre-projet.up.railway.app/mcp # Avec le token maître — doit retourner 200 curl -s -o /dev/null -w "%{http_code}\n" \ -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ -H "Content-Type: application/json" \ -d '{"jsonrpc":"2.0","id":1,"method":"tools/list","params":{}}' \ https://votre-projet.up.railway.app/mcp ``` `BEARER_SECRET_MASTER` est une variable Railway (lue par le conteneur Bun). Ce n'est **pas** la même surface que les variables d'environnement Convex. Ne le définissez pas via `npx convex env set` — cela n'aura aucun effet sur le serveur HTTP. *** Connexion des clients MCP [#connexion-des-clients-mcp] Claude Code [#claude-code] Ajoutez dans `~/.claude.json` ou le `.claude/settings.json` de votre projet : ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://votre-projet.up.railway.app/mcp", "headers": { "Authorization": "Bearer VOTRE_BEARER_SECRET_MASTER" } } } } ``` Redémarrez Claude Code. Les 82 outils VantagePeers devraient apparaître dans la liste des outils. Connecteur MCP HTTP Claude.ai [#connecteur-mcp-http-claudeai] Claude.ai utilise OAuth DCR — aucun token Bearer statique n'est nécessaire. Lorsque vous ajoutez l'URL du serveur dans les paramètres du connecteur MCP de Claude.ai : 1. Claude.ai envoie une requête `POST /register` (RFC 7591 Enregistrement Dynamique de Client). 2. Le serveur enregistre le client avec le profil de portée `client-generic` (refus par défaut). 3. Claude.ai complète le flux OAuth PKCE via `/authorize` et `/token`. 4. Les requêtes atteignent `/mcp` avec un token d'accès OAuth à courte durée de vie. Pour élever un client Claude.ai à un accès complet après l'auto-enregistrement : ```bash # Lister les clients enregistrés (token maître requis) curl -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ https://votre-projet.up.railway.app/admin/oauth/clients # Initialiser les profils de portée par défaut (exécuter une fois après le premier déploiement) curl -X POST \ -H "Authorization: Bearer $BEARER_SECRET_MASTER" \ https://votre-projet.up.railway.app/admin/oauth/seed-profiles ``` Autres clients MCP (SSE / Streamable HTTP) [#autres-clients-mcp-sse--streamable-http] Tout client supportant Streamable HTTP (spec MCP 2025-03-26) peut se connecter : ```json { "url": "https://votre-projet.up.railway.app/mcp", "transport": "streamable-http", "headers": { "Authorization": "Bearer VOTRE_TOKEN" } } ``` *** Résolution des problèmes [#résolution-des-problèmes] Timeout du healthcheck [#timeout-du-healthcheck] **Symptôme :** Railway affiche "Healthcheck failed" ou le déploiement ne passe jamais à l'état "Running." **Étapes de diagnostic :** 1. Vérifiez que le serveur se lie à `0.0.0.0`, pas à `127.0.0.1`. 2. Vérifiez que `PORT` n'est pas manuellement surchargé dans les Variables Railway. 3. Consultez `railway logs` pour les erreurs de démarrage avant que le healthcheck ne se déclenche. ```bash railway logs --build # erreurs de phase de build railway logs # erreurs d'exécution ``` `bun: command not found` (déploiements depuis le dépôt source) [#bun-command-not-found-déploiements-depuis-le-dépôt-source] **Symptôme :** Le build réussit mais le conteneur plante au démarrage avec `bun: command not found`. **Correction :** Assurez-vous que `nixpacks.toml` déclare `bun` dans `nixPkgs` : ```toml [phases.setup] nixPkgs = ["nodejs_22", "bun"] ``` C'est l'erreur la plus courante lors de la suppression de `nixpacks.toml` en pensant que `railway.json` le couvre — ce n'est pas le cas. `nixpacks.toml` contrôle ce qui est installé ; `railway.json` contrôle comment ça s'exécute. Variables d'environnement non chargées [#variables-denvironnement-non-chargées] **Symptôme :** Le serveur démarre mais retourne `server_misconfigured` ou ne peut pas atteindre Convex. **Correction :** Vérifiez que les variables sont définies sur Railway, pas seulement en local : ```bash railway variables ``` Assurez-vous que `CONVEX_URL_INTERNAL` (pas `CONVEX_URL`) est défini — le serveur HTTP lit la variable d'URL interne. Erreurs CORS depuis les clients navigateur [#erreurs-cors-depuis-les-clients-navigateur] **Symptôme :** Les clients MCP basés sur navigateur voient des erreurs `Access-Control-Allow-Origin`. Le serveur définit des en-têtes CORS permissifs pour toutes les origines par défaut : ``` Access-Control-Allow-Origin: * Access-Control-Allow-Methods: GET, POST, DELETE, OPTIONS ``` Si vous voyez des erreurs CORS, vérifiez que votre client n'utilise pas d'en-tête personnalisé absent de la liste `allowHeaders` (`Content-Type`, `Authorization`, `mcp-session-id`, `Last-Event-ID`, `mcp-protocol-version`). Échec de build double `cd` [#échec-de-build-double-cd] **Symptôme :** Le build échoue avec `bash: cd: mcp-server/mcp-server: No such file or directory`. **Cause :** Le répertoire racine du service Railway est déjà défini sur `mcp-server/` ET le `buildCommand` inclut aussi `cd mcp-server`. Choisissez l'une ou l'autre approche : * Soit définissez le répertoire racine dans le tableau de bord Railway et supprimez `cd mcp-server` des commandes. * Soit gardez la racine au niveau du dépôt et ajoutez `cd mcp-server` aux commandes. *** Liste de contrôle de production [#liste-de-contrôle-de-production] Avant de passer en production avec n'importe quel tenant payant, confirmez tous les éléments ci-dessous. * Domaine personnalisé configuré via `railway domain` ou le tableau de bord Railway * HTTPS uniquement — Railway applique TLS automatiquement ; vérifiez l'absence de liens HTTP dans les configs client * Chemin de healthcheck `/health` actif et retournant 200 (non authentifié) * `BEARER_SECRET_MASTER` stocké dans les Variables Railway, pas dans un fichier commité * Politique de rotation Bearer documentée — planifiez `openssl rand -hex 32` + redéploiement Railway * Profils de portée OAuth initialisés : `POST /admin/oauth/seed-profiles` exécuté après le premier déploiement * `CONVEX_URL_INTERNAL` pointe vers le bon déploiement Convex (pas un déploiement de développement en production) * Le déploiement Convex utilise l'environnement de production — voir le [guide backend Convex](/docs/self-host/convex-backend) * Alertes Railway configurées (notifications de défaillance CPU, mémoire, healthcheck) * `railway logs` confirme l'état "Running" et l'absence d'erreurs au démarrage --- # Notes de version Day-114 URL: /fr/docs/release-notes/day-114 Notes de version Day-114 [#notes-de-version-day-114] **Package :** `vantage-peers-mcp@2.13.1` **Date :** 2026-06-27 **Convex prod :** `compassionate-goldfinch-737.convex.cloud` redéployé à HEAD `d09fc5b` **Mise à niveau requise pour les utilisateurs de list\_memories et list\_episodes.** Les appelants antérieurs à la version 2.13.1 reçoivent `items: []` de ces deux outils à chaque invocation, indépendamment des données stockées. Il s'agit d'un dysfonctionnement fonctionnel, pas d'une dérive de pagination. Mettre à niveau vers `>=2.13.1` immédiatement. Correction critique — réponse vide silencieuse list_memories + list_episodes [#correction-critique--réponse-vide-silencieuse-list_memories--list_episodes] **PR :** [#978](https://github.com/vantageos-agency/vantage-peers/pull/978) — squash `0db28d5` Ce qui était cassé [#ce-qui-était-cassé] `list_memories` et `list_episodes` retournaient silencieusement `items: []` à chaque appel depuis v2.5.0 (Day-92 S3.3 B8 déploiement curseur) jusqu'à v2.13.0. Cause racine : le gestionnaire MCP lisait `memories?.page` depuis la forme de retour Convex `listMemories`. L'assistant `paginate()` de Convex retourne `{ value: T[], continueCursor: string | null, isDone: boolean }`. Le champ s'appelle `value`, pas `page`. `memories?.page` est toujours `undefined` → `items: []` à chaque invocation. Effet secondaire : comme `continueCursor` n'était jamais lu, `nextCursor` n'était jamais non plus émis. La pagination était doublement cassée — pas de données et pas de possibilité de paginer vers l'avant. Cela était présent sur la **première page** (sans curseur), pas seulement sur les pages suivantes. Chaque appel à `list_memories` ou `list_episodes` retournait un résultat vide quel que soit le nombre de mémoires existant dans le namespace. Ce qui a changé [#ce-qui-a-changé] `mcp-server/src/tools.ts` — deux blocs d'assemblage de réponse gestionnaire corrigés : * Gestionnaire `list_episodes` L2161–2188 : lit maintenant `memories.value` (pas `?.page`), lit `memories.continueCursor` + `memories.isDone`, et émet l'enveloppe `{items, nextCursor}` via `encodeCursor({backendCursor})`. * Gestionnaire `list_memories` L2515–2547 : correction identique appliquée. Les deux corrections reproduisent le motif de renforcement d'enveloppe PR-A/B/C/E utilisant l'assistant partagé `mcp-server/src/paging.ts`. Aucune modification du backend Convex n'était requise — la requête Convex `memories:listMemories` implémentait déjà correctement `paginate()` et retournait `{ value, continueCursor, isDone }`. Le bug était entièrement dans la couche d'assemblage de réponse MCP. Preuves de test [#preuves-de-test] Nouveau fichier : `mcp-server/src/__tests__/list_memories_episodes_pagination.test.ts` — 11/11 PASS * 5 tests pour `list_memories` : assertion données semées, première page avec curseur, chaîne de pagination complète, backend vide, `nextCursor` absent quand `isDone=true`. * 6 tests pour `list_episodes` : même couverture. Preuves RED-avant : 8 échecs avec `AssertionError: result must have an items array: expected false to be true` et `TypeError: Cannot read properties of undefined (reading 'length')`. Zéro régression suite complète : 27 fichiers / 380 tests PASS (serveur MCP). 35 fichiers / 328 tests PASS (Convex). Delta baseline TypeScript = 0 vs 176 erreurs pré-correction. Appelants pré-2.13.1 — action requise [#appelants-pré-2131--action-requise] Tout appelant utilisant `list_memories` ou `list_episodes` sur vantage-peers-mcp en dessous de la version 2.13.1 doit mettre à niveau. Il n'y a pas de contournement — les outils étaient non fonctionnels au niveau MCP pour tous les namespaces. ```bash npm install vantage-peers-mcp@latest # ou npx vantage-peers-mcp@latest ``` *** Doctrine MCP Tools Standard v1 [#doctrine-mcp-tools-standard-v1] **PR :** [#980](https://github.com/vantageos-agency/vantage-peers/pull/980) — squash `d09fc5b` **Runbook VantageRegistry :** `kd750j7z7tqre6hxqmfsa8s9ed89erng` Laurent verbatim 2026-06-27 : *« Omega doit faire comme sigma a fait pour VP MCP — pas de divergence ! 1 seul standard que l'on décline partout, pour tous les MCP. »* Cette PR établit la doctrine de pagination `list_*` cross-fleet comme un standard canonique versionné applicable à tous les serveurs MCP VantageOS — VP MCP (Sigma), VR MCP (Omega), vCRM (Theta), et tout futur MCP. Contenu de la doctrine (v1) [#contenu-de-la-doctrine-v1] Le document de doctrine (`projects/vantage-peers/mcp-tools-standard-doctrine-v1.md`) couvre : 1. **Motif obligatoire `list_*`** — schéma Zod args (`pagingArgsSchema`), enveloppe de retour (`{items, nextCursor?}`), contrat backend Convex, assemblage du gestionnaire MCP, alternative `createdBefore`, limites par défaut/max, projection obligatoire `fields=lite`. 2. **Anti-patterns bannis** — 7 motifs avec classe de sévérité, extraits de code mauvais/correct, références aux incidents Day-114. 3. **Modèle de matrice de couverture** — colonnes standard du tableau d'audit, barème de sévérité, processus d'audit, protocole de test adversarial. 4. **Référence cross-fleet MCP** — tableau de tous les serveurs MCP VantageOS connus avec statut de conformité actuel. 5. **Porte de conformité** — exigences du corps de PR, liste de vérification du vérificateur Eta (Day-82 v1.1.0), porte de publication npm. 6. **Playbook de migration** — processus en 7 étapes pour amener les outils `list_*` non conformes à la sévérité LOW. Résultats de l'audit Day-114 [#résultats-de-laudit-day-114] L'audit Day-114 a vérifié les 18 outils `list_*` dans VP MCP : * **15 LOW** — conformité complète : argument curseur présent, `clampLimit` appliqué (1–200), `{items, nextCursor}` émis sur les pages complètes. * **2 HIGH (corrigés dans la PR #978)** — `list_memories` + `list_episodes` : lecture erronée de forme `memories?.page`, `items: []` à chaque appel. * **1 EXCEPTION** — `list_broadcast_status` : forme de retour objet unique, pagination par curseur architecturalement inapplicable ; porte le marqueur JSDoc `@cursorPagingException`. Statut de conformité de la flotte post-Day-114 [#statut-de-conformité-de-la-flotte-post-day-114] | MCP | Propriétaire | Statut | | ------------------------------- | ------------ | ------------------------------------------- | | VP MCP (`vantage-peers-mcp`) | Sigma | 15 LOW + 2 HIGH corrigés + 1 EXCEPTION | | VR MCP (`vantage-registry-mcp`) | Omega | Reconstruction sur ce motif (audit Day-115) | | vCRM MCP | Theta | Audit planifié Day-115+ | *** Redéploiement Convex prod [#redéploiement-convex-prod] Convex prod (`compassionate-goldfinch-737.convex.cloud`) a été redéployé à HEAD `d09fc5b` suite à la fusion de la PR #980. Le serveur MCP sur Railway a également été redémarré pour intégrer l'assemblage de gestionnaire `tools.ts` mis à jour de la PR #978. Le test de fumée d'activation a réussi : `list_memories namespace="orchestrator/sigma"` a retourné `items.length > 0` en prod avec des données semées connues. *** PRs de documentation compagnon [#prs-de-documentation-compagnon] * **PR #983** — Mise à jour du README du dépôt principal : motif de boucle curseur ajouté à la section « Itération de grands résultats de liste ». * **PR #984** — Mise à jour du README npm du serveur MCP : contrat d'enveloppe documenté dans la Référence rapide. *** Liens [#liens] * [Pagination par curseur](/docs/pagination) * [Sécurité d'enveloppe](/docs/envelope-safety) * [Catalogue des outils](/docs/tools-catalogue) * Dépôt principal : [vantageos-agency/vantage-peers](https://github.com/vantageos-agency/vantage-peers/blob/main/README.md) * npm : [vantage-peers-mcp](https://www.npmjs.com/package/vantage-peers-mcp) * PR #978 : [github.com/vantageos-agency/vantage-peers/pull/978](https://github.com/vantageos-agency/vantage-peers/pull/978) * PR #980 : [github.com/vantageos-agency/vantage-peers/pull/980](https://github.com/vantageos-agency/vantage-peers/pull/980) * Runbook VR : `kd750j7z7tqre6hxqmfsa8s9ed89erng` --- # Agent Expert URL: /fr/docs/toolkit/agents Agent vantage-peers-expert [#agent-vantage-peers-expert] L'agent `vantage-peers-expert` est un spécialiste MCP VantagePeers complet intégré dans le plugin. Il connaît tous les \~82 outils VP, les conventions de namespace, les types de mémoire, les protocoles de tâches, la gestion des missions, la messagerie, les notes de briefing, le journal, les fix-patterns, les composants, les mandats et les épisodes. Quand l'invoquer [#quand-linvoquer] L'agent est déclenché automatiquement quand Claude Code détecte ces patterns dans votre prompt : | Phrase déclencheuse | Ce qu'il fait | | ----------------------- | ------------------------------------------------------------------ | | "store this" | Appelle `store_memory` avec le bon type et namespace | | "recall X" | Appelle `recall` avec une requête de recherche hybride | | "create task" | Crée une tâche conforme T-VERIFY (sections VERIFICATION + TESTS) | | "set up VP" | Délègue au skill `vantage-peers-init` | | "what's in memory" | Appelle `recall` ou `list_memories` pour remonter l'état pertinent | | "send message to X" | Appelle `send_message` avec le routage correct | | "VP smoke test" | Exécute le skill init | | "check my tasks" | Délègue au skill `check-tasks` | | "log a decision" | Crée une mémoire `reference` dans le namespace approprié | | "write a briefing note" | Appelle `create_briefing_note` avec un contenu structuré | | "fix pattern" | Appelle `store_fix_pattern` ou `recall_fix_patterns` | | "VP namespace" | Explique les conventions de namespace et les applique | Vous pouvez aussi l'invoquer directement : ``` Utilise vantage-peers-expert pour stocker la décision de basculer vers le transport HTTP Railway. ``` Ce qu'il sait [#ce-quil-sait] Catalogue d'outils (~82 outils) [#catalogue-doutils-82-outils] L'agent dispose d'une cartographie complète de tous les outils MCP VP par catégorie : | Catégorie | Outils principaux | | ------------------ | -------------------------------------------------------------------------------------------------------------------- | | Mémoire | `store_memory`, `recall`, `list_memories`, `get_memory`, `update_memory`, `delete_memory` | | Tâches | `create_task`, `list_tasks`, `start_task`, `pause_task`, `resume_task`, `complete_task`, `update_task`, `block_task` | | Missions | `create_mission`, `list_missions`, `get_mission`, `update_mission`, `start_mission`, `complete_mission` | | Messagerie | `send_message`, `check_messages`, `mark_as_read`, `list_messages` | | Notes de briefing | `create_briefing_note`, `list_briefing_notes`, `get_briefing_note`, `update_briefing_note` | | Journal | `write_diary`, `list_diary_entries`, `get_diary_entry` | | Fix Patterns | `store_fix_pattern`, `recall_fix_patterns`, `list_fix_patterns`, `apply_fix_pattern` | | Profils / Présence | `set_summary`, `get_summary`, `list_summaries`, `register_profile` | | Système | `health`, `list_tools` | Conventions de namespace [#conventions-de-namespace] L'agent applique automatiquement les conventions de namespace VP : | Portée | Pattern | Pour quoi | | -------------------------- | --------------------- | ---------------------------------------------------- | | Faits cross-équipe | `global` | Décisions, mandats, fix-patterns applicables partout | | Délimité au projet | `project/` | ex. `project/vantage-peers`, `project/cedar` | | Délimité à l'orchestrateur | `orchestrator/` | État personnel, snapshots de session | Types de mémoire [#types-de-mémoire] | Type | Quand utilisé | | ----------- | ------------------------------------------------------------------------------ | | `user` | Faits sur l'opérateur — préférences, contraintes | | `feedback` | Corrections, notes de qualité, "ne jamais refaire X" | | `project` | Faits au niveau projet — décisions de stack, URLs déployées | | `reference` | Artefacts à long terme — snapshots de session, résumés de spec | | `episode` | Enregistrements narratifs — ce qui s'est passé en session, rapports d'incident | Doctrine T-VERIFY [#doctrine-t-verify] Chaque tâche créée par l'agent inclut des blocs `VERIFICATION` et `TESTS` obligatoires. L'agent ne créera pas de tâche sans eux. Recall-Before-Assumptions [#recall-before-assumptions] L'agent appelle toujours `recall` avant de répondre à toute question factuelle sur l'état du projet, l'historique ou les décisions. Il indiquera "No memory found" si la recherche ne retourne rien, plutôt que de deviner. Exemples de prompts [#exemples-de-prompts] **Stocker une décision :** ``` Store this architecture decision — we're using Railway for HTTP transport on Cedar. ``` L'agent appelle `store_memory` avec `type=reference`, `namespace=project/cedar`, contenu structuré. **Recall avant de répondre :** ``` What stack did we decide on for the Cedar API? ``` L'agent appelle d'abord `recall query="Cedar API stack decision" namespace=project/cedar`, puis répond d'après les résultats. **Créer une tâche correcte :** ``` Create a task for sigma to implement the Bearer token rotation endpoint. ``` L'agent appelle `create_task` avec `assignedTo=sigma`, et remplit les sections obligatoires `VERIFICATION` et `TESTS` dans la description. **Dispatch de swarm d'agents :** ``` Dispatch a task to eta to review commit acc0092 before we publish the npm package. ``` L'agent crée une tâche structurée avec le brief de revue et les critères VERIFICATION pour la gate d'approbation d'Eta. Limites de portée [#limites-de-portée] L'agent ne fait pas de travail en dehors des outils VP. Il route les demandes hors portée : | Type de demande | Routé vers | | ------------------------------ | ------------------------- | | Modifications de code frontend | Agent `dev-frontend` | | Décisions d'architecture | Agent `dev-senior-dev` | | Fonctions backend Convex | Agent `dev-convex-expert` | Quand invoqué comme sous-agent depuis un autre agent, il retourne : outil appelé + résultat clé (ID, compte, ou aperçu de contenu) + namespace utilisé. --- # Commandes Slash URL: /fr/docs/toolkit/commands Commandes Slash [#commandes-slash] Les commandes slash sont l'interface d'invocation directe des 9 skills. Chaque commande encapsule exactement un skill et transmet les arguments optionnels. Les 9 commandes [#les-9-commandes] | Commande | Skill encapsulé | Description | | --------------------- | ------------------ | ------------------------------------------------------------------------------ | | `/check-messages` | check-messages | Interroger la boîte de réception et choisir la prochaine tâche (mode autonome) | | `/check-tasks` | check-tasks | Lister votre file de tâches, triée par priorité | | `/close-day` | close-day | Clôture EOD : mettre à jour tâches, écrire journal, stocker résumé | | `/daily-start` | daily-start | Démarrage matinal : charger le contexte et présenter le plan | | `/pre-compact` | pre-compact | Snapshot de session avant compaction de contexte | | `/recall ` | recall | Recherche hybride sémantique + BM25 sur les mémoires VP | | `/standup` | standup | Générer un rapport de standup structuré et déposer une note de briefing | | `/vantage-peers-init` | vantage-peers-init | Vérifier l'enregistrement MCP, la connectivité et l'auth | | `/write-diary` | write-diary | Écrire une entrée de journal structurée pour aujourd'hui | Exemples d'utilisation [#exemples-dutilisation] /check-messages [#check-messages] ``` /check-messages ``` Interroge votre boîte de réception. Affiche les messages non lus avec l'expéditeur et le contenu. En mode autonome, choisit et démarre automatiquement la prochaine tâche prioritaire après le traitement des messages. Argument optionnel pour vérifier avec un rôle spécifique : ``` /check-messages --role sigma ``` *** /check-tasks [#check-tasks] ``` /check-tasks ``` Liste toutes les tâches assignées à votre rôle d'orchestrateur. Groupe par priorité (urgent → high → medium → low). Signale les tâches bloquées avec leurs IDs de dépendances. Suggère la prochaine tâche non bloquée à démarrer. *** /close-day [#close-day] ``` /close-day ``` Déclenche la séquence de clôture EOD : révise les tâches ouvertes, écrit le journal pour la date d'aujourd'hui, stocke un résumé de session comme mémoire `reference`, et définit votre présence d'orchestrateur en état fermé/veille. *** /daily-start [#daily-start] ``` /daily-start ``` Charge le contexte VP pour la session courante : rappelle les mémoires récentes du projet, vérifie les messages, liste les tâches actives. En mode humain : présente un plan de session proposé. En mode autonome : choisit et démarre directement la tâche non bloquée de plus haute priorité. *** /pre-compact [#pre-compact] ``` /pre-compact ``` Sauvegarde un snapshot complet de session avant la compaction de contexte. Stocke l'état actuel (missions actives, tâches, bloqueurs, résumé en 3 lignes) comme mémoire `reference` et une note de briefing. Le prochain contexte rappellera ceci et reprendra de façon fluide. *** /recall [#recall] ``` /recall ``` Effectue une recherche hybride sémantique + BM25 sur les mémoires VP. Le namespace est détecté automatiquement depuis la requête, ou vous pouvez le spécifier : ``` /recall "decisions architecture auth" --namespace project/vantage-peers ``` Retourne les mémoires les mieux correspondantes avec leurs types, namespaces et horodatages de création. *** /standup [#standup] ``` /standup ``` Génère un standup structuré avec 4 sections : * **DONE** — tâches terminées depuis le dernier standup * **IN PROGRESS** — tâches actuellement actives * **BLOCKERS** — tâches bloquées avec les IDs de dépendances * **GIT** — commits récents (si l'outil Bash est disponible) Dépose le résultat comme `briefing_note` avec le topic `standup`. *** /vantage-peers-init [#vantage-peers-init] ``` /vantage-peers-init ``` Exécute 3 vérifications et produit un rapport PASS/FAIL : 1. Enregistrement MCP — `vantage-peers` visible dans la liste d'outils 2. Connectivité — `/health` retourne `{ status: "ok" }` 3. Auth — l'appel `recall` réussit avec un Bearer valide Les 3 doivent passer avant d'utiliser les autres skills. *** /write-diary [#write-diary] ``` /write-diary ``` Guide à travers une entrée de journal structurée. Pose une question d'ancrage sur la chose la plus importante aujourd'hui, puis construit et stocke une entrée de journal avec les points saillants, ce qui a été appris, et les bloqueurs ouverts. --- # Hooks URL: /fr/docs/toolkit/hooks Hooks [#hooks] Les hooks s'exécutent automatiquement sur chaque appel d'outil correspondant dans Claude Code. Ils appliquent silencieusement les standards de qualité du workflow VP — ils ne se manifestent que lorsqu'ils bloquent une action. Quand un hook bloque, il affiche une raison claire et un correctif. Les hooks de ce plugin sont des **gates de qualité BU-agnostiques** — preuve d'évidence sur les tâches, discipline de messagerie, structure des briefs et missions, hygiène d'estimation temporelle. Ils s'exécutent automatiquement sur tous vos workspaces une fois le plugin installé. Les 7 hooks [#les-7-hooks] enforce-evidence-bound-completion [#enforce-evidence-bound-completion] **Déclencheur :** `PreToolUse` — correspond à `mcp__vantage-peers__complete_task` et `mcp__vantage-peers__update_task` **Ce qu'il applique :** Chaque fermeture de tâche ou mise à jour vers le statut `review`/`done` doit inclure un `completionNote` d'au moins 40 caractères contenant au moins un jeton de preuve vérifiable : | Type de jeton de preuve | Exemples | | ----------------------- | -------------------------------------------- | | URL | Lien PR, URL de déploiement, URL dashboard | | Commit SHA | 7-40 caractères hexadécimaux | | Numéro PR / issue | `#546`, `#113` | | ID VP / Convex | ID tâche, ID mémoire, ID message | | Ratio de tests | `311/314`, `69/69` | | Artefact compté | `18 tests`, `7 fichiers`, `2900 lignes` | | Chemin de fichier | `analysis/report.md`, `qa/screenshots/x.png` | **Ce qu'il bloque :** Les notes de complétion contenant uniquement des mots de revendication sans preuve — "done", "merged", "PASS", "all good", "fixed". **Exemple d'appel bloqué :** ``` complete_task({ taskId: '...', completionNote: 'done' }) # BLOQUÉ : "done" est une revendication, pas une preuve. ``` **Exemple d'appel accepté :** ``` complete_task({ taskId: '...', completionNote: 'PR #546 mergé, build passe, commit acc0092' }) # PASS : contient PR#, confirmation de build, commit SHA ``` **Désactivation :** Ajoutez `// allow-no-evidence: ` au commentaire de contexte de l'appel d'outil. Utilisez uniquement quand vous êtes véritablement bloqué (ex. tâche terminée sans artefact numérique). Corrigez la source si vous désactivez fréquemment. *** enforce-no-task-in-message [#enforce-no-task-in-message] **Déclencheur :** `PreToolUse` — correspond à `mcp__vantage-peers__send_message` **Ce qu'il applique :** Les messages inter-orchestrateurs contenant des instructions impératives ("implement", "fix", "build", "deploy", "create", "update") doivent référencer un ID de tâche. Le travail vit dans une tâche — les messages coordonnent, les tâches assignent. **Ce qu'il bloque :** Les messages qui donnent des instructions sans pointer vers une tâche formellement suivie. **Exemple d'appel bloqué :** ``` send_message({ to: 'sigma', content: 'Please implement the retry logic for the HTTP client.' }) # BLOQUÉ : instruction impérative sans référence de tâche ``` **Exemple d'appel accepté :** ``` send_message({ to: 'sigma', content: 'Task k170xxx is ready for your review — #546 is open.' }) # PASS : référence un ID de tâche et un PR ``` **Pourquoi cette règle existe :** Quand les instructions ne vivent que dans les messages, elles sont invisibles dans la file de tâches, ne peuvent pas être priorisées et n'ont pas de responsabilité de complétion. Créer d'abord une tâche rend le travail traçable. *** enforce-task-quality [#enforce-task-quality] **Déclencheur :** `PreToolUse` — correspond à `mcp__vantage-peers__create_task` **Ce qu'il applique :** Chaque nouvelle tâche doit inclure les sections `VERIFICATION` et `TESTS` dans sa description. C'est la doctrine T-VERIFY — une tâche sans ces sections ne peut pas être achevée ou révisée de façon fiable. **Sections requises :** ``` VERIFICATION: - [ ] - [ ] TESTS: - [ ] ``` **Ce qu'il bloque :** Les tâches dont le champ `description` manque des marqueurs `VERIFICATION:` et `TESTS:`. **Exemple de description de tâche acceptée :** ``` Implémenter l'endpoint de rotation de token Bearer. VERIFICATION: - [ ] POST /rotate-token retourne 200 avec nouveau bearer - [ ] L'ancien bearer retourne 401 après rotation TESTS: - [ ] npm test -- --grep "bearer rotation" ``` *** block-time-estimates [#block-time-estimates] **Déclencheur :** `PreToolUse` — correspond à `Edit`, `Write`, `mcp__vantage-peers__send_message`, `mcp__vantage-peers__create_task`, `mcp__vantage-peers__update_task`, `mcp__vantage-peers__create_mission` **Ce qu'il applique :** Les estimations d'effort et de durée dans le contenu sont bloquées. Les formulations vagues de durée dans les tâches, messages, missions et fichiers écrits ne sont pas autorisées. **Désactivation pour valeurs de configuration légitimes :** Ajoutez `// allow-time-estimate: ` sur la ligne concernée. Valide : valeurs de configuration factuelles (intervalles cron, durées d'animation, constantes TTL). Non valide : estimations d'effort de travail. **Pourquoi cette règle existe :** Les estimations d'effort dans les tâches et messages ont un mauvais bilan de précision et ancrent incorrectement les attentes. Le travail est délimité par les critères VERIFICATION, pas par une durée estimée. *** auto-compact-reminder [#auto-compact-reminder] **Déclencheur :** `PostToolUse` — correspond à `.*` (tous les outils) **Ce qu'il applique :** Suit le nombre d'appels d'outils par session. Rappelle de compacter au 35e appel d'outil, puis tous les 15 appels suivants. // allow-time-estimate: factual tool-call count thresholds **Ce qu'il fait :** Affiche un message de rappel quand le seuil est atteint : "Le contexte grandit — pensez à exécuter le skill `pre-compact` avant que la fenêtre de contexte soit pleine." **Portée :** Compteur au niveau de la session. Se réinitialise au démarrage de la session. **Pourquoi cette règle existe :** Les fenêtres de contexte Claude Code sont limitées. Exécuter `pre-compact` avant d'atteindre la limite garantit que l'état de session est préservé et que le prochain contexte peut reprendre sans perte. **Aucune désactivation nécessaire** — les rappels sont consultatifs, pas bloquants. *** enforce-mission-template [#enforce-mission-template] **Déclencheur :** `PreToolUse` — correspond à `mcp__vantage-peers__create_mission` **Ce qu'il applique :** Tout appel à `create_mission` doit référencer un Mission Template via le champ `templateId`. Les missions sans template structuré dérivent rapidement de leur objectif annoncé. **Ce qu'il bloque :** Les appels à `mcp__vantage-peers__create_mission` où `templateId` est absent ou vide. Sortie : un refus clair pointant vers l'exigence du template. **Correctif :** Choisissez un Mission Template (`mcp__vantage-registry__list_templates` ou votre catalogue local), passez son ID dans `templateId`. Si la mission est réellement libre, créez d'abord votre propre template via `upsert_template` puis référencez-le. **Pourquoi cette règle existe :** Les missions templates livrent à une cadence prévisible et survivent aux passations. Les missions non-templates non. *** enforce-brief-template [#enforce-brief-template] **Déclencheur :** `PreToolUse` — correspond à `Task` (outil de dispatch de subagents Claude Code) **Ce qu'il applique :** Chaque brief de l'outil Task (délégation à un subagent) doit inclure une ligne `Template reference:` proche du sommet, pointant vers le brief template dont vous avez dérivé le prompt (ex : `resources/templates/brief-backend.md`). **Ce qu'il bloque :** Les appels Task dont le corps `prompt` n'a pas de marqueur `Template reference:`. Sortie : un refus avec le format attendu. **Correctif :** Ajoutez une seule ligne comme `Template reference: resources/templates/brief-backend.md` en haut du prompt. Si aucun template ne s'applique (rare), référencez `resources/templates/agent-brief-template.md` comme fallback générique et adaptez le brief. **Pourquoi cette règle existe :** Les subagents travaillent sur des briefs qu'ils n'ont pas écrits. Une `Template reference:` rend le brief auditable et reproductible — et donne aux subagents la structure dont ils ont réellement besoin (FILES / EXACT CHANGES / ACCEPTANCE CRITERIA). *** Référence des déclencheurs de hooks [#référence-des-déclencheurs-de-hooks] | Hook | Type de déclencheur | Outils correspondants | | ----------------------------------- | ------------------- | ------------------------------------------------------------------------------- | | `enforce-evidence-bound-completion` | PreToolUse | `complete_task`, `update_task` | | `enforce-no-task-in-message` | PreToolUse | `send_message` | | `enforce-task-quality` | PreToolUse | `create_task` | | `block-time-estimates` | PreToolUse | `Edit`, `Write`, `send_message`, `create_task`, `update_task`, `create_mission` | | `auto-compact-reminder` | PostToolUse | Tous les outils (`.*`) | | `enforce-mission-template` | PreToolUse | `create_mission` | | `enforce-brief-template` | PreToolUse | `Task` (dispatch de subagent) | --- # VantagePeers Toolkit URL: /fr/docs/toolkit VantagePeers Toolkit [#vantagepeers-toolkit] Le plugin `vantage-peers` est un plugin Claude Code opinioné pour tout workspace consommant un serveur MCP VantagePeers. Installez-le une fois, connectez-le à votre déploiement VP, et chaque orchestrateur Claude Code de votre workspace acquiert la messagerie structurée, la mémoire, les tâches, les missions, le journal, le standup et la gestion de session — clé en main. **Version du plugin :** 2.4.0 — aligné avec `vantage-peers-mcp` npm v2.4.x. Installation [#installation] ``` claude plugin install vantage-peers ``` C'est la commande d'installation complète. Consultez [Installation](/docs/toolkit/install) pour le démarrage rapide en 5 étapes. Ce qui est livré dans v2.4.0 [#ce-qui-est-livré-dans-v240] | Catégorie | Nombre | Description | | --------------- | ------ | --------------------------------------------------------------------------------------- | | Skills | 9 | Protocoles de workflow réutilisables invoqués par phrase déclencheuse ou commande slash | | Hooks | 7 | Guardrails PreToolUse / PostToolUse appliqués automatiquement | | Commandes slash | 9 | Raccourcis `/commande` mappés sur des skills | | Agents | 1 | `vantage-peers-expert` — spécialiste MCP VP complet | Prérequis [#prérequis] * Un serveur MCP VantagePeers déployé (Railway en un clic sur [vantagepeers.com/railway](https://vantagepeers.com/railway) ou Convex auto-hébergé) * Claude Code avec support des plugins * Votre URL de déploiement et votre secret Bearer Explorer [#explorer] --- # Installation URL: /fr/docs/toolkit/install Installation [#installation] Prérequis [#prérequis] Avant d'installer le plugin : * Un serveur MCP VantagePeers opérationnel. Déployez sur Railway : [vantagepeers.com/railway](https://vantagepeers.com/railway). Notez votre URL (ex. `https://vantage-peers-abc123.railway.app`) et `BEARER_SECRET`. * Claude Code installé et fonctionnel dans votre workspace. **Installer le plugin** ``` claude plugin install vantage-peers ``` Cela installe les skills, hooks, commandes et l'agent `vantage-peers-expert` dans votre workspace Claude Code. **Configurer .mcp.json** Copiez le template du plugin : ```json { "mcpServers": { "vantage-peers": { "type": "http", "url": "https://votre-déploiement.railway.app/mcp", "headers": { "Authorization": "Bearer votre-secret-bearer" } } } } ``` Enregistrez en tant que `.mcp.json` à la racine de votre workspace. Redémarrez Claude Code après l'enregistrement. Consultez [Tokens Bearer](/docs/auth/bearer-tokens) pour le format du secret Bearer et comment en obtenir un. **Compléter le template CLAUDE.md** Le plugin inclut un fichier `templates/CLAUDE.md.append` avec les protocoles de workflow VP (recall-before-assumptions, protocole de tâches, conventions de namespace). Ajoutez son contenu à la fin de votre `CLAUDE.md` de workspace : ```bash cat "$(claude plugin path vantage-peers)/templates/CLAUDE.md.append" >> CLAUDE.md ``` Cela installe le contexte de protocole VP dont les skills dépendent (détection d'identité d'orchestrateur, basculement de mode, conventions de namespace). **Exécuter l'init et vérifier** ``` /vantage-peers-init ``` Cela exécute 3 vérifications : 1. Enregistrement MCP — confirme que le serveur `vantage-peers` est visible dans la liste d'outils de Claude Code 2. Connectivité — appelle `/health` sur votre URL de déploiement, attend `{ status: "ok" }` 3. Auth — teste l'authentification Bearer via un appel `recall` Les 3 vérifications doivent afficher `PASS`. En cas d'échec, le skill fournit une suggestion de correction pour chaque échec. **Premières commandes** ``` /check-messages /check-tasks /daily-start ``` * `/check-messages` — interroge votre boîte de réception ; attendez-vous à "No new messages" sur un déploiement vierge * `/check-tasks` — liste vos tâches assignées * `/daily-start` — charge le contexte VP et présente votre plan de session Vérifier que les skills et hooks sont actifs [#vérifier-que-les-skills-et-hooks-sont-actifs] Après l'installation, confirmez que le plugin est chargé : ``` claude plugin list ``` Vous devriez voir `vantage-peers` avec la version `2.4.0`. Pour vérifier que les hooks fonctionnent, essayez de créer une tâche de test sans blocs VERIFICATION/TESTS : ``` /vantage-peers-init ``` Le hook `enforce-task-quality` bloquera tout appel `create_task` sans la structure requise. Les hooks s'exécutent silencieusement sur chaque appel d'outil correspondant. Ils n'apparaissent pas dans la conversation sauf s'ils bloquent une action. Si un hook bloque, il affiche la raison et le correctif — lisez le message avant de réessayer. Dépannage [#dépannage] | Symptôme | Cause | Correction | | ---------------------------------------------------------------- | ------------------------------------------- | ---------------------------------------------------------------------------------------------------- | | `/vantage-peers-init` échoue vérification 1 (enregistrement MCP) | `.mcp.json` introuvable ou malformé | Vérifiez que `.mcp.json` existe à la racine du workspace et que le JSON est valide | | `/vantage-peers-init` échoue vérification 2 (connectivité) | URL incorrecte ou service Railway en veille | Vérifiez le tableau de bord Railway — réveillez le service, vérifiez que l'URL se termine par `/mcp` | | `/vantage-peers-init` échoue vérification 3 (auth) | Mauvais secret Bearer | Vérifiez que `BEARER_SECRET` correspond à la variable d'env `BEARER_SECRET_MASTER` sur Railway | | Hook bloque de façon inattendue | Le contenu correspond à un pattern de hook | Lisez le message de blocage — il explique la règle et le correctif | --- # Skills URL: /fr/docs/toolkit/skills Skills [#skills] Les skills sont des protocoles de workflow réutilisables qui encodent les meilleures pratiques VP. Chaque skill est invoqué par une phrase déclencheuse (langage naturel) ou sa commande slash correspondante. Les skills utilisent les outils MCP VP en interne et appliquent des patterns comme Evidence-Bound Done et la doctrine T-VERIFY. Les 9 skills [#les-9-skills] check-messages [#check-messages] **Description :** Interroger les messages non lus d'autres orchestrateurs, répondre à ceux qui nécessitent une action, et (en mode autonome) choisir automatiquement la prochaine tâche todo non bloquée. **Phrases déclencheuses :** "check messages", "any messages", "inbox", "peers", "new messages" **Quand l'utiliser :** * Au début de chaque session pour vérifier le travail dispatché * En mode autonome pour chaîner les tâches (le skill s'auto-chaîne via l'Étape 6) * Quand un orchestrateur pair peut avoir envoyé des instructions ou terminé un travail délégué **Exemple :** ``` Utilisateur : check messages ``` Le skill détecte votre mode d'orchestrateur (humain vs autonome), interroge `check_messages`, affiche les messages non lus avec leurs expéditeurs, répond à ceux qui nécessitent une action, les marque comme lus, et en mode autonome choisit la prochaine tâche prioritaire. *** check-tasks [#check-tasks] **Description :** Récupérer toutes les tâches assignées à votre rôle d'orchestrateur, filtrer les tâches terminées, trier par priorité, et signaler les tâches bloquées. **Phrases déclencheuses :** "my tasks", "task list", "what should I work on", "backlog" **Quand l'utiliser :** * Pour avoir une vue d'ensemble de votre charge de travail actuelle * Avant de démarrer une session pour savoir ce qui est en file d'attente * Quand vous voulez voir les tâches bloquées et leurs bloqueurs **Exemple :** ``` Utilisateur : what should I work on today? ``` Le skill appelle `list_tasks` avec votre rôle assigné, groupe par priorité (urgent → high → medium → low), met en évidence les tâches bloquées avec leurs IDs de dépendances, et présente la prochaine tâche non bloquée. *** close-day [#close-day] **Description :** Routine de fin de journée — met à jour les statuts des tâches ouvertes, écrit une entrée de journal, stocke un résumé de session en mémoire, et appelle `set_summary` en état fermé. **Phrases déclencheuses :** "close day", "end of day", "wrap up", "close session" **Quand l'utiliser :** * À la fin d'une session de travail avant d'arrêter Claude Code * Avant une compaction de contexte planifiée **Exemple :** ``` Utilisateur : close day ``` Le skill demande des mises à jour en attente, écrit une entrée de journal pour aujourd'hui, stocke une mémoire `reference` avec les points saillants de la session, et définit le résumé de votre orchestrateur en état fermé/veille. *** daily-start [#daily-start] **Description :** Démarrage de session matinale — charge le contexte VP (mémoires récentes, tâches actives, messages), présente le plan de journée pour les opérateurs humains ou choisit automatiquement la tâche la plus prioritaire pour les orchestrateurs autonomes. **Phrases déclencheuses :** "start the day", "morning plan", "daily planning", "session start" **Quand l'utiliser :** * Au début de chaque session de travail * Lors de la reprise après une compaction de contexte **Exemple :** ``` Utilisateur : start the day ``` En mode humain : rappelle les mémoires récentes du projet, liste les tâches actives, vérifie les messages, et présente un plan de session proposé. En mode autonome : choisit et démarre directement la tâche non bloquée de plus haute priorité. *** pre-compact [#pre-compact] **Description :** Snapshot de session avant compaction de contexte — sauvegarde l'état complet de la session (missions actives, tâches, bloqueurs, résumé en 3 lignes) comme mémoire `reference` et note de briefing. **Phrases déclencheuses :** "save context", "before compaction", "snapshot session" **Quand l'utiliser :** * Quand Claude Code avertit que le contexte approche la limite * Avant de compacter intentionnellement pour continuer dans un contexte vierge **Exemple :** ``` Utilisateur : save context before compaction ``` Le skill appelle `store_memory` avec un snapshot de l'état de session actuel et `create_briefing_note` avec une note de passation structurée, pour que la prochaine session puisse `recall` exactement où les choses en étaient. *** recall [#recall] **Description :** Recherche hybride sémantique + BM25 sur les mémoires VP. Détecte automatiquement le namespace le plus probable à partir de la requête. **Phrases déclencheuses :** "recall", "search memory", "what do we know about", "look up" **Quand l'utiliser :** * Avant de répondre à toute question factuelle sur l'état du projet, l'historique ou les décisions * Quand vous avez besoin de trouver un fix pattern, une spec ou une décision précédemment stockés **Exemple :** ``` Utilisateur : recall what we decided about the auth architecture ``` Le skill construit une requête de recall hybride (sémantique + BM25), recherche dans le namespace pertinent (détecté automatiquement depuis le contexte de la requête), et retourne les mémoires les mieux correspondantes avec leurs types et namespaces. *** standup [#standup] **Description :** Générer un rapport de standup structuré (sections DONE / IN PROGRESS / BLOCKERS / GIT) et le déposer comme note de briefing. **Phrases déclencheuses :** "standup", "status report", "daily report", "sitrep" **Quand l'utiliser :** * Standup quotidien ou passation de shift * Quand un coordinateur d'équipe a besoin d'une mise à jour de statut structurée * Avant une réunion de planification **Exemple :** ``` Utilisateur : standup ``` Le skill appelle `list_tasks` pour les complétiions récentes et les éléments en cours, vérifie git pour les commits récents (si Bash est disponible), assemble le rapport en 4 sections, et appelle `create_briefing_note` avec le topic `standup`. *** vantage-peers-init [#vantage-peers-init] **Description :** Vérifier la configuration VP — contrôle l'enregistrement MCP, teste `/health`, et effectue un smoke-test d'auth via `recall`. Produit un rapport PASS/FAIL avec des instructions de correction spécifiques par échec. **Phrases déclencheuses :** "verify VP setup", "VP smoke test", "init vantage-peers" **Quand l'utiliser :** * Après l'installation initiale du plugin * Après avoir modifié `.mcp.json` ou le secret Bearer * Après un redéploiement Railway **Exemple :** ``` /vantage-peers-init ``` Les 3 vérifications doivent passer avant d'utiliser les autres skills. En cas d'échec, suivez l'instruction de correction spécifique affichée par le skill. *** write-diary [#write-diary] **Description :** Écrire une entrée de journal structurée — pose une question d'ancrage, puis construit une entrée avec les points saillants, les bloqueurs et une section de réflexion. **Phrases déclencheuses :** "write diary", "diary entry", "log today", "journal entry" **Quand l'utiliser :** * À la fin d'une session significative * Après l'accomplissement d'une étape importante * Dans le cadre du skill `close-day` (qui appelle celui-ci en interne) **Exemple :** ``` Utilisateur : write diary ``` Le skill demande "Quelle a été la chose la plus importante qui s'est passée aujourd'hui ?" puis appelle `write_diary` avec une entrée structurée couvrant les points saillants, ce qui a été appris, et les bloqueurs ouverts. --- # Erreurs courantes URL: /fr/docs/troubleshooting/common-errors Erreurs courantes [#erreurs-courantes] **Message d'erreur** : ``` Error: CONVEX_URL not found. Set it via: export CONVEX_URL=https://your-deployment.convex.cloud Or create a .env.local file with CONVEX_URL=... ``` **Cause** : le serveur MCP n'a pas trouvé d'URL de déploiement Convex dans l'environnement ou le fichier `.env.local`. **Correction** : Option A — variable d'environnement : ```bash export CONVEX_URL=https://votre-deploiement.convex.cloud ``` Option B — fichier `.env.local` dans le répertoire où vous lancez `npx vantage-peers-mcp` : ``` CONVEX_URL=https://votre-deploiement.convex.cloud ``` Trouvez l'URL de votre déploiement dans le [tableau de bord Convex](https://dashboard.convex.dev) → votre projet → Paramètres → URL de déploiement. **Message d'erreur** : ``` HTTP 401 Unauthorized {"error":"invalid_token","error_description":"Bearer token is missing or invalid"} ``` **Cause** : le transport HTTP requiert un jeton Bearer dans l'en-tête `Authorization`. Le jeton est soit manquant, soit expiré (OAuth), soit incorrect (non-concordance du token master). **Correction** : Pour le Bearer master (admin) : ```bash export BEARER_SECRET_MASTER=votre-secret-ici # Puis ajoutez dans la config du client MCP : Authorization: Bearer ``` Pour les tokens OAuth : ré-autorisez le client via le flux OAuth. Les tokens d'accès OAuth expirent — vérifiez que votre client se rafraîchit avec le token de rafraîchissement avant expiration. **Message d'erreur** : ``` MCP error: Tool 'tool_name' not found UnknownToolError: No tool registered with name 'tool_name' ``` **Cause** : le nom d'outil utilisé dans l'appel MCP ne correspond à aucun outil enregistré. Causes courantes : * Faute de frappe dans le nom de l'outil (ex. `list_task` au lieu de `list_tasks`) * Utilisation d'un outil supprimé dans une version plus récente * Ancien client MCP avec une liste d'outils mise en cache **Correction** : 1. Consultez la [Référence des outils](/docs/tools) pour le nom exact de l'outil 2. Appelez `tools/list` pour obtenir la liste des outils du serveur actuel 3. Si vous utilisez Claude Code, redémarrez la connexion au serveur MCP pour rafraîchir le cache **Message d'erreur** : ``` ZodError: [{"code":"invalid_type","expected":"string","received":"number","path":["assignedTo"]}] McpError: Invalid arguments for tool 'create_task' ``` **Cause** : les arguments passés à l'outil ne correspondent pas au schéma attendu. **Correction** : consultez le schéma de l'outil dans la [Référence des outils](/docs/tools). Problèmes courants : * Passer un nombre là où une chaîne est attendue (ex. `priority: 1` devrait être `priority: "high"`) * Passer un tableau comme chaîne JSON — le serveur normalise automatiquement la plupart des paramètres de tableau * Champs requis manquants **Message d'erreur** : ``` ConvexError: Function "tasks:list" not found Error calling Convex: Could not find function with path "memories:search" ``` **Cause** : le déploiement Convex n'a pas la fonction attendue. Cela se produit quand : * Le backend Convex n'est pas déployé ou utilise une ancienne version * `npx convex deploy` n'a pas été lancé après une mise à jour du code * CONVEX\_URL pointe vers le mauvais déploiement **Correction** : ```bash # Depuis la racine du repo vantage-peers : npx convex deploy --prod ``` **Symptôme** : `recall_memories` ou `search_memories` retourne un tableau vide, mais vous savez que des mémoires existent. **Cause** : les espaces de noms sont sensibles à la casse. `sigma` et `Sigma` sont des espaces de noms différents. **Correction** : utilisez des chaînes d'espaces de noms exactement en minuscules. Tous les orchestrateurs intégrés utilisent des lettres grecques minuscules (`sigma`, `pi`, `tau`, etc.). **Message d'erreur** : ``` GitHub API error: 403 rate limit exceeded X-RateLimit-Remaining: 0 ``` **Cause** : la variable d'environnement `GITHUB_TOKEN` n'est pas définie (limite non authentifiée : 60 req/heure) ou la limite de débit du token est épuisée. **Correction** : 1. Définissez `GITHUB_TOKEN` dans le tableau de bord Convex : * Paramètres → Variables d'environnement → `GITHUB_TOKEN` * Utilisez un token d'accès personnel fin avec les permissions `issues:read` et `issues:write` 2. Les requêtes authentifiées ont une limite de 5000 req/heure **Message d'erreur** : ``` connect ECONNREFUSED 127.0.0.1:3000 Error: fetch failed — connection refused ``` **Cause** : le serveur MCP HTTP ne tourne pas, ou tourne sur un port différent. **Correction** : ```bash cd mcp-server PORT=3000 CONVEX_URL=... BEARER_SECRET_MASTER=... node dist/server-http.js ``` Vérifiez qu'il écoute : ```bash curl http://localhost:3000/health ``` **Message d'erreur** : ``` TypeError: [stream-marker] wrapToolResult: invalid payload — ... ``` Ou `parseToolResult` retourne `null` quand vous attendez un résultat structuré. **Cause** : le payload n'est pas conforme à `VpToolResultSchema`. Problèmes courants : * La valeur de `kind` ne correspond pas à l'une des 6 chaînes autorisées * `diary-entry` et `briefing-note` utilisent `item` (singulier), pas `items` — confusion fréquente * Champs requis manquants (`_id`, `title` pour les tâches, etc.) **Correction** : ```ts const result = VpToolResultSchema.safeParse(payload) if (!result.success) { console.error('Erreur de schéma:', result.error.format()) } ``` Consultez la [référence du marqueur de flux](/docs/paradigm-b/stream-marker) pour la définition complète de l'union discriminée. **Symptôme** : `VP_EMIT_UI_MARKERS=1` est défini mais les réponses des outils ne contiennent pas de marqueurs. **Cause** : la variable d'environnement doit être définie dans le **tableau de bord Convex** (côté serveur), pas dans le fichier `.env.local` local ou l'environnement shell. **Correction** : 1. Ouvrez le tableau de bord Convex → votre déploiement → Paramètres → Variables d'environnement 2. Ajoutez `VP_EMIT_UI_MARKERS` avec la valeur `1` 3. Enregistrez — prend effet au prochain appel de fonction, sans redéploiement --- # Erreurs de workpool Convex URL: /fr/docs/troubleshooting/convex-workpool Erreurs de workpool Convex [#erreurs-de-workpool-convex] Message d'erreur [#message-derreur] ``` Error: Couldn't acquire a permit on this funrun ``` Variantes que vous pouvez également rencontrer : ``` WorkpoolError: All permits are currently in use ConvexError: funrun concurrency limit exceeded ``` Cause racine [#cause-racine] Convex impose une **limite de concurrence par déploiement** sur les exécutions de fonctions (funruns). Chaque déploiement sur l'offre gratuite est limité à un nombre fixe d'exécutions de fonctions simultanées. Lorsque VantagePeers effectue de nombreuses opérations d'agents en parallèle (écritures mémoire, mises à jour de tâches, envois de messages), les slots de concurrence se remplissent et les nouveaux funruns échouent à acquérir un permit. Il s'agit d'une **contrainte de la plateforme Convex**, pas d'un bug dans VantagePeers. L'erreur est la plus fréquente lorsque : * Plusieurs agents envoient des messages ou écrivent des mémoires simultanément (burst fleet) * Un job cron se déclenche en même temps qu'une activité agent intensive * Un agent exécute une requête de recherche (vecteur + BM25 hybride) pendant que d'autres écrivent Correction : patron de règle de filtre [#correction--patron-de-règle-de-filtre] La correction standard fleet est une **règle de filtre** qui limite ou diffère les opérations quand le workpool est saturé. **Identifiez les outils à haute fréquence** provoquant le burst. Coupables courants : `store_memory`, `send_message`, `create_task`, `update_task`. **Ajoutez un backoff exponentiel** à l'agent appelant ces outils : ```ts async function avecBackoff( fn: () => Promise, maxTentatives = 4, delaiBaseMs = 200 ): Promise { for (let tentative = 0; tentative <= maxTentatives; tentative++) { try { return await fn() } catch (err) { const estErreurWorkpool = err instanceof Error && (err.message.includes("Couldn't acquire a permit") || err.message.includes("WorkpoolError")) if (!estErreurWorkpool || tentative === maxTentatives) throw err const delai = delaiBaseMs * 2 ** tentative + Math.random() * 100 await new Promise((resolve) => setTimeout(resolve, delai)) } } throw new Error('inaccessible') } ``` **Pour les opérations fleet** (beaucoup d'agents écrivant simultanément), utilisez une **règle de filtre** pour sérialiser ou limiter le débit des écritures. ``` create_filter_rule({ pattern: "store_memory|update_task", priority: "low", action: "defer", deferMs: 500 }) ``` **Passez à Convex Pro** si vous atteignez régulièrement la limite. Les déploiements Pro ont des limites de concurrence nettement plus élevées. Voir la [page de tarification Convex](https://convex.dev/pricing). Vérifier l'utilisation actuelle des funruns [#vérifier-lutilisation-actuelle-des-funruns] Dans votre tableau de bord Convex : 1. Allez dans votre déploiement → onglet **Functions** 2. Triez par **Duration** — les fonctions longues maintiennent les permits plus longtemps 3. Vérifiez les **Logs** pour la fréquence des `WorkpoolError` Bursts liés aux crons [#bursts-liés-aux-crons] Les tâches récurrentes VantagePeers s'exécutent sur des actions planifiées Convex. Si vous avez de nombreuses tâches récurrentes avec le même intervalle, elles se déclenchent simultanément et se disputent les permits. **Correction** : décalez vos planifications de tâches récurrentes. * Agent sigma : `cronExpression: "0 * * * *"` (heure pile) * Agent tau : `cronExpression: "15 * * * *"` (15 après) * Agent phi : `cronExpression: "30 * * * *"` (30 après) N'interceptez pas et n'avalez pas silencieusement les `WorkpoolError`. Si une écriture mémoire ou un envoi de message échoue silencieusement, les agents opèreront sur des données périmées. Réessayez toujours ou remontez l'erreur. --- # Dépannage URL: /fr/docs/troubleshooting Dépannage [#dépannage] Cette section couvre les problèmes les plus courants rencontrés lors de l'exécution de VantagePeers en production. Chaque guide inclut une analyse de la cause racine et des instructions de correction étape par étape. Diagnostic rapide [#diagnostic-rapide] Avant de plonger dans les guides spécifiques, collectez ces informations : 1. **Version du serveur MCP** : `npm list vantage-peers-mcp` ou vérifiez `package.json` 2. **Déploiement Convex** : `npx convex dashboard` → Functions → erreurs récentes 3. **Variables d'environnement** : confirmez que `CONVEX_URL`, `AI_GATEWAY_API_KEY`, et optionnellement `VP_EMIT_UI_MARKERS` sont définies 4. **Transport** : stdio (Claude Code) ou HTTP (Railway / connecteur Claude.ai) Guides [#guides] Toujours bloqué ? [#toujours-bloqué-] * Consultez les [issues GitHub](https://github.com/vantageos-agency/vantage-peers/issues) — recherchez votre message d'erreur * Consultez le [tableau de bord Convex](https://dashboard.convex.dev) → onglet Logs pour les erreurs côté serveur * Ouvrez une nouvelle issue avec votre version du serveur MCP, le type de transport et le message d'erreur exact --- # Embeddings RAG URL: /fr/docs/troubleshooting/rag-embeddings Embeddings RAG [#embeddings-rag] VantagePeers utilise `@convex-dev/rag` avec **text-embedding-3-small** (1536 dimensions) pour la recherche sémantique de mémoires et la recherche hybride (vecteur + BM25). Configuration [#configuration] Variables d'environnement [#variables-denvironnement] À définir dans votre tableau de bord Convex (Paramètres → Variables d'environnement) : | Variable | Requis | Description | | --------------------- | ------ | -------------------------------------------------------------------- | | `AI_GATEWAY_API_KEY` | Oui | Clé API compatible OpenAI pour le modèle d'embedding | | `AI_GATEWAY_BASE_URL` | Non | Remplacement pour passerelle compatible OpenAI (défaut : API OpenAI) | `AI_GATEWAY_API_KEY` accepte les clés API OpenAI standard (`sk-...`) ou toute clé de passerelle compatible OpenAI (ex. Azure OpenAI, OpenRouter). Le nom du modèle d'embedding est codé en dur à `text-embedding-3-small`. Vérifier la configuration [#vérifier-la-configuration] Après avoir défini la clé, testez-la en appelant `search_memories` : ``` search_memories({ query: "test", namespace: "sigma", limit: 1 }) ``` Si elle retourne des résultats (ou un tableau vide), les embeddings fonctionnent. Si elle lève une exception, consultez les erreurs ci-dessous. *** Erreurs courantes [#erreurs-courantes] `AI_GATEWAY_API_KEY` non définie [#ai_gateway_api_key-non-définie] ``` Error: AI_GATEWAY_API_KEY is not set. Configure it in Convex dashboard → Settings → Environment Variables. ``` **Correction** : Ouvrez le [tableau de bord Convex](https://dashboard.convex.dev) Sélectionnez votre déploiement → **Paramètres** → **Variables d'environnement** Ajoutez `AI_GATEWAY_API_KEY` avec votre valeur de clé API OpenAI Enregistrez — la modification prend effet immédiatement, sans redéploiement *** Limite de débit dépassée [#limite-de-débit-dépassée] ``` Error: 429 Too Many Requests — Rate limit reached for text-embedding-3-small OpenAI error: You exceeded your current quota ``` **Cause racine** : votre compte OpenAI a atteint sa limite de débit d'embedding. Cela se produit quand de nombreux agents recherchent ou stockent des mémoires simultanément. **Options de correction** : Ajoutez un délai entre les opérations intensives en embedding. Les écritures mémoire (`store_memory`) génèrent un embedding par appel. Regrouper les écritures en chaînes `content` plus grandes réduit le nombre total de requêtes d'embedding. ```ts // Au lieu de plusieurs petites mémoires : store_memory({ content: "fait 1", namespace: "sigma" }) store_memory({ content: "fait 2", namespace: "sigma" }) // Combinez en une seule : store_memory({ content: "fait 1\n\nfait 2", namespace: "sigma" }) ``` Passez votre compte OpenAI au Niveau 2 ou supérieur. Le Niveau 1 (nouveaux comptes) a une limite de 1M tokens/minute pour text-embedding-3-small. Le Niveau 2 l'augmente à 10M tokens/minute. Routez les embeddings via une passerelle qui gère la limitation de débit pour vous (ex. Azure OpenAI, OpenRouter). Définissez `AI_GATEWAY_BASE_URL` sur l'endpoint de votre passerelle et `AI_GATEWAY_API_KEY` sur votre clé de passerelle. *** Incompatibilité de dimensions [#incompatibilité-de-dimensions] ``` Error: Vector dimension mismatch: expected 1536, got 1024 ConvexError: Index dimension does not match stored vectors ``` **Cause racine** : l'index vectoriel Convex pour les mémoires a été créé avec une dimension (ex. 1536 de text-embedding-3-small) mais le modèle d'embedding actuel retourne une dimension différente. Corriger une incompatibilité de dimensions nécessite de ré-embedder toutes les mémoires existantes. Cela ne peut pas se faire sans migration de données. **Correction** : vérifiez `AI_GATEWAY_BASE_URL`. Si vous n'avez pas changé de modèle intentionnellement, retirez `AI_GATEWAY_BASE_URL` pour restaurer text-embedding-3-small à 1536 dims. *** Délai d'attente d'embedding dépassé [#délai-dattente-dembedding-dépassé] ``` Error: Embedding request timed out after 30000ms ``` **Cause racine** : l'appel API d'embedding n'a pas répondu dans le délai imparti de la fonction Convex. Rare avec OpenAI direct, mais possible avec des passerelles lentes. **Correction** : vérifiez la latence de la passerelle. Passez à OpenAI direct si votre passerelle est lente. Réduisez la taille du contenu — gardez chaque mémoire sous 8000 tokens. *** Référence du modèle d'embedding [#référence-du-modèle-dembedding] | Propriété | Valeur | | ----------------- | --------------------------------- | | Modèle | `text-embedding-3-small` | | Fournisseur | OpenAI (ou passerelle compatible) | | Dimensions | **1536** | | Entrée maximale | 8191 tokens | | Mode de recherche | Similarité cosinus | | Type d'index | Index vectoriel Convex | | Recherche hybride | Fusion RRF (vecteur + BM25) | --- # VP-Sources answer-footer doctrine URL: /fr/docs/cloud/doctrine/vp-sources-footer VP-Sources answer-footer doctrine [#vp-sources-answer-footer-doctrine] What this doctrine says [#what-this-doctrine-says] Each of the 5 covered tools embeds two verbatim doctrine paragraphs appended after the existing tool description: > **VP-Sources doctrine**: MUST be called before any factual claim about fleet state, audits, dette tooling, mission/task/client status, incident history, doctrine references. > Cite returned ids in the answer footer as `VP-Sources: recall("")→[ids] | none-needed:`. These two strings appear verbatim in every covered tool's `description` field. Any MCP client that requests the tool list receives them inline — no additional system prompt injection is required. Why [#why] MCP clients receive the full tool list (names + descriptions) in a single response before the first tool call. Embedding the doctrine there means any agent that calls one of the 5 covered tools has already been instructed about the citation obligation at tool-list time. The alternative — adding the rule to a system prompt — requires every client deployment to be updated independently. Inline embedding is deployment-agnostic: it travels with the tool definition. Tools covered [#tools-covered] The following 5 tools carry the VP-Sources doctrine strings as of PR-H (T-GREEN `908fd67`): | Tool | Exported constant (mcp-server/src/tools.ts) | | ---------------------------------- | --------------------------------------------------- | | `recall` | `RECALL_TOOL_DESCRIPTION` | | `hybrid_search` | `HYBRID_SEARCH_TOOL_DESCRIPTION` | | `text_search` | `TEXT_SEARCH_TOOL_DESCRIPTION` | | `list_briefing_notes` | `LIST_BRIEFING_NOTES_TOOL_DESCRIPTION` | | `search_briefing_notes_by_keyword` | `SEARCH_BRIEFING_NOTES_BY_KEYWORD_TOOL_DESCRIPTION` | Each constant is exported from `mcp-server/src/tools.ts` and tested with a snapshot assertion in `mcp-server/src/__tests__/tools-descriptions.test.ts`. Footer format [#footer-format] When a search tool returns results the agent must cite them in the final answer footer. **Full citation (sources found):** ``` VP-Sources: recall("Pi feedback rules")→[j57dy3049btafda9m2f5d2ggk987ph3f, j572s2bh4e0n20n0ttxynwrnts891nb5] ``` **No search needed:** ``` VP-Sources: none-needed:trivial code edit ``` **Worked example** — an agent answers a question about current mission status: 1. Agent calls `recall` with `query="VP-MCP top level Bloc A mission status"`. 2. Search returns documents `k571gcctka8mq5jbkgpj0a0b2n892ctg` and `k977bvf03qzas7v7g0zqca9c7n8937zh`. 3. Agent answers the question based on those documents. 4. Footer: ``` VP-Sources: recall("VP-MCP top level Bloc A mission status")→[k571gcctka8mq5jbkgpj0a0b2n892ctg, k977bvf03qzas7v7g0zqca9c7n8937zh] ``` The footer is appended to the agent's final answer, not to intermediate reasoning steps. One footer per user-facing response is sufficient even if multiple tool calls were made. Advisory only [#advisory-only] No hook enforces absence of the footer. An agent that omits the footer will not be blocked. This is intentional. The doctrine is designed for progressive adoption: * Agents that implement it immediately gain auditability and trust with human reviewers. * Agents that do not implement it are not broken — they simply lack the citation trail. * A blocking hook would create friction for all callers including non-VP clients using the same MCP server. The advisory status may be revisited in a future sprint if adoption data shows systematic omission. When `none-needed` is acceptable [#when-none-needed-is-acceptable] Use `none-needed:` when a factual search was genuinely not required: * Trivial mechanical code edit with no claim about system state (e.g. renaming a variable). * Calling a tool that returns the answer directly (`get_task`, `get_mission`, `whoami`) — the tool ID itself is the source. * Pure arithmetic or string formatting with no fleet-state dependency. * Iterative follow-up in the same tool-call chain where all sources are already cited in the prior response. * The user asked a question answerable from the current conversation context alone. Do not use `none-needed` to avoid searching. If the answer involves any claim about fleet state, doctrine, task status, or incident history, call one of the 5 covered tools first. References [#references] * Doctrine source: Eta Q1 msg `k977bvf03qzas7v7g0zqca9c7n8937zh` * Mission: `k571gcctka8mq5jbkgpj0a0b2n892ctg` (VP-MCP top level Bloc A) * Audit sections 27+28.4 * T-RED `0b4dc84`, T-GREEN `908fd67` * MCP tool references: [list\_briefing\_notes](/docs/cloud/mcp-tools/list-bus), [list\_bus](/docs/cloud/mcp-tools/list-bus), [list\_components](/docs/cloud/mcp-tools/list-components), [list\_repo\_mappings](/docs/cloud/mcp-tools/list-repo-mappings) --- # bulk_complete_tasks URL: /fr/docs/cloud/mcp-tools/bulk-complete-tasks bulk_complete_tasks [#bulk_complete_tasks] Bulk-close tasks that match a filter in one atomic mutation. Introduced in PR-F (merged commit `4c068d2` after Eta REVISE round addressing blast-radius / scope / caller-gate hardening). Designed to safely drain cron-spam backlogs accumulated from auto-generated `check-messages` polling tasks. `dryRun` defaults to `true`. The tool never mutates the database unless you explicitly pass `dryRun: false`. Always preview first to confirm the count, then call again with `dryRun: false` to commit. Closed tasks are irreversible — status is permanently set to `done`. Safety contract (iter-2 hardening) [#safety-contract-iter-2-hardening] The mutation enforces three guardrails before any write: | Guardrail | Throws | When | | ----------------------------------- | ------------------------ | ---------------------------------------------------------------------------------------------- | | **Reductive filter required** | `BULK_FILTER_TOO_BROAD` | Neither `filter.autoGeneratedOnly: true` nor `filter.assignedTo` set — match-all is forbidden. | | **Caller required for live commit** | `BULK_CALLER_REQUIRED` | `dryRun: false` with no `callerOrchestrator` — default-deny on the destructive path. | | **Blast-radius cap** | `BULK_HARD_CAP_EXCEEDED` | Matched count exceeds `BULK_COMPLETE_HARD_CAP = 500` — narrow the filter and retry. | Backing implementation uses a `withIndex("by_status")` iterator with early-stop at `cap+1` to count without scanning the full table. Args [#args] | Arg | Type | Default | Description | | -------------------------- | ------- | ----------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | `filter` | object | (required) | Filter object controlling which tasks are matched. MUST contain at least one reductive predicate (`autoGeneratedOnly: true` OR `assignedTo: ""`) — else throws `BULK_FILTER_TOO_BROAD`. | | `filter.autoGeneratedOnly` | boolean | `false` | When `true`, matches tasks where `createdBy` matches `/^cron-/i` OR `title` matches `/^\/?check-messages$/i`. | | `filter.assignedTo` | string | — | When set, narrows matches to tasks whose `assignedTo` equals this role. Combined with `autoGeneratedOnly` via AND. | | `dryRun` | boolean | `true` | Safety default. `true` returns a preview without mutating. Pass `false` explicitly to commit (requires `callerOrchestrator`). | | `completionNoteTemplate` | string | (see below) | Template string written as `completionNote` on each closed task. Supports `{{day}}`, `{{bulkRunId}}`, `{{executedAt}}` interpolation. Default: `"bulk-cleanup: cron-spam day {{day}} runId={{bulkRunId}} executedAt={{executedAt}}"`. | | `callerOrchestrator` | string | — | Caller identity for RBAC. **Required for `dryRun: false`** (default-deny). When provided and not `"system"`, every matched task must have `createdBy` or `assignedTo` equal to the caller. | Returns [#returns] `dryRun=true` (preview — default) [#dryruntrue-preview--default] ```ts { count: number, // number of tasks that would be closed (≤ BULK_COMPLETE_HARD_CAP) sampleIds: string[], // up to 10 matching task IDs bulkRunId: string, // unique run ID (Day-76 evidence token, pre-generated) cappedAt?: number // present iff matched count was truncated at the 500-cap; caller must narrow filter } ``` `dryRun=false` (commit) [#dryrunfalse-commit] ```ts { count: number, // number of tasks closed sampleIds: string[], // up to 10 closed task IDs bulkRunId: string, // unique run ID used in every completionNote executedAt: number // epoch ms when the mutation ran } ``` Examples [#examples] Dry-run preview (default behavior) [#dry-run-preview-default-behavior] ```jsonc // call — dryRun=true is the default; this call never mutates { "filter": { "autoGeneratedOnly": true }, "callerOrchestrator": "system" } // response { "count": 152, "sampleIds": ["k17abc...", "k17def...", "k17ghi..."], "bulkRunId": "bulk-1782050000000-a3f2" } ``` Live bulk close with custom completion note template [#live-bulk-close-with-custom-completion-note-template] ```jsonc // call — explicit dryRun=false with custom template { "filter": { "autoGeneratedOnly": true }, "dryRun": false, "completionNoteTemplate": "bulk-cleanup: cron-spam day {{day}} runId={{bulkRunId}}", "callerOrchestrator": "system" } // response { "count": 152, "sampleIds": ["k17abc...", "k17def...", "k17ghi..."], "bulkRunId": "bulk-1782050000000-a3f2", "executedAt": 1782050000000 } ``` RBAC-gated call (orchestrator-scoped) [#rbac-gated-call-orchestrator-scoped] ```jsonc // call — pi can only close tasks it created or was assigned { "filter": { "autoGeneratedOnly": true }, "dryRun": false, "callerOrchestrator": "pi" } // response (all matched tasks belong to pi) { "count": 8, "sampleIds": ["k17jkl...", "k17mno..."], "bulkRunId": "bulk-1782050000001-c9d4", "executedAt": 1782050000001 } ``` Cron contract [#cron-contract] The `autoGeneratedOnly` filter matches tasks that satisfy either predicate below. This is the same contract used by `list_tasks excludeAutoGenerated` (PR-E). | Predicate | Pattern | Example matches | Example non-matches | | ----------- | --------------------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------- | | `createdBy` | `/^cron-/i` (dash mandatory) | `cron-bot`, `cron-daily` | `cronus`, `cron` (no dash) | | `title` | `/^\/?check-messages$/i` (whole-string, optional leading slash) | `check-messages`, `/check-messages`, `CHECK-MESSAGES` | `check-messages-v2`, `run check-messages` | **Filter placement:** applied in-memory against all non-done tasks, before any mutation is executed. Day-76 evidence-bound completionNote [#day-76-evidence-bound-completionnote] Every task closed by `bulk_complete_tasks` receives a `completionNote` that satisfies the Day-76 Evidence-Bound Done doctrine. The default template injects two verifiable proof tokens: * `{{day}}` — project day number computed from epoch `2026-03-06 UTC`. Unique per calendar day. * `{{bulkRunId}}` — format `bulk--`. Unique per run, consistent across all tasks closed in that run. * `{{executedAt}}` — epoch ms timestamp of the mutation. Default note written to each task: `"bulk-cleanup: cron-spam day {{day}} runId={{bulkRunId}} executedAt={{executedAt}}"` (with values interpolated). This means every closed task carries a traceable, auditable proof token — the `bulkRunId` links the batch, and `day` scopes it to a human-readable project timeline. Callouts [#callouts] **Blast-radius cap:** the iterator uses `withIndex("by_status")` to scan only non-done tasks with early-stop at `BULK_COMPLETE_HARD_CAP + 1 = 501`. Matched count above 500 throws `BULK_HARD_CAP_EXCEEDED` — narrow the filter (e.g. add `assignedTo`) and retry. Dry-run output carries `cappedAt: 500` when truncation applies. **Reductive filter required:** a filter with neither `autoGeneratedOnly: true` nor `assignedTo` set is rejected with `BULK_FILTER_TOO_BROAD`. Match-all is forbidden by design — destructive surface must always be scoped. **RBAC + caller gate:** `dryRun: false` without `callerOrchestrator` throws `BULK_CALLER_REQUIRED` (default-deny on the destructive path). When provided and not `"system"`, every matched task must have `createdBy` or `assignedTo` equal to the caller, else the entire mutation throws `RBAC_DENIED` — no partial close. Use `"system"` to bypass RBAC for fleet-wide cleanup. **Why this matters:** before PR-F, cron-spam tasks could only be listed (with `excludeAutoGenerated`) but not closed in bulk. Pi's queue accumulated 152 cron-spawned tasks (audit section 13) that required individual `complete_task` calls to clear. `bulk_complete_tasks` drains the full backlog in two calls — one preview, one commit — with a verifiable audit trail via `bulkRunId`. --- # improvisation_digest URL: /fr/docs/cloud/mcp-tools/improvisation-digest improvisation_digest [#improvisation_digest] Scan a rolling time window of VP tasks, messages, and memories for records that carry durable-artifact fleet/state tokens (commit SHA, PR number, VP document ID, or decisive verb such as `merged`, `deployed`, `approved`) but have **no VP-Sources footer**. This is the Eta heuristic proxy for an orchestrator having made a fleet-state claim without a prior `recall` upstream. ADVISORY-only — pure read query. `improvisation_digest` never blocks any action. Results are informational: a high improvisation rate indicates a team should increase VP-Sources citation hygiene, but the tool itself takes no automated action and has no side effects. Args [#args] | Arg | Type | Default | Description | | --------------- | --------- | ------- | ----------------------------------------------------------------------------------------------- | | `windowDays` | number | `7` | Number of days to look back. | | `orchestrators` | string\[] | — | Scope to these orchestrator roles only (e.g. `["sigma","pi"]`). Omit to scan all orchestrators. | Returns [#returns] ```ts { countsByOrch: Record, // hit count per orchestrator countsByCategory: Record, // hit count per record type: "task" | "message" | "memory" samples: Array<{ // up to 50 representative snippets id: string, category: string, orchestrator: string, snippet: string }> } ``` `countsByOrch` and `countsByCategory` are both zero-initialized for all observed orchestrators/categories — entries with zero hits are omitted from the returned map. `samples` is sorted newest-first and capped at 50 entries. Examples [#examples] Default 7-day window across all orchestrators [#default-7-day-window-across-all-orchestrators] ```jsonc // call { "windowDays": 7 } // response (illustrative) { "countsByOrch": { "sigma": 3, "pi": 1 }, "countsByCategory": { "task": 2, "message": 2 }, "samples": [ { "id": "k17abc...", "category": "task", "orchestrator": "sigma", "snippet": "completionNote: merged PR #954 into main — VP-MCP top level..." }, { "id": "k97def...", "category": "message", "orchestrator": "pi", "snippet": "deployed vantage-peers-mcp@2.13.0 to Railway at commit ef91f6f" } ] } ``` Scoped to a single orchestrator [#scoped-to-a-single-orchestrator] ```jsonc // call — audit sigma's last 14 days { "windowDays": 14, "orchestrators": ["sigma"] } // response — only sigma records are evaluated { "countsByOrch": { "sigma": 5 }, "countsByCategory": { "task": 3, "memory": 2 }, "samples": [ { "id": "k17xxx...", "category": "memory", "orchestrator": "sigma", "snippet": "approved PR-C — list_repo_mappings envelope safety shipped at 4ddca2b" } ] } ``` Detection heuristic (Eta A5 scope filter) [#detection-heuristic-eta-a5-scope-filter] A record is flagged when **both** conditions hold simultaneously: | Condition | Check | | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | **Durable-artifact token present** | Body contains at least one of: 7–40 hex commit SHA; `#NNN` PR/issue ref; Convex document ID (`k1…` or `j…` prefix); decisive verb (`merged`, `deployed`, `approved`, `shipped`, `released`, `fixed`). | | **VP-Sources footer absent** | Body does NOT contain the `VP-Sources:` substring. | **A5 scope exclusions** — the following are never flagged regardless of content: * Records authored by `system` * Records where `createdBy` matches `/^cron-/i` (dash mandatory) * Records originating from webhook ingestion paths The A5 exclusions prevent false positives from automated infrastructure records that legitimately reference SHAs or PR numbers without a VP-Sources footer obligation. V1 scope and V2 roadmap [#v1-scope-and-v2-roadmap] V1 (current) scans VP records only — tasks, messages, and memories stored in VantagePeers (Option C). Per Pi Day-113 arbitration (msg `k97a0pp6kq1axkj6cmc4pecpy989ce1w`), the fallback if V1 misses too many improvisations is **Option B** — a new dedicated `sessions` Convex table — **not** Option A (transcript-replay from JSONL conversation logs). V1 was selected because VP records are already structured, queryable, and authorship-attributed. Monitor `countsByOrch` trends over 2–4 weeks; if V1 coverage proves insufficient (because agents do not store all fleet-state claims as VP records), the next iteration introduces a dedicated `sessions` table (Option B) where the digest can pull richer per-session context without the transcript ingestion pipeline complexity of Option A. Cross-reference [#cross-reference] * [VP-Sources answer-footer doctrine](/docs/cloud/doctrine/vp-sources-footer) — full reference including worked examples, `none-needed` acceptable cases, and advisory-only rationale. * Convex query: `improvisationDigest:scanWindow` * Mission: `k571gcctka8mq5jbkgpj0a0b2n892ctg` (VP-MCP top level Bloc A, PR-I) * T-RED `cd6cda3` · T-GREEN `b9414dc` --- # list_bus URL: /fr/docs/cloud/mcp-tools/list-bus list_bus [#list_bus] List business units (BUs) registered in VantagePeers, with pagination, projection (`lite|full`), and optional filters. Args [#args] | Arg | Type | Default | Description | | ---------------- | --------------------------------------------- | -------- | --------------------------------------------------------------------------------------------- | | `orchestratorId` | string | — | Filter by lead orchestrator (e.g. `"sigma"`). | | `status` | `"idea" \| "building" \| "live" \| "revenue"` | — | Filter by lifecycle status. | | `limit` | number 1-200 | `20` | Page size. Default `20`, capped at `200`. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (5 keys). `"full"` returns complete BU object (18+ keys). | Returns [#returns] ```ts { items: BusinessUnit[] | BusinessUnitLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Compact list (fields=lite) [#compact-list-fieldslite] ```jsonc // call { "limit": 20, "fields": "lite" } // response (~5KB for 100 BUs) { "items": [ { "_id": "j5xxx...", "_creationTime": 1782050000000, "name": "VantagePeers", "status": "live", "orchestratorId": "sigma" } ], "nextCursor": "eyJjcmVhdGlvblRpbWUiOjE3ODIwNDk5MDAwMDAsImlkIjoiajV5eXkifQ==" } ``` Detailed single BU (fields=full + limit=1) [#detailed-single-bu-fieldsfull--limit1] ```jsonc { "orchestratorId": "sigma", "limit": 1, "fields": "full" } ``` Returns the full BU record (name, description, purpose, businessModel, targetCustomers, services, pricing, revenueProjections, coreTeam, etc.). Paginate through all live BUs [#paginate-through-all-live-bus] ```jsonc // page 1 { "status": "live", "limit": 20 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "status": "live", "limit": 20, "cursor": "" } ``` Pagination + envelope safety [#pagination--envelope-safety] `list_bus` follows the standard VantagePeers envelope safety pattern (PR-A): * **Default limit**: `20`. Keeps payloads small (\~2-5KB) for typical interactive calls. * **Cap**: `200`. Requests with `limit > 200` are clamped server-side. * **fields=lite**: projects to 5 stable keys (`_id`, `_creationTime`, `name`, `status`, `orchestratorId`). Payload stays under 25KB even for 100 BUs. * **Cursor**: opaque token encoding `{creationTime, id}` to survive same-millisecond inserts. Treat as opaque — do not parse client-side. Same pattern applies to `list_components` (PR-B) and `list_repo_mappings` (PR-C). Why this matters [#why-this-matters] Before PR-A: `list_bus` had no cap, `fields=lite` was a no-op (returned full rows), and default limit was 50. A fleet with many BUs could return a 64KB+ payload, overflowing the MCP envelope (25K-token cap) in client sessions. PR-A enforces strict defaults and an actual lite projection, eliminating envelope overflow as a failure mode. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 9. --- # list_components URL: /fr/docs/cloud/mcp-tools/list-components list_components [#list_components] List components (agents, skills, hooks, plugins) registered in VantagePeers, with pagination, projection (`lite|full`), and optional filters. Args [#args] | Arg | Type | Default | Description | | -------- | ------------------------------------------ | -------- | ----------------------------------------------------------------------------------------- | | `type` | `"agent" \| "skill" \| "hook" \| "plugin"` | — | Filter by component type. | | `team` | string | — | Filter by team (e.g. `"development"`). | | `limit` | number 1-200 | `20` | Page size. Default `20`, capped at `200`. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (5 keys). `"full"` returns complete component object. | Returns [#returns] ```ts { items: Component[] | ComponentLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Compact list (fields=lite) [#compact-list-fieldslite] ```jsonc // call { "limit": 20, "fields": "lite" } // response (~3KB for 100 components) { "items": [ { "_id": "j5xxx...", "_creationTime": 1782050000000, "name": "dev-convex-expert", "type": "agent", "team": "development" } ], "nextCursor": "eyJjcmVhdGlvblRpbWUiOjE3ODIwNDk5MDAwMDAsImlkIjoiajV5eXkifQ==" } ``` Paginate through all skill components [#paginate-through-all-skill-components] ```jsonc // page 1 { "type": "skill", "limit": 20 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "type": "skill", "limit": 20, "cursor": "" } ``` Pagination + envelope safety [#pagination--envelope-safety] `list_components` follows the standard VantagePeers envelope safety pattern (PR-B): * **Default limit**: `20`. Keeps payloads small (\~2-3KB) for typical interactive calls. * **Cap**: `200`. Requests with `limit > 200` are clamped server-side. * **fields=lite**: projects to 5 stable keys (`_id`, `_creationTime`, `name`, `type`, `team`). Payload stays under 25KB even for 100 components. * **Cursor**: opaque token encoding `{creationTime, id}` to survive same-millisecond inserts. Treat as opaque — do not parse client-side. * **Hybrid cursor decode**: old-format `{createdBefore}` cursors (S3.3 B8 callers) are decoded and forwarded as `createdBefore` for back-compat. New-format opaque cursors pass through directly. Same pattern applies to `list_bus` (PR-A) and `list_repo_mappings` (PR-C). Why this matters [#why-this-matters] Before PR-B: `list_components` had no cap, `fields=lite` was a no-op (returned full rows regardless), and default limit was 100. A registry with many components could return a 64KB+ payload, overflowing the MCP envelope (25K-token cap) in client sessions. PR-B enforces strict defaults and an actual lite projection, eliminating envelope overflow as a failure mode. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 9. --- # list_repo_mappings URL: /fr/docs/cloud/mcp-tools/list-repo-mappings list_repo_mappings [#list_repo_mappings] List GitHub repository to orchestrator webhook mappings registered in VantagePeers, newest first, with pagination and projection (`lite|full`). Args [#args] | Arg | Type | Default | Description | | -------- | ------------------ | -------- | --------------------------------------------------------------------------------------- | | `limit` | number 1-200 | `20` | Page size. Default `20`, capped at `200`. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (5 keys). `"full"` returns complete mapping object. | Returns [#returns] ```ts { items: RepoMapping[] | RepoMappingLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Compact list (fields=lite) [#compact-list-fieldslite] ```jsonc // call { "limit": 20, "fields": "lite" } // response (~2KB for 100 mappings) { "items": [ { "_id": "j5xxx...", "_creationTime": 1782050000000, "repo": "vantageos-agency/vantage-peers", "orchestrator": "sigma", "project": "vantage-peers" } ], "nextCursor": "eyJ0aW1lIjoxNzgyMDQ5OTAwMDAwLCJpZCI6Imo1eXl5In0=" } ``` Paginate through all mappings [#paginate-through-all-mappings] ```jsonc // page 1 { "limit": 20 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "limit": 20, "cursor": "" } ``` Pagination + envelope safety [#pagination--envelope-safety] `list_repo_mappings` follows the standard VantagePeers envelope safety pattern (PR-C): * **Default limit**: `20`. Keeps payloads small (\~2KB) for typical interactive calls. * **Cap**: `200`. Requests with `limit > 200` are clamped server-side. * **fields=lite**: projects to 5 stable keys (`_id`, `_creationTime`, `repo`, `orchestrator`, `project`). Excludes `active`, `lastDeployedSHA`, `lastDeployedAt`. * **Cursor**: opaque token encoding `{time, id}` to survive same-millisecond inserts. Treat as opaque — do not parse client-side. * **Hybrid cursor decode**: old-format `{createdBefore}` cursors (S3.3 B8 batch 2 callers) are decoded and forwarded as `createdBefore` for back-compat. New-format opaque cursors pass through directly. Same pattern applies to `list_bus` (PR-A) and `list_components` (PR-B). Why this matters [#why-this-matters] Before PR-C: `list_repo_mappings` had no cap, `fields=lite` was a no-op (returned full rows regardless), and default limit was 50. A deployment with many repo mappings could return a large payload, overflowing the MCP envelope (25K-token cap) in client sessions. PR-C enforces strict defaults and an actual lite projection, eliminating envelope overflow as a failure mode. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 9. --- # list_tasks URL: /fr/docs/cloud/mcp-tools/list-tasks list_tasks [#list_tasks] List tasks registered in VantagePeers, newest-updated first, with pagination, projection (`lite|full`), status filters, and the `excludeAutoGenerated` cron-spam filter introduced in PR-E. Args [#args] | Arg | Type | Default | Description | | ---------------------- | ---------------------------- | -------- | ------------------------------------------------------------------------------------- | | `assignedTo` | string | — | Filter by assignee (e.g. `"pi"`). | | `status` | string \| string\[] \| alias | — | Single status, array, or alias (`"open"`, `"active"`, `"all"`). | | `missionId` | string | — | Filter to tasks belonging to a specific mission. | | `createdBy` | string | — | Filter by creator (e.g. `"sigma"`). | | `updatedSince` | number | — | Epoch ms. Returns tasks with `updatedAt >= this`. | | `createdBefore` | number | — | Epoch ms. Pagination anchor (legacy; prefer `cursor`). | | `limit` | number 1-200 | `50` | Page size. | | `cursor` | string | — | Opaque pagination token returned as `nextCursor` from prior call. | | `fields` | `"lite" \| "full"` | `"full"` | `"lite"` returns compact projection (7 keys). `"full"` returns complete task object. | | `excludeAutoGenerated` | boolean | `false` | When `true`, filters out cron-generated tasks. Default `false` — backward-compatible. | Returns [#returns] ```ts { items: Task[] | TaskLite[], nextCursor: string | null } ``` `nextCursor` is `null` when the current page is the last one; non-null when more rows exist. Examples [#examples] Default query (all open tasks for an agent) [#default-query-all-open-tasks-for-an-agent] ```jsonc // call { "assignedTo": "pi", "status": "open", "fields": "lite", "limit": 30 } // response { "items": [ { "_id": "k17xxx...", "_creationTime": 1782050000000, "title": "Review PR-E docs", "status": "review", "priority": "high", "assignedTo": "pi", "missionId": "k571gcctka8mq5jbkgpj0a0b2n892ctg" } ], "nextCursor": null } ``` Exclude cron-generated tasks (`excludeAutoGenerated=true`) [#exclude-cron-generated-tasks-excludeautogeneratedtrue] ```jsonc // call — Pi queue cleaned of cron-spam (audit §13: 152 cron tasks) { "assignedTo": "pi", "status": "open", "excludeAutoGenerated": true, "limit": 50 } // response — only human-dispatched tasks; cron-bot + check-messages rows absent { "items": [ { "_id": "k17yyy...", "_creationTime": 1782050100000, "title": "Validate VP-MCP PR-E", "status": "todo", "priority": "high", "assignedTo": "pi", "missionId": "k571gcctka8mq5jbkgpj0a0b2n892ctg" } ], "nextCursor": "eyJ0aW1lIjoxNzgyMDUwMDAwMDAwLCJpZCI6Ims1eHh4In0=" } ``` Paginate through results [#paginate-through-results] ```jsonc // page 1 { "assignedTo": "pi", "status": "open", "excludeAutoGenerated": true, "limit": 50 } // → { items: [...], nextCursor: "..." } // page 2 (use nextCursor) { "assignedTo": "pi", "status": "open", "excludeAutoGenerated": true, "limit": 50, "cursor": "" } ``` `excludeAutoGenerated` cron contract [#excludeautogenerated-cron-contract] The `excludeAutoGenerated` filter removes tasks that match either of these predicates: | Predicate | Pattern | Example matches | Example non-matches | | ----------- | --------------------------------------------------------------- | ----------------------------------------------------- | ----------------------------------------- | | `createdBy` | `/^cron-/i` (dash mandatory) | `cron-bot`, `cron-daily` | `cronus`, `cron` (no dash) | | `title` | `/^\/?check-messages$/i` (whole-string, optional leading slash) | `check-messages`, `/check-messages`, `CHECK-MESSAGES` | `check-messages-v2`, `run check-messages` | **Filter placement:** applied in-memory in the `list` query handler, after `createdBy` / `updatedSince` / `createdBefore` filters, before `filterByOrgScope` and envelope assembly. Post-filter pages may be smaller than `limit` because filtered rows do not count toward the page fill. This is by design — the cron-spam catalog is small and narrowly targeted, so pages will rarely shrink significantly. If you need exactly N human tasks, over-fetch with a larger `limit` and truncate client-side. `fields=lite` projection [#fieldslite-projection] `"lite"` returns 7 stable keys: `_id`, `_creationTime`, `title`, `status`, `priority`, `assignedTo`, `missionId`. Full task object (`"full"`) includes: `description`, `createdBy`, `completionNote`, `dependsOn`, `blockedBy`, `startedAt`, `completedAt`, `updatedAt`, `tags`, and all other schema fields. Status aliases [#status-aliases] | Alias | Expands to | | ---------- | ---------------------------------------------- | | `"open"` | `["todo", "in_progress", "review", "blocked"]` | | `"active"` | `["todo", "in_progress"]` | | `"all"` | No filter — returns all statuses | Why this matters [#why-this-matters] Before PR-E: `list_tasks` had no way to hide automatically-generated tasks (cron-dispatched tasks, `check-messages` entries). Pi's queue accumulated 152 cron-spawned tasks (audit §13), making it difficult to see human-dispatched work without manual filtering. `excludeAutoGenerated=true` hides these rows server-side with zero API surface change — existing callers are unaffected. Audit ref: `analysis/mcp-crud-baseline-vp-audit-2026-06-14.md` section 13. Mission `k571gcctka8mq5jbkgpj0a0b2n892ctg` (VP-MCP top level Bloc A), RED `eb78cfa`, GREEN `74dea44`.