Skip to content

fix(skills): correct tool-surface drift in build/integrations/agenda skills - #10

Open
alonmuroch wants to merge 2 commits into
mainfrom
fix/skills-tool-surface-drift
Open

fix(skills): correct tool-surface drift in build/integrations/agenda skills#10
alonmuroch wants to merge 2 commits into
mainfrom
fix/skills-tool-surface-drift

Conversation

@alonmuroch

Copy link
Copy Markdown
Contributor

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 through apps/mcp/src/tools/tool-aliases.ts.

brains-build

  • get_overnight_digest was a phantom — and not just a stale name: the whole feature is gone from stage (no apps/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: the starter-pack-my-day recipe, which writes a "Daily digests" board.
  • create_automation doesn't exist → save_automation_draft (+ a note that update_automation edits in place without a flow).
  • Added the shipped capabilities the skill never mentioned: board forms, run_board_skill, sharing + share circles, dataset ACLs, board files/links, history/revert, automation secrets.

brains-integrations

  • "There's no MCP tool to enumerate the catalog" was false — list_recipes (canonical for list_starter_recipes) does exactly this, with tier/kind/category/q. The skill was sending users to a browser for a one-call operation.
  • Version drift is readable over MCP via list_installed_versions. The upgrade action is still web-only — verified, and kept.
  • The recipe uninstall cascade (preview_uninstall_recipeuninstall_recipe) is MCP-callable; the skill implied web-only.
  • Added install tuning: set_integration_config, set_integration_overrides, run_integration_once, bulk_set_integration_state.
  • New authoring section. The skill was consumer-side only. The authoring tools are 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_digest call (2 sites), including a tomorrow/thoughts/connections "lens" vocabulary that no longer exists. Now reads the newest "Daily digests" row and skips silently when absent.

Verification

  • Every tool name checked against grep -n 'name: "<tool>"' in the brains repo; aliases resolved via RENAME_CANONICAL.
  • The "Daily digests" board name and starter-pack-my-day slug confirmed in db/init/168_starter_recipes_seed_bulk.sql.
  • bun tests/plugin-contract/run.ts passes.
  • Deliberately does not duplicate the IntegrationTemplate spec — it routes to the flow that owns it. Duplicating it would guarantee the next drift.

⚠️ Merge order

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-011 rewrites both of these skills onto create_flow({kind}) / create_instance / list_instancesnone 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

…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.
@nir-ssvlabs
nir-ssvlabs self-requested a review July 21, 2026 09:33
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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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
nir-ssvlabs previously approved these changes Jul 21, 2026

@nir-ssvlabs nir-ssvlabs left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 "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`) |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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`) |

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🟡 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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants