fix(skills): correct tool-surface drift in build/integrations/agenda skills - #10
fix(skills): correct tool-surface drift in build/integrations/agenda skills#10alonmuroch wants to merge 2 commits into
Conversation
…skills The layer-3 skills named tools that do not exist on stage and omitted large parts of the shipped tool surface. - brains-build: drop `get_overnight_digest` (the overnight-thinker service and its tool are gone); the daily brief is now the `starter-pack-my-day` recipe writing a "Daily digests" board. Correct `create_automation` -> `save_automation_draft`/`update_automation`. Add board forms, `run_board_skill`, and a compact "tools around a board" table covering sharing + share circles, dataset ACLs, board files/links, dashboard/mini-site/schema history + revert, and automation secrets. - brains-integrations: `list_recipes` (+ `recommend_recipes`) does enumerate the catalog over MCP — the "no MCP tool" claim was false. `list_installed_versions` reports version drift (the upgrade itself is still web-only). The recipe uninstall cascade (`preview_uninstall_recipe` / `uninstall_recipe`) is callable over MCP. Add install tuning (`set_integration_config`, `set_integration_overrides`, `run_integration_once`, `bulk_set_integration_state`) and a new plugin-only authoring section. - brains-agenda: same dead `get_overnight_digest` defect; read the daily brief from the "Daily digests" board instead.
| if the user wants to *publish* something, this is the only place it can happen. | ||
|
|
||
| - **Start with the playbook, not a blank template.** To author an integration | ||
| recipe, call **`create_integration_flow`** first — it returns the full |
There was a problem hiding this comment.
🟡 create_integration_flow is not on the current MCP surface — it ships in the unlanded ssvlabs/brains#871. This skill's whole purpose is removing tool names that don't exist, and the authoring section reintroduces exactly that: an agent reading this file will call a phantom tool and dead-end, with no merge-order guard here (the caveat lives only in the PR description, which the agent never sees). Gate the authoring section behind #871, or add an inline note that the tool is unavailable until then.
There was a problem hiding this comment.
Checked this against the tree rather than the PR description — the dependency is already satisfied, so no gate or caveat is needed.
origin/stage: apps/mcp/src/tools/integration-flow.ts:352 name: "create_integration_flow"
origin/main: apps/mcp/src/tools/integration-flow.ts (present)
registered: apps/mcp/src/tools/index.ts:13416 for (const t of integrationFlowTools())
ssvlabs/brains#871 merged 2026-07-20T15:06Z, and it has since been promoted past stage — the tool is on main too, so it's live for users on prod, not just staging. That last part is the bit worth having on the record: the plugin ships to whatever a user's deployment is running, so 'exists on stage' wouldn't actually have been sufficient. It exists on both.
Adding an inline "unavailable until #871" note now would be actively wrong, so I've left the authoring section as-is.
While I was in here I re-verified the rest of the branch the same way — extracted every backticked identifier from the three changed SKILL.md files and diffed it against the real tool surface built from apps/mcp/src/tools/** on origin/stage. Everything resolves. The only two that didn't match a literal name: "…" are install_recipe and list_recipes, which are the canonical names produced by the rename layer (tool-aliases.ts:29-30: apply_starter_recipe → install_recipe, list_starter_recipes → list_recipes), so those are correct too.
That sweep did turn up one real gap, now fixed in a3ac903: the agenda skill pointed at the "Daily digests" board but left the dataset as <name> and said "take the newest row". That board carries five datasets (daily, weather, important_emails, telegram_log, unanswered_emails) written by four different starter-pack automations — only daily holds the My Day brief, so an unguided pick could have surfaced a weather strip under "Last night's read on things". Same class of bug as the drift this branch fixes, just in a non-tool identifier.
nir-ssvlabs
left a comment
There was a problem hiding this comment.
All tool names verified against apps/mcp/src/tools/ on stage — including the pluginOnly tools (run_integration_once, bulk_set_integration_state, publisher vault) that don't surface through the claude.ai MCP client. The create_integration_flow dependency noted in the PR description is already satisfied (#871 merged). Clean, accurate drift fix.
The agenda skill pointed at the "Daily digests" board but left the dataset as `<name>`, and told the agent to take "the newest row". That board carries five datasets — `daily`, `weather`, `important_emails`, `telegram_log` and `unanswered_emails` — written by four different starter-pack automations. Only `daily` holds the My Day brief, so an unguided pick could surface a weather strip or a Telegram log under "Last night's read on things". Names the dataset and says why it matters. Same class as the drift this branch fixes: an identifier the agent had to guess. Verified against scripts/seed-starter-recipes/bundles.ts on ssvlabs/brains stage — board name "Daily digests" (bundles.ts:189), My Day's dataset "daily" (bundles.ts:96). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| 2. `get_overnight_digest` (no args = latest personal digest) — optional context. | ||
| 2. The latest daily brief — optional context. There is no digest tool; the brief | ||
| is a board row written by the My Day recipe. `list_boards` → find the board | ||
| named **"Daily digests"** → `get_board board_id=<id> dataset="daily"` and take |
There was a problem hiding this comment.
🟡 get_board gives no ordering guarantee and takes no sort argument; it defaults to offset: 0, limit: 100. "take the newest row" therefore reads a stale row once the daily dataset passes 100 rows, which it will — the My Day recipe appends one per day. Page to the end via offset using the returned page.total, or pass filter on the dataset's date field for the window.
| catalog with pictures. | ||
| - **Web UI — starter pack:** for "set me up" / "install the basics", send the | ||
| user to `/recipes/starter-pack` — one click bootstraps the three Google | ||
| integrations (gmail-inbox, gcalendar, gdrive-files) atomically. Bundle |
There was a problem hiding this comment.
🟡 "Bundle cascades only run through the web UI" is stale in the same way as the drift this branch fixes: install_recipe accepts kind: 'bundle' recipes and auto-installs missing dependencies children-first, so install_recipe slug="starter-pack" brain_id=<uuid> bootstraps the pack in one MCP call. Name that for "set me up" instead of bouncing the user to /recipes/starter-pack.
| | **Board form** | Chat-with-agent intake page that appends a row to a board dataset on submit | "collect responses", "give people a form/signup link" | `create_board_form` (then `list_board_forms` / `update_board_form` / `list_board_form_responses` / `delete_board_form`) | | ||
| | **Telegram bot** | The brain over Telegram | "text it from my phone", "ping me without the laptop" | (point to the bot) | | ||
| | **Overnight digest** | Auto daily/weekly read on what's coming up | "morning brief", "what should I be thinking about" | `get_overnight_digest` | | ||
| | **Daily digest** | Not a tool — a recipe-installed automation that writes a "Daily digests" board + dashboard | "morning brief", "what should I be thinking about" | `install_recipe slug="starter-pack-my-day"` (browse with `list_recipes`) | |
There was a problem hiding this comment.
🟡 install_recipe requires brain_id alongside slug; the call shown here omits it, so an agent whose user has more than one brain either errors out or picks one at random. Show install_recipe slug="starter-pack-my-day" brain_id=<uuid> and resolve the target with list_brains first.
| | **Automation** | Sandboxed TS program on a cron schedule with a scoped token | "every morning do X", "auto-draft Y when Z", anything re-prompted on a timer | `create_automation_flow` | | ||
| | **Workflow** | Goal container: charter + KPIs + deadlines + roster + owned board + paused template automations; one status flip pauses/un-pauses all | "ship X by Q3", "coordinate this initiative with a team & deadline" | `create_workflow_flow` | | ||
| | **Mini-site** | Static sandboxed HTML on a brain — deck, one-pager, dashboard | "build me a deck/one-pager", "render this board visually", "share a link" | `create_mini_site` | | ||
| | **Board form** | Chat-with-agent intake page that appends a row to a board dataset on submit | "collect responses", "give people a form/signup link" | `create_board_form` (then `list_board_forms` / `update_board_form` / `list_board_form_responses` / `delete_board_form`) | |
There was a problem hiding this comment.
🟡 create_board_form defaults to status: 'draft', which is owner-only preview and accepts no submissions — so following this row for "give people a form/signup link" hands out a form_url nobody can submit to. State that the form must be created or updated with status: 'open' before the link goes out.
What & why
The layer-3 skills named tools that don't exist and omitted large parts of the shipped MCP surface. Every tool name in this diff was verified to exist in
ssvlabs/brains@stage, with canonical names resolved throughapps/mcp/src/tools/tool-aliases.ts.brains-build
get_overnight_digestwas a phantom — and not just a stale name: the whole feature is gone fromstage(noapps/overnight-thinker, no migration, no tool). An agent reading this skill would call a tool that has never existed on the current surface. Replaced with the real mechanism: thestarter-pack-my-dayrecipe, which writes a "Daily digests" board.create_automationdoesn't exist →save_automation_draft(+ a note thatupdate_automationedits in place without a flow).run_board_skill, sharing + share circles, dataset ACLs, board files/links, history/revert, automation secrets.brains-integrations
list_recipes(canonical forlist_starter_recipes) does exactly this, withtier/kind/category/q. The skill was sending users to a browser for a one-call operation.list_installed_versions. The upgrade action is still web-only — verified, and kept.preview_uninstall_recipe→uninstall_recipe) is MCP-callable; the skill implied web-only.set_integration_config,set_integration_overrides,run_integration_once,bulk_set_integration_state.pluginOnly— this plugin is the only surface that can publish a recipe, and it was the one surface with no instructions for doing so.brains-agenda
Carried the same dead
get_overnight_digestcall (2 sites), including atomorrow/thoughts/connections"lens" vocabulary that no longer exists. Now reads the newest "Daily digests" row and skips silently when absent.Verification
grep -n 'name: "<tool>"'in the brains repo; aliases resolved viaRENAME_CANONICAL.starter-pack-my-dayslug confirmed indb/init/168_starter_recipes_seed_bulk.sql.bun tests/plugin-contract/run.tspasses.IntegrationTemplatespec — it routes to the flow that owns it. Duplicating it would guarantee the next drift.The authoring section points at the MCP tool
create_integration_flow, which ships in ssvlabs/brains#871. Merge that first, or the authoring path dead-ends.Also note:
origin/feat/generic-mcp-surface-brns-mcp-011rewrites both of these skills ontocreate_flow({kind})/create_instance/list_instances— none of which exist on stage. It would trade 2 stale tool names for ~6 nonexistent ones. It should be treated as a design doc for an unlanded refactor, not merged as-is; this PR intentionally does not build on it.🤖 Generated with Claude Code