neuron-explorer
Steering-first neuron explorer for Qwen3.5-4B: push every MLP neuron, keep every rollout, browse the results
Open source MCP server. 82 tools, 20 tables. Semantic memory, inter-agent messaging, task management. Free, self-hosted.
Translation pending
Developer toolsTypeScript · PythonGitHub @vantageos-agencyOnlineOwner unconfirmed
Have you tried it? One tap is enough. No sign-in needed.
Owners of public repositories under a personal GitHub account can sign in to verify ownership and manage the introduction themselves. No administrator approval is needed.
Sign in, generate a verification file, and commit it to this repository’s default branch within 30 minutes. Files on other branches or forks do not count. Then check the file below to manage the project without administrator approval. Keep the file to retain your access.
If needed, you will go to sign-in. After signing in, return here and press your chosen verification button again.
Run /nomorevibe verify in your project folder to verify ownership and manage the introduction yourself.
Verify in one minuteAsk about other verification options
Open-source coordination backend for AI agent teams. Shared memory, messaging, tasks via MCP. 20 tables, 75 tools. Convex-native.
Taken from the repository README
Loading the full README. The saved excerpt is shown below.
The coordination layer for AI agent teams. Memory. Messaging. Tasks. Knowledge.
Deploy once. Connect any Claude Code agent. Your team is coordinated.
Quick links: npm — vantage-peers-mcp · Docs site · Pagination doctrine · CHANGELOG
Multi-agent Claude Code crews share one persistent brain via 109 MCP tools: memory + semantic recall, real-time messaging, tasks, missions, and a fix-pattern KB. Backed by Convex (real-time DB + vector search). Deploy on Railway in under 10 minutes, or self-host on free Convex tier.Read the full README ↗The coordination layer for AI agent teams. Memory. Messaging. Tasks. Knowledge.
Deploy once. Connect any Claude Code agent. Your team is coordinated.
Quick links: npm — vantage-peers-mcp · Docs site · Pagination doctrine · CHANGELOG
Multi-agent Claude Code crews share one persistent brain via 109 MCP tools: memory + semantic recall, real-time messaging, tasks, missions, and a fix-pattern KB. Backed by Convex (real-time DB + vector search). Deploy on Railway in under 10 minutes, or self-host on free Convex tier.
VantagePeers runs on Convex — a real-time database with serverless functions, vector search, and built-in cron. CONVEX_URL in your environment points to a specific Convex deployment.
Three deployment paths:
Free self-host (recommended for solo + small teams) — deploy your own Convex project:
git clone https://github.com/vantageos-agency/vantage-peers.git
cd vantage-peers && bun install
npx convex dev # creates a new Convex deployment under your account
The Convex free tier covers solo + small-team coordination usage. Your CONVEX_URL is the deployment URL printed by npx convex dev.
Hosted cloud (consume our fleet deployment) — point CONVEX_URL to our managed Convex prod (compassionate-goldfinch-737.convex.cloud). Subject to fair-use quotas; intended for evaluation. Production use should self-host or upgrade to Pro Support.
Pro Support (dedicated deployment) — dedicated Convex instance with SLA, multi-tenant isolation, and priority support. Contact [email protected] for setup.
For any path, the MCP server is identical (npm install -g vantage-peers-mcp then vantage-peers-mcp to start) — only the CONVEX_URL differs.
Deploy your own VantagePeers MCP server in 1 click. Auto-configures CONVEX_URL + healthcheck + public HTTPS endpoint. Free Convex tier sufficient for solo + small-team deployments. See vantagepeers.com/docs for the full quick-start guide.
flowchart LR
A1[Claude Code agent A] -->|stdio| MCP
A2[Claude Code agent B] -->|stdio| MCP
A3[Cursor / Codex / etc.] -->|stdio| MCP
MCP[vantage-peers-mcp<br/>109 MCP tools] -->|HTTPS| Convex
Convex[(Convex Cloud<br/>real-time DB<br/>vector search)]
Convex -.shared by all agents.-> A1
Convex -.shared by all agents.-> A2
Convex -.shared by all agents.-> A3
One Convex deployment. One MCP server process per agent. All agents share the same database — memories, messages, tasks, missions, fix patterns.
Run multiple Claude Code agents and every session starts blind. No shared context. No coordination. Work duplicated. Mistakes repeated. VantagePeers fixes this:
| Without VantagePeers | With VantagePeers |
|---|---|
| Each agent starts blind | Agents recall shared knowledge via semantic search |
| No communication between agents | Real-time messaging (broadcast, DM, channels) |
| Work gets duplicated | Task tracking with dependencies and assignees |
| Mistakes get repeated | Fix-pattern KB with semantic lookup before debugging |
| No coordination | Mission-based multi-step workflows |
Agent A stores a fact:
{ "namespace": "global", "type": "project", "content": "API uses FastAPI with SQLAlchemy ORM", "createdBy": "alice" }
Agent B recalls it 3 days later:
{ "query": "what framework does the API use", "namespace": "global" }
Returns:
"API uses FastAPI with SQLAlchemy ORM" (score 0.91, type=project, createdBy=alice)
Agent A pings Agent B directly:
{ "from": "alice", "channel": "bob", "content": "Schema is ready. Start on the API endpoints." }
Agent B's next check_messages returns the message; status flips to read after mark_as_read.
Every list_* MCP tool in VantagePeers follows one canonical pagination contract. The driver: Claude Code's tool-response cap is ~60 KB. A list_memories call against a busy namespace easily blows past that with full-row payloads, so every list tool ships with strict defaults (limit default 20, hard cap 200) and an opt-in fields="lite" projection that returns only 4–6 fields per row. Callers paginating large result sets always combine fields="lite" + cursor iteration.
The canonical envelope contract is fleet-wide and non-negotiable:
interface ListEnvelope<T> {
items: T[]; // projected rows (lite or full)
nextCursor?: string; // present IFF there are more pages; absent when done
}
nextCursor is an opaque base64url token — callers must not parse it. The format may evolve (TTL, signature). To iterate, pass the returned nextCursor back as the cursor arg on the next call. When the field is absent, the caller MUST stop. There is no separate isDone flag in the wire format — absence of nextCursor IS the done signal.
Concrete cursor loop (works identically for list_tasks, list_memories, list_episodes, list_messages, every list_*):
async function drainList(tool: string, args: Record<string, unknown>) {
const all: unknown[] = [];
let cursor: string | undefined;
while (true) {
const res = await mcpCall(tool, { ...args, fields: "lite", limit: 100, cursor });
const envelope = JSON.parse(res.content[0].text) as { items: unknown[]; nextCursor?: string };
all.push(...envelope.items);
if (!envelope.nextCursor) break;
cursor = envelope.nextCursor;
}
return all;
}
// usage
const allOpenTasks = await drainList("list_tasks", { assignedTo: "sigma", status: "open" });
Forbidden patterns (each caused a Day-114 production incident): reading .page instead of .value from Convex paginate() returns (silent items: []), returning a flat array instead of {items, nextCursor} envelope, silent MAX_LIMIT clamp without nextCursor (caller stuck at page 1), per-tool divergent MAX_LIMIT constants, and envelope-coverage tests that only check wrapper shape (hasProperty("items") passes on items: []). Every list_* test MUST use the seeded-data assertion pattern (items.length === N) — wrapper-shape-only assertions are banned.
Full doctrine: projects/vantage-peers/mcp-tools-standard-doctrine-v1.md (Sections 1–6: pattern obligatoire, anti-patterns, coverage matrix, fleet cross-reference, compliance gate, migration playbook). Cross-MCP fleet runbook: VR runbook mcp-tools-standard-pagination-doctrine (id kd750j7z7tqre6hxqmfsa8s9ed89erng). Day-114 audit matrix: projects/vantage-peers/mcp-pagination-audit-day114.md — 18 list_* tools audited (15 LOW, 2 HIGH fixed in PR #978, 1 documented EXCEPTION).
0db28d5) — list_memories + list_episodes silent items:[] fix. Root cause: handler read memories?.page instead of the actual Convex paginate return field memories.value ({ value, continueCursor, isDone }). The bug silently returned empty arrays on EVERY call regardless of seeded data — not only on subsequent pages. Present since the original paginationOpts wiring (S3.3 B8, v2.5.0). Fixed via the canonical handler pattern (extract .value, encode continueCursor via encodeCursor, emit {items, nextCursor}). Shipped as [email protected] on npm.d09fc5b) — MCP Tools Standards doctrine v1 landed at projects/vantage-peers/mcp-tools-standard-doctrine-v1.md. Cross-MCP fleet canonical — every VantageOS MCP server (vantage-peers-mcp, vantage-registry-mcp, vCRM, doc-forge, architect, composer, frameworks) inherits the same list_* contract, anti-pattern ban list, and seeded-data test gate. Sister MCPs (Omega VR first) re-brick on this doctrine to eliminate divergence.text-embedding-3-small embeddings (used via AI Gateway or direct OpenAI)# 1. Clone
git clone https://github.com/vantageos-agency/vantage-peers.git
cd vantage-peers
# 2. Install
bun install
# 3. Start the Convex dev server (creates a new deployment on first run)
npx convex dev
# 4. Set environment variables in Convex dashboard (Settings → Environment Variables)
# AI_GATEWAY_API_KEY — OpenAI-compatible key for text-embedding-3-small
# BEARER_SECRET_MASTER — random 32+ char secret (generate: openssl rand -hex 32)
npx convex env set AI_GATEWAY_API_KEY=your-openai-api-key
npx convex env set BEARER_SECRET_MASTER=$(openssl rand -hex 32)
Configure MCP in your Claude Code settings (~/.claude.json):
{
"mcpServers": {
"vantage-peers": {
"command": "npx",
"args": ["-y", "vantage-peers-mcp"],
"env": {
"CONVEX_URL": "https://your-deployment.convex.cloud",
"BEARER_SECRET": "your-bearer-secret-master-value"
}
}
}
}
Replace your-deployment with the URL printed by npx convex dev. Open Claude Code and confirm vantage-peers tools appear in the tool list.
VantagePeers Cloud runs an HTTP MCP server (server-http.ts) via the Streamable HTTP transport. Deploy to Railway in one click:
Once deployed, the public endpoint is https://your-app.up.railway.app/mcp. Add to Claude.ai, ChatGPT, Cursor, or any MCP-capable client as an HTTP MCP server pointing at that URL with your BEARER_SECRET_MASTER as the bearer token.
See vantagepeers.com/docs/cloud/connect for per-client copy-paste config snippets.
Top 5 capabilities, in order of impact:
text-embedding-3-small). Hybrid search (vector + BM25 + RRF fusion) available.checkout_task for multi-instance conflict safety, missions for multi-step workflows (configurable templates: IRP, repo-fix, new-feature).search_fix_patterns BEFORE debugging cuts repeat-mistake rate.Memory & knowledge
user, feedback, project, reference, episode)isLatest)generate_upload_url → store_document_chunked) — mint a signed upload URL, POST the binary, then the document is chunked, embedded, and scheduled for RAG sync per chunk at write time, so uploaded documents are searchable via recall/hybrid_search alongside other memories. To validate an OKF bundle you uploaded: generate_upload_url (URL + single-use ticket) → POST → claim_upload → validate_okf_bundle (see docs/cloud/kb-ingest.md)Coordination
list_broadcast_status)checkout_task)Operations
External integration
Observability
See vantagepeers.com/docs for the full reference.
VantagePeers Cloud (multi-tenant) and Self-host both share the same OAuth 2.1 + scope enforcement core. The following controls form the v2.12.0 security baseline.
client_secret at /token — mcp-server/server-http.ts L382-585. Confidential clients (issued at DCR) must present client_secret on every token exchange. Comparison uses crypto.timingSafeEqual (constant-time) to eliminate length/early-exit oracles. Public clients (no secret at registration) continue PKCE-only. Refusal returns invalid_client per RFC 6749 §5.2. Shipped PR #621, commit 5fd6354.redirect_uri exact-match at /authorize — mcp-server/server-http.ts L298-376. The authorization endpoint rejects any redirect_uri that is not byte-identical to one of the URIs registered for the client_id. No prefix match, no host-only match, no scheme normalization. Hard error before any consent screen. Shipped PR #621, commit 5fd6354.redirect_uris validation at POST /register — mcp-server/server-http.ts L333-405. Rejects absent, empty-array, non-string, unparseable, non-https (except http://localhost / http://127.0.0.1 for dev), and fragment-bearing URIs with invalid_redirect_uri (RFC 7591 §3.2.2). Defense-in-depth: Convex layer enforces the same guard in registerPublicClient. Closes zombie-client class. Commit 2f3e653.patchScopeProfileEmergencyconvex/oauth.ts exposes patchScopeProfileEmergency, a master-token-gated mutation for tenant rename / scope-profile rewrite. Guarantees:
* into any scope of a cloud-* profile.oauth_clients row referencing the old key is cascade-updated.oauth_tokens issued under the old key are revoked atomically with the rename.oauth_audit_log entry (action, actor, before/after snapshot, timestamp). The ledger is append-only; no update or delete path exists.Shipped PR #622, commit 9a1b8cf. Full D9 cascade-update across oauth_clients reached enforcement parity in PR #623, commit 2f5c974.
mcp-server/src/scope-filter.ts is the single chokepoint that translates the caller's OAuth scope set into a row-level filter applied to every multi-tenant list/get path. The framework is wired into:
list_memories, get_memorylist_briefing_noteslist_messageslist_peersWave A (initial surface) shipped PR #624, merged at main 251d183. Wave B (extended surface) is tracked in PR #625.
oauth_audit_log — append-only emergency-action ledgerconvex/schema.ts defines oauth_audit_log as an append-only table. Every emergency mutation (patchScopeProfileEmergency, future master-gated paths) writes a row capturing actor, action, before/after, and timestamp. No mutation path updates or deletes existing rows. This is the auditable record of every out-of-band tenant operation.
withOrgScope fail-closed stepconvex/lib/auth.ts's withOrgScope now fails closed by default when no Clerk identity is present (previously fail-open to master/wildcard access); a per-call-site allowNoIdentityMaster opt-in preserves the old behavior for audited internal call sites. Four client-facing handlers (memories.listMemories, memories.getMemory, messages.listByChannel, diary.list) are now org-scoped, and the MCP legacy bearer path no longer leaves guards unenforced. This closes one fail-open gap — it is a step, not the completion of the multi-tenant model, which remains tracked separately. Full detail, auth-surface table, and open follow-ups: docs/cloud/security-multi-tenant.md §7.
VantagePeers Cloud (multi-tenant SaaS) and VantagePeers Self-host are two distinct products. Runbooks are split: Cloud operations live under docs/cloud/, Self-host operations under docs/getting-started/. Security controls above apply to both products; tenant-specific cascade and audit semantics are documented in docs/cloud/security-multi-tenant.md.
VantagePeers is a standard MCP server — works with any client supporting the Model Context Protocol:
| Tool | Support | Config |
|---|---|---|
| Claude Code | Full MCP | ~/.claude.json |
| Cursor | Full MCP | .cursor/mcp.json |
| Codex (OpenAI) | Full MCP | ~/.codex/config.json |
| Windsurf | Full MCP | ~/.codeium/windsurf/mcp_config.json |
| Cline | Full MCP | VS Code settings |
| Roo Code | Full MCP | VS Code settings |
| OpenCode | Full MCP | opencode.toml |
| Amazon Q Developer | Full MCP | ~/.aws/amazonq/mcp.json |
| Augment Code | Full MCP | VS Code settings |
| Void | Full MCP | Void settings |
| Continue.dev | Agent mode | ~/.continue/config.json |
| GitHub Copilot | Agent mode | .github/copilot-mcp.json |
See Supported Tools for copy-paste config snippets per tool.
| Tool | Description |
|---|---|
store_memory | Store a typed memory entry with optional graph relations |
get_memory | Retrieve a single memory entry by ID |
list_memories | List memories by namespace with optional type filter |
soft_delete_memory | Soft-delete a memory entry by ID |
recall | Semantic vector search over memories, filtered by namespace/type |
text_search | BM25 full-text keyword search over memories |
hybrid_search | Combined vector + BM25 search via RRF fusion |
store_episode | Store a structured episodic memory (context, goal, action, outcome, insight) |
get_episode | Fetch a single episode by memory document ID |
list_episodes | List episodes ordered newest first with optional filters |
search_episodes_by_keyword | BM25 full-text search restricted to episodes |
search_episodes_by_semantic | Semantic vector search restricted to episodes |
| Tool | Description |
|---|---|
get_profile | Fetch an orchestrator's profile (static identity + dynamic session state) |
update_profile | Create or update an orchestrator profile |
list_peers | List all registered agent instances and their current summaries |
set_summary | Set a status summary visible to other agents via list_peers |
whoami | Returns the orchestrator identity baked into the current bearer's scope context |
| Tool | Description |
|---|---|
send_message | Send a message to a channel, agent, or broadcast |
check_messages | Check unread messages for a recipient/instance (supports since for incremental polling) |
mark_as_read | Mark message receipts as read by receipt ID |
delete_message | Delete a message by ID |
get_message | Fetch a single message by Convex document ID |
list_messages | List messages with filters (channel, sender, date range) |
list_broadcast_status | List read/unread receipts for a broadcast message |
search_messages_by_keyword | BM25 full-text search over message content |
| Tool | Description |
|---|---|
create_task | Create a new task with assignee, priority, optional dependencies |
get_task | Fetch a single task by Convex document ID |
get_bulk_complete_run | Status of a live bulk_complete_tasks run by its bulkRunId (running / complete / failed + reason) |
list_tasks | List tasks filtered by assignee, status, project, priority |
list_tasks_by_mission | List all tasks belonging to a specific mission |
search_tasks_by_keyword | BM25 full-text search over task titles |
update_task | Update any task fields — incl. cancel (status="cancelled" + cancelReason, creator-only) |
complete_task | Mark a task as done with a mandatory completion note |
start_task | Claim a task and set status to in_progress |
checkout_task | Atomically claim a task (conflict-safe for multi-instance) |
delete_task | Delete a task by ID (blocked in prod — cancel an erroneous task via status="cancelled" instead) |
list_blocked_on_me | List the tasks other peers have blocked (blockedOnTaskId) on your live tasks, oldest wait first, with ages. Opt-in read; check_messages never carries it |
block_task | Mark a task as blocked with optional reason and a blockedCause (peer_task | human | authorisation | other) naming WHAT is being waited on |
fail_task | Mark a task as failed — a terminal state distinct from done/cancelled — with a mandatory failureNote. The only way to record a failure; update_task refuses status="failed" |
add_task_dependency | Add dependency tasks that must complete first |
Blocked-task waiting-on state: blockedCause (optional on block_task, defaults server-side to "other") distinguishes a task blocked waiting on a human answer from one blocked waiting on an authorisation (a merge/publish/approval gate) — the two were previously indistinguishable, collapsed into free text on blockedOnNobodyReason. It is a structured discriminator of the cause, not a caller-written state: the waiting-on label a consumer reads is DERIVED from {status, blockedCause} via deriveBlockedWaitingOn (convex/tasks.ts), never written directly. Pre-existing blocked rows are unaffected (read back as "other"); no migration ran.
Task & mission statuses: todo → in_progress → review → done (terminal) or failed (terminal), plus blocked (waiting on a dependency) and cancelled (terminal). failed is a third terminal, distinct from done (succeeded) and cancelled (retired before/without attempting the work): a task whose work was genuinely attempted and did not succeed. It is recorded ONLY via fail_task (mandatory failureNote) — update_task refuses status="failed" server-side, the same way it refuses status="blocked". The underlying completionOutcome ("succeeded" | "failed") is never a caller-supplied arg on complete_task or fail_task: each tool hardcodes its own value, and status is DERIVED from it via deriveTerminalStatus (convex/tasks.ts) — there is no field for a closer to pick between "finished" and "failed", only a distinct named tool to call. A task already done/cancelled/failed cannot be re-terminated as failed. A waiter blocked on a task that fails is NOT auto-unblocked: fail_task notifies the waiter's owner that the blocker FAILED (never the success-path "is now done" wording) but leaves the waiter blocked, with blockedOnTaskId intact — no autonomous pick may treat a failed prerequisite as though it held. Only a blocker reaching done sweeps its waiters to todo. A task or mission created in error is retired with cancelled — settable only by its creator, with a mandatory cancelReason. A cancelled row is excluded from the open/active list filters and is never counted as done; an already-done task (or complete mission) cannot be cancelled. Prefer cancelling over deleting — delete_task is blocked in production. Pre-existing done/cancelled rows are left as recorded — no migration reclassifies them, since no signal exists to tell a true failure apart from a real success/cancellation after the fact (see CHANGELOG for the full reasoning).
| Tool | Description |
|---|---|
create_mission | Create a mission grouping related tasks under a project |
get_mission | Fetch a single mission by ID |
list_missions | List missions filtered by project, pilot, status |
update_mission | Update mission fields — incl. cancel (status="cancelled" + cancelReason, creator-only) |
update_mission_status | Advance a mission through its lifecycle stages |
get_mission_template | Fetch a configurable mission template by name |
update_mission_template | Create or upsert a mission template |
instantiate_template_into_mission | Create one task per template step inside a mission |
| Tool | Description |
|---|---|
write_diary | Write a daily diary entry for an agent instance |
get_diary | Retrieve a diary entry by orchestrator and date |
list_diaries | List diary entries with date range and orchestrator filters |
create_briefing_note | Create a briefing note with topic, participants, decisions |
update_briefing_note | Partial-update an existing briefing note (RBAC: createdBy or system) |
get_briefing_note | Fetch a single briefing note by ID |
list_briefing_notes | List briefing notes filtered by topic or creator |
search_briefing_notes_by_keyword | BM25 full-text search over briefing note content |
Recurring tasks (7): create_recurring_task, list_recurring_tasks, get_recurring_task, pause_recurring_task, resume_recurring_task, delete_recurring_task, update_recurring_task
Mandates (7): create_mandate, accept_mandate, update_mandate, settle_mandate, validate_mandate_spending, list_mandates, get_mandate
Business units (5): create_bu, update_bu, get_bu, list_bus, delete_bu
Issues (7): list_issues, get_issue, update_issue_status, link_commit_to_issue, verify_issue, issue_stats, link_issue_to_pattern
Repo mappings (4): add_repo_mapping, list_repo_mappings, remove_repo_mapping, get_repo_mapping
Fix patterns (7): create_fix_pattern, get_fix_pattern, list_fix_patterns, add_fix_attempt, validate_fix, search_fix_patterns, link_issue_to_pattern
Error monitoring (2): list_errors, get_error
Deployments (2): add_deployment, remove_deployment
| Tool | Description |
|---|---|
validate_task_payload | Dry-run lint for VP write-path tools — checks validation axes and returns failures with fix snippets |
list_bus — envelope safety (PR-A)list_bus received strict defaults and an actual fields=lite projection in PR-A (branch feat/vpmcp-a-list-bus-envelope, commit a7ac41c), extending the S3.3 B8 follow-up batch 1 cursor rollout (which gave list_bus opaque cursor support) with hardened defaults and real projection logic:
20 (was 50). Cap: 200 (was unbounded).fields='lite': projects to {_id, _creationTime, name, status, orchestratorId} — was a no-op since v2.4.12 (accepted the arg without applying projection). PR-A activates the actual server-side projection.{ items, nextCursor } (was flat array). nextCursor is null on the last page, opaque string otherwise.{creationTime, id} to survive same-millisecond inserts.Full reference: list_bus — MCP Tools Reference.
Same envelope safety pattern will apply to list_components (PR-B) and list_repo_mappings (PR-C).
list_components — envelope safety (PR-B)list_components received strict defaults and an actual fields=lite projection in PR-B (branch feat/vpmcp-b-list-components-envelope, commit 39f8d08), reusing the shared mcp-server/src/paging.ts helper introduced in PR-A:
20 (was 100). Cap: 200 (was unbounded).fields='lite': projects to {_id, _creationTime, name, type, team} — was a no-op (returned full row). PR-B activates the actual server-side projection.{ items, nextCursor } (was flat array). nextCursor is null on the last page, opaque string otherwise.{creationTime, id} to survive same-millisecond inserts. Hybrid decode preserves S3.3 B8 {createdBefore} cursors.Full reference: list_components — MCP Tools Reference.
list_repo_mappings — envelope safety (PR-C)list_repo_mappings received strict defaults and an actual fields=lite projection in PR-C (branch feat/vpmcp-c-list-repo-mappings-envelope, commit 4ddca2b), reusing the shared mcp-server/src/paging.ts helper introduced in PR-A:
20 (was 50). Cap: 200 (was unbounded).fields='lite': projects to {_id, _creationTime, repo, orchestrator, project} — excludes active, lastDeployedSHA, lastDeployedAt. PR-C activates the actual server-side projection.{ items, nextCursor } (was flat array). nextCursor is null on the last page, opaque string otherwise.{time, id} to survive same-millisecond inserts. Hybrid decode preserves S3.3 B8 {createdBefore} cursors.Full reference: list_repo_mappings — MCP Tools Reference.
list_tasks — excludeAutoGenerated filter (PR-E)list_tasks gained a new optional excludeAutoGenerated: boolean arg in PR-E (branch feat/vpmcp-e-list-tasks-exclude-cron, commit 74dea44):
true: filters tasks where createdBy matches /^cron-/i (dash mandatory — cron-bot filtered, cronus not) OR title matches /^\/?check-messages$/i (whole-string, case-insensitive, optional leading slash).false: returns all tasks unchanged — fully backward-compatible.limit (filtered rows do not count toward limit). Acceptable — cron catalog is small.Example — Pi queue cleaned of cron-spam (152 cron tasks, audit §13):
list_tasks assignedTo="pi" status="open" excludeAutoGenerated=true limit=50
Full reference: list_tasks — MCP Tools Reference.
bulk_complete_tasks (PR-F)bulk_complete_tasks bulk-closes tasks that match a filter in one atomic mutation. Introduced in PR-F (commit 8eaa893) to safely drain cron-spam backlogs.
Safety: dryRun defaults to true. Always preview first, then call again with dryRun=false to commit. Closed tasks are irreversible — status permanently set to done.
// Step 1 — preview (dryRun=true is default)
bulk_complete_tasks filter={autoGeneratedOnly:true} callerOrchestrator="system"
// → { count: 152, sampleIds: ["k17...", ...], bulkRunId: "bulk-1782050000000-a3f2" }
// Step 2 — commit (explicit dryRun=false)
bulk_complete_tasks filter={autoGeneratedOnly:true} dryRun=false callerOrchestrator="system"
// → { count: 152, sampleIds: ["k17...", ...], bulkRunId: "bulk-1782050000000-a3f2", executedAt: 1782050000000 }
Draining more than 500 (R-31): a live call closes the first 500 and returns remaining: true with the same bulkRunId; the rest drains by itself in the background (a scheduled continuation re-applies the same filter, tenant scope, creator/assignee check and closure gate, 500 per batch, same completion note). Poll get_bulk_complete_run bulkRunId=<id> for {status: running | complete | failed, closed, remaining, failureReason?}. A failed run means a later batch was refused (RBAC or the closure gate): failureReason says why, closed is what was closed before it, the rest stay open, and re-calling bulk_complete_tasks with the same filter meets the same refusal. The status row is readable by the run's own organisation and its creator only; any other caller gets "not found".
Tenant boundary across same-named agents: orchestrator names are not unique across organisations, and through MCP the Convex scope is the fleet service account, so the name check alone cannot separate an org-a eta from an org-b eta. bulk_complete_tasks and the single-task tools (complete_task, update_task, start_task, pause_task, resume_task, block_task, fail_task, delete_task, checkout_task, correct_task_segment) therefore forward the bearer's verified organisation to Convex (verifiedOrg, from the verified token context only, never a tool argument), and Convex refuses (RBAC_DENIED, nothing written) any task whose org differs. The fleet master keeps its cross-tenant reach.
Caveats:
list_tasks excludeAutoGenerated.callerOrchestrator is provided and is not "system", every matched task must have createdBy === callerOrchestrator OR assignedTo === callerOrchestrator. Any mismatch throws RBAC_DENIED.completionNote containing {{day}} (project day number from epoch 2026-03-06) and {{bulkRunId}} (unique run ID). The default template is "bulk-cleanup: cron-spam day {{day}} runId={{bulkRunId}} executedAt={{executedAt}}". Override with completionNoteTemplate.Cron contract (same as list_tasks excludeAutoGenerated):
createdBy matches /^cron-/i (dash mandatory): cron-bot filtered, cronus not filtered.title matches /^\/?check-messages$/i (whole-string, optional leading slash, case-insensitive).Full reference: bulk_complete_tasks — MCP Tools Reference.
All 4 list queries (list_tasks, list_tasks_by_mission, list_missions, list_briefing_notes) support these params (v2.3.x):
| Param | Type | Notes |
|---|---|---|
fields | "lite" | "full" | "lite" returns compact projection (5-10x smaller payload). v2.3.1+. |
status | string | string[] | alias | Single status, array, or alias ("open", "active", "all"). Aliases NOT permitted inside arrays. v2.3.2+. |
createdBy | creator | Filter by row creator (e.g. "pi"). list_tasks + list_tasks_by_mission only. v2.3.3+. |
updatedSince | number (ms) | Filter to rows with updatedAt >= this. Typical: Date.now() - 24*60*60*1000. v2.3.3+. |
limit | number | Default 50 (briefingNotes 20). Auto-clamps to 30 (15 for briefingNotes) when fields="full" AND no explicit limit. v2.3.3+. |
Pi pull-cycle quickstart:
list_tasks createdBy="pi" status="review" fields="lite" limit=30
Returns recently-completed Pi-dispatched tasks with compact projection — typically 5-10x smaller payload than the default.
Tool descriptions can embed advisory doctrine substrings so that client LLMs read the citation contract inline at tool-list time — before any tool call is made. No hook enforces absence: the doctrine is advisory-only, intentionally so that client implementations can adopt it gradually.
Each covered tool appends two additional paragraphs (separated by a blank line) after its existing 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("<q>")→[ids] | none-needed:<reason>'.
| Tool | Exported constant |
|---|---|
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 |
All five constants are exported from mcp-server/src/tools.ts and consumed by the MCP server's tool registration block. Snapshot tests in mcp-server/src/__tests__/tools-descriptions.test.ts assert that both doctrine substrings are present in each constant.
MCP clients receive the full tool list (names + descriptions) in a single response before the first tool call. Embedding the doctrine string there means any agent that calls one of these 5 tools has already been instructed about the citation obligation — no separate system-prompt injection is required.
When a search tool returns results the agent must cite them in the final answer footer:
VP-Sources: recall("Pi feedback rules")→[j57dy3049btafda9m2f5d2ggk987ph3f, j572s2bh4e0n20n0ttxynwrnts891nb5] | none-needed:trivial code edit
recall("<q>") — the query string used, with the tool name.→[ids] — comma-separated Convex document IDs returned by the search.none-needed:<reason> — use when a search was not required (see below).none-needed is acceptableget_task, whoami).VP-Sources answer-footer doctrine — full reference including worked examples and advisory-only rationale.
k977bvf03qzas7v7g0zqca9c7n8937zhk571gcctka8mq5jbkgpj0a0b2n892ctg (VP-MCP top level Bloc A)0b4dc84, T-GREEN 908fd67improvisation_digest scans 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 made a fleet-state claim without a prior recall upstream."
V1 scope — Option C: scans VP records only (tasks + messages + memories). Per Pi Day-113 arbitration (msg k97a0pp6kq1axkj6cmc4pecpy989ce1w), fallback if V1 misses too many = Option B (new dedicated sessions Convex table), not Option A (JSONL replay).
ADVISORY-only — pure read query. The tool never blocks any action.
| Arg | Type | Default | Description |
|---|---|---|---|
windowDays | number | 7 | Number of days to look back. |
orchestrators | string[] | — | Scope to these orchestrator roles (e.g. ["sigma","pi"]). Omit for all. |
{
countsByOrch: Record<string, number>, // hit count per orchestrator
countsByCategory: Record<string, number>, // hit count per record type (task/message/memory)
samples: Array<{ // up to 50 example snippets
id: string,
category: string,
orchestrator: string,
snippet: string
}>
}
Default 7-day window, all orchestrators:
{ "tool": "improvisation_digest", "arguments": { "windowDays": 7 } }
Scoped to a single orchestrator:
{ "tool": "improvisation_digest", "arguments": { "windowDays": 14, "orchestrators": ["sigma"] } }
A record is flagged when both conditions hold:
#NNN PR/issue reference, a Convex document ID (k1… or j… prefix), or a decisive verb (merged, deployed, approved, shipped, released, fixed).VP-Sources: footer substring.Eta A5 scope filter: only records authored by agents matching the orchestrator allowlist (excludes system, cron-*, and webhook-sourced entries).
k571gcctka8mq5jbkgpj0a0b2n892ctg (VP-MCP top level Bloc A)cd6cda3, T-GREEN commit b9414dc| Table | Purpose | Key Fields |
|---|---|---|
memories | Core memory store with typed entries and graph relations | namespace, type, content, createdBy, relations, isLatest |
profiles | Agent identity and session state | orchestratorId, instanceId, static, dynamic |
messages | Inter-agent messages | from, channel, content, sessionDay |
messageReceipts | Per-recipient read tracking | messageId, recipient, recipientInstanceId, readAt |
missions | High-level mission grouping for tasks | name, project, status, priority, pilot |
tasks | Individual work items with dependencies | title, assignedTo, status, priority, dependsOn, missionId |
diary | Daily diary entries per agent | date, orchestrator, content, highlights, blockers |
briefingNotes | Shared briefing documents | title, topic, participants, content, decisions |
components | Agent/skill/hook/plugin registry with content backup | name, type, team, content, version |
recurringTasks | Cron-based task templates | title, assignedTo, cronExpression, active, nextRunAt |
missionTemplates | Configurable multi-step workflow templates | name, steps, isDefault, createdBy |
mandates | Cross-agent service requests with budgets | requestedBy, fulfilledBy, service, budget, spendingLimits |
businessUnits | Business units | name, status, businessModel, pricing, kpis, managementFee |
issues | GitHub issues synced via webhook | repo, issueNumber, status, priority, fixCommits |
githubRepoMapping | Maps GitHub repos to orchestrators | repo, orchestrator, project, active |
fixPatterns | Bug-fix knowledge base with semantic search | symptom, rootCause, validatedFix, tags, stack, severity |
Orchestrator names are open strings — any value is accepted. The following are conventions used by the VantageOS team:
| Role | Purpose |
|---|---|
pi | Lead orchestrator — planning, delegation, strategy |
tau | Frontend specialist |
phi | Backend specialist |
sigma | Infrastructure — deployments, CI/CD, monitoring |
omega | VantageRegistry — agent and skill catalog |
eta | Code reviewer — GitHub PR reviews |
alpha | Client delivery |
lambda | Tech intelligence |
victor | HR / people operations |
system | Reserved for webhooks. Bypasses RBAC on delete operations. |
Since issue #132, validators accept any string. The names above are conventions, not enforced constraints.
Memory types: user (facts about the user), feedback (behavioral corrections), project (architectural decisions), reference (external pointers), episode (structured lessons with severity).
Three search strategies via @convex-dev/rag:
text-embedding-3-small). Used by recall and search_fix_patterns.text_search.hybrid_search.Embedding is asynchronous — expect a 2-5s delay between store_memory and the entry becoming searchable.
A role (e.g., pi, sigma) is a logical identity. An instance (e.g., pi-chromebook, sigma-vps) is a specific running copy. Multiple instances of the same role can run concurrently. Messages route to a role (all instances receive) or to a specific instance. Each instance sets its own set_summary and claims tasks independently via the atomic checkout_task tool.
# MCP smoke tests — the served tools against a live Convex deployment
bun scripts/test-mcp.ts
# Convex function unit tests
npx vitest run
# RAG integration tests — store → embed → recall pipeline
bun scripts/test-rag-integration.ts
Reports written to tests/mcp-smoke-report.md, tests/unit-report.md.
Drop this into any agent's CLAUDE.md to enable the memory protocol:
## SHARED MEMORY (non-negotiable)
You have access to VantagePeers via MCP tools.
1. On session start: `recall` your namespace for relevant context.
2. After every failure: `store_episode` with context/goal/action/outcome/insight.
3. Before repeating a mistake: `recall` similar past episodes.
4. Before fixing a bug: `search_fix_patterns` to check if it's been seen before.
5. Store non-obvious learnings via `store_memory`.
6. Use `orchestrator/[name]` for personal namespace, `global` for shared.
server/discover) and the 2025 era (initialize) from one entrytext-embedding-3-small — 1536-dim embeddings via AI Gateway or direct OpenAIFull documentation at vantagepeers.com/docs:
Contributions welcome. Please open an issue first to discuss what you would like to change.
Each pull request records its changelog entry as one new file changelog.d/<pr-or-branch-slug>.md and never edits CHANGELOG.md directly, so open pull requests do not conflict with each other. Validate with node scripts/changelog-assemble.mjs --check. See docs/changelog-fragments.md.
Built by the VantageOS AI Orchestrator Team — sigma, omega, kappa, tau, beta, theta, gamma, mu, athena, hermes, demeter, eta, chi, iota, psi, rho, phi, alpha, lambda, victor, ulysse, atlas, argus — under the supervision of Pi (π) and Laurent Perello.
FSL-1.1-Apache-2.0 — source-available, free to self-host, converts to Apache 2.0 after 2 years. You may not offer VantagePeers as a competing hosted service.
fixAttempts | Individual fix attempts per pattern | patternId, description, worked, why, commit |
monitoredDeployments | Convex deployments polled for errors | name, deploymentUrl, deployKeyEnvVar, githubRepo, active |
errorLogs | Deduplicated error log with auto-issue linking | hash, functionName, errorMessage, count, issueNumber |
issueStats | Daily issue-resolution metrics per repo | repo, date, medianTimeToFix, beforeVantageOS, afterVantageOS |