From 25fcf46da5513b4058b7c10d03177772bc4e4c3a Mon Sep 17 00:00:00 2001 From: Meta Vens Date: Tue, 19 May 2026 17:49:07 +0100 Subject: [PATCH] Fix Bifrost intake MCP mounting --- docs/agent-transport.md | 3 + .../bifrost-intake/.codex-plugin/plugin.json | 2 +- plugins/bifrost-intake/.mcp.json | 5 +- plugins/bifrost-intake/scripts/mcp-server.mjs | 59 ++++++++++++++++++- .../skills/bifrost-intake/SKILL.md | 8 +-- 5 files changed, 70 insertions(+), 7 deletions(-) diff --git a/docs/agent-transport.md b/docs/agent-transport.md index 565822c..8fcd120 100644 --- a/docs/agent-transport.md +++ b/docs/agent-transport.md @@ -64,6 +64,7 @@ The `snapshot` command writes a MessagePack-encoded `cultnet.snapshot_response_r Tools: +- `get_intake_context` - `enqueue_update_request` - `list_update_requests` - `claim_update_request` @@ -74,6 +75,8 @@ Tools: The plugin is listed in `.agents/plugins/marketplace.json` as `bifrost-intake`. +`get_intake_context` is the normal Codex-facing entry point. It claims the next matching request for the current repo and returns a context packet immediately. If nothing is queued, it returns a direct no-work message so the agent can stop worrying about intake and continue the live turn. + ## Next Integration Points - Teach the VoidBot consensus feeder to enqueue Bifrost update requests after it writes a packet. diff --git a/plugins/bifrost-intake/.codex-plugin/plugin.json b/plugins/bifrost-intake/.codex-plugin/plugin.json index 4c5c52e..e598f55 100644 --- a/plugins/bifrost-intake/.codex-plugin/plugin.json +++ b/plugins/bifrost-intake/.codex-plugin/plugin.json @@ -33,7 +33,7 @@ "privacyPolicyURL": "https://github.com/GameCult/Bifrost", "termsOfServiceURL": "https://github.com/GameCult/Bifrost", "defaultPrompt": [ - "Claim the next Bifrost update request for this repo.", + "Get Bifrost intake context for this repo.", "Enqueue this consensus packet for a repo Face.", "List queued Bifrost agent requests." ], diff --git a/plugins/bifrost-intake/.mcp.json b/plugins/bifrost-intake/.mcp.json index 53669b4..3effc29 100644 --- a/plugins/bifrost-intake/.mcp.json +++ b/plugins/bifrost-intake/.mcp.json @@ -2,7 +2,10 @@ "mcpServers": { "bifrost-intake": { "command": "node", - "args": ["./scripts/mcp-server.mjs"], + "args": ["E:/Projects/Bifrost/plugins/bifrost-intake/scripts/mcp-server.mjs"], + "env": { + "BIFROST_ROOT": "E:/Projects/Bifrost" + }, "note": "Local Bifrost intake MCP server. Wraps Bifrost's CultCache/CultNet agent transport CLI." } } diff --git a/plugins/bifrost-intake/scripts/mcp-server.mjs b/plugins/bifrost-intake/scripts/mcp-server.mjs index 473db7c..011c136 100644 --- a/plugins/bifrost-intake/scripts/mcp-server.mjs +++ b/plugins/bifrost-intake/scripts/mcp-server.mjs @@ -1,14 +1,30 @@ #!/usr/bin/env node import { spawn } from "node:child_process"; +import { existsSync } from "node:fs"; import { dirname, resolve } from "node:path"; import { fileURLToPath } from "node:url"; const pluginRoot = resolve(dirname(fileURLToPath(import.meta.url)), ".."); -const bifrostRoot = resolve(pluginRoot, "..", ".."); +const bifrostRoot = resolveBifrostRoot(); const transportCli = resolve(bifrostRoot, "tools", "agent-transport.mjs"); const serverInfo = { name: "bifrost-intake", version: "0.1.0" }; const tools = [ + { + name: "get_intake_context", + description: "Claim the next matching Bifrost request and return a Codex-ready context packet, or say there is no queued intake work.", + inputSchema: { + type: "object", + additionalProperties: false, + required: ["repo"], + properties: { + repo: { type: "string", description: "Current repository short name, such as AetheriaLore." }, + agent: { type: "string", description: "Optional current Face identity, such as nibu." }, + claimedBy: { type: "string" }, + store: { type: "string" } + } + } + }, { name: "enqueue_update_request", description: "Enqueue a Bifrost agent update request in the CultCache-backed intake store.", @@ -190,6 +206,8 @@ async function callTool(params) { const args = params.arguments ?? {}; switch (name) { + case "get_intake_context": + return textToolResult(await getIntakeContext(args)); case "enqueue_update_request": return jsonToolResult(await runTransport([ "enqueue", @@ -251,6 +269,26 @@ async function callTool(params) { } } +async function getIntakeContext(args) { + const repo = requireString(args.repo, "repo"); + const claimed = await runTransport([ + "claim", + "--repo", repo, + ...optionalArg("--agent", args.agent), + ...optionalArg("--claimed-by", args.claimedBy ?? args.agent), + ...storeArg(args.store), + ]); + + if (!claimed) { + const face = typeof args.agent === "string" && args.agent.trim().length > 0 + ? ` for ${args.agent.trim()}` + : ""; + return `No Bifrost intake requests are queued for ${repo}${face}. Do not stall on intake for this turn; continue with the user's direct request or the repo's normal next action.`; + } + + return formatClaimedRequest(claimed); +} + async function requireRequestById(args) { const id = requireString(args.id, "id"); const requests = await runTransport(["list", ...storeArg(args.store)]); @@ -364,3 +402,22 @@ function sendMessage(message) { process.stdout.write(`Content-Length: ${body.length}\r\n\r\n`); process.stdout.write(body); } + +function resolveBifrostRoot() { + const candidates = [ + process.env.BIFROST_ROOT, + resolve(pluginRoot, "..", ".."), + "E:/Projects/Bifrost", + ].filter((candidate) => typeof candidate === "string" && candidate.trim().length > 0); + + for (const candidate of candidates) { + const root = resolve(candidate); + if (existsSync(resolve(root, "tools", "agent-transport.mjs"))) { + return root; + } + } + + throw new Error( + "Could not find Bifrost root. Set BIFROST_ROOT to the repository that contains tools/agent-transport.mjs.", + ); +} diff --git a/plugins/bifrost-intake/skills/bifrost-intake/SKILL.md b/plugins/bifrost-intake/skills/bifrost-intake/SKILL.md index 55724c8..4106a0f 100644 --- a/plugins/bifrost-intake/skills/bifrost-intake/SKILL.md +++ b/plugins/bifrost-intake/skills/bifrost-intake/SKILL.md @@ -11,9 +11,9 @@ Use these tools when a user asks to feed a consensus packet to a repo Face, clai Default flow: -1. Use `list_update_requests` to inspect queued work for a repo or Face. -2. Use `claim_update_request` with the repo name before injecting the request into Codex. -3. Use `format_claimed_request` when you need a compact prompt packet for a claimed request. -4. Use `close_update_request` when the work is completed or cancelled. +1. Use `get_intake_context` at the start of a repo-agent turn when the agent should check Bifrost intake. +2. If it returns a request packet, treat that packet as live context for the turn. +3. If it says no request is queued, do not ask the user what to do because of intake; continue with the user's direct request or the repo's normal next action. +4. Use `close_update_request` when the claimed work is completed or cancelled. Do not store a parallel queue in VoidBot or Codex session memory. If the request is intended to persist, put it in Bifrost intake.