fix(kernel): persist agent skill & MCP-server assignments to agent.toml#6046
Conversation
c0eee65 to
a5fb487
Compare
houko
left a comment
There was a problem hiding this comment.
Two CLAUDE.md style violations to fix before merge.
1. CHANGELOG.md — four sentences packed onto one continuation line
CLAUDE.md is explicit: "CHANGELOG.md bullets — one sentence per line within a bullet."
The new fix(kernel) entry's continuation line contains four sentences on a single line.
Split into one sentence per line:
- **fix(kernel): persist per-agent skill & MCP-server assignments to `agent.toml` so they survive a restart** (#6045) (@DaBlitzStein).
`set_agent_skills` and `set_agent_mcp_servers` wrote only the SQLite blob and never called `persist_manifest_to_disk`, unlike the sibling setters (`set_agent_model` / `set_agent_channels` / `set_agent_schedule` / `set_agent_tool_filters`).
Since boot reconciliation re-syncs each agent from its on-disk `agent.toml` and overwrites DB-only fields, a skill/MCP assigned via the dashboard returned `200`, showed as assigned in the API, then was silently wiped on the next daemon restart.
Both setters now persist to disk.
Regression test: `test_set_agent_skills_persists_allowlist_to_agent_toml`.2. crates/librefang-kernel/src/kernel/agent_state.rs — two multi-line // comment blocks
CLAUDE.md: "Never write multi-paragraph docstrings or multi-line comment blocks — one short line max."
The first block (8 lines before set_agent_skills's persist_manifest_to_disk call) and the second (4 lines before the MCP one) both violate this.
The WHY is non-obvious and worth a comment, but it should fit in one line each.
Suggested replacements:
// Without this, boot reconciliation silently overwrites DB-only fields from the on-disk agent.toml on restart.
self.persist_manifest_to_disk(agent_id);// Same persistence requirement as set_agent_skills: boot reconciliation overwrites DB-only fields from agent.toml.
self.persist_manifest_to_disk(agent_id);The detailed mechanism (boot.rs log message, sibling list) belongs in the PR body — where it already appears — rather than in an inline comment that will rot as the codebase evolves.
Generated by Claude Code
There was a problem hiding this comment.
One finding during daily review pass:
Missing regression test for set_agent_mcp_servers
The PR adds persist_manifest_to_disk to both set_agent_skills (lines ~460–475 of agent_state.rs) and set_agent_mcp_servers (lines ~534–540), and correctly adds test_set_agent_skills_persists_allowlist_to_agent_toml for the skills path. But there is no parallel test for the MCP-servers path — a future regression in that setter could go undetected.
Please add test_set_agent_mcp_servers_persists_servers_to_agent_toml alongside the existing test, using the same pattern (spawn agent, call set_agent_mcp_servers, read_to_string the agent.toml, assert the server name appears). The two paths got identical fixes; they should have identical coverage.
No other issues found.
houko
left a comment
There was a problem hiding this comment.
Requesting changes to consolidate the three unresolved review points so this doesn't merge with known gaps. All are small and the fix logic itself is correct — just needs the coverage and style cleanup before merge.
-
Missing regression test for
set_agent_mcp_servers(raised 06-10 and 06-12, still open). The PR fixes bothset_agent_skillsandset_agent_mcp_servers, but only the skills path has a test. Addtest_set_agent_mcp_servers_persists_allowlist_to_agent_tomlmirroring the existing one: boot kernel, spawn agent with a knownsource_toml_path, callset_agent_mcp_servers([<server>]), read the on-diskagent.toml, assert the server name is present. Two identical fixes should have identical coverage. -
CHANGELOG continuation packs four sentences on one line (raised 06-11). CLAUDE.md: "CHANGELOG.md bullets — one sentence per line within a bullet." Split the new
fix(kernel)entry's continuation into one sentence per line. -
Two multi-line
//comment blocks inagent_state.rs(raised 06-11). The 8-line block beforeset_agent_skills'spersist_manifest_to_diskcall and the 4-line block before the MCP one violate the kernel crate's one-line-per-comment convention. Keep the WHY but compress each to a single line; the detailed mechanism (boot.rs log, sibling list) already lives in the PR body.
None of these are logic blockers — the persist fix is correct and the breadth is complete (skills + mcp were the only two setters missing the call). Re-request review once they're addressed.
a5fb487 to
53eae21
Compare
b921104 to
ce83fa5
Compare
6297ee5 to
dc1a891
Compare
dc1a891 to
07f73b1
Compare
07f73b1 to
c196392
Compare
…ml (librefang#6045) set_agent_skills and set_agent_mcp_servers updated the in-memory registry and the SQLite blob (save_agent) but never called persist_manifest_to_disk, unlike the sibling setters (set_agent_model / set_agent_channels / set_agent_schedule / set_agent_tool_filters). Boot reconciliation re-syncs each agent from its on-disk agent.toml and overwrites DB-only fields, so a skill or MCP server assigned via the dashboard returned 200, showed as assigned in the API, then was silently wiped on the next daemon restart. Both setters now call persist_manifest_to_disk after a successful save_agent, so the allowlist lands in agent.toml and survives a restart. Placed in the kernel setter (not the API route handler) so it is robust to the routes/agents module split (librefang#5975). Regression test: test_set_agent_skills_persists_allowlist_to_agent_toml spawns an agent, assigns a skill, and asserts agent.toml on disk contains it.
…GELOG Adds the missing regression test for set_agent_mcp_servers (modelled on the existing set_agent_skills test) and splits the CHANGELOG entry into one sentence per line per convention.
c196392 to
d9a74b0
Compare
All three requested items (MCP test, CHANGELOG one-sentence-per-line, comment wrapping) were addressed in the 06-20 push; base merged up to current main. Re-reviewed and clean.
Summary
Closes #6045.
Assigning a skill or MCP server to an agent via the dashboard/API (
PUT /api/agents/{id}/skills/.../mcp_servers) persisted only to the SQLite blob, not toagent.toml. Because boot reconciliation treats the on-disk manifest as authoritative, the assignment returned200, showed asassignedin the API, then was silently wiped on the next daemon restart.Root cause
set_agent_skillsandset_agent_mcp_servers(crates/librefang-kernel/src/kernel/agent_state.rs) update the in-memory registry and callsave_agent(DB) but never callpersist_manifest_to_disk. The sibling setters all do:set_agent_model,set_agent_channels,set_agent_schedule,set_agent_tool_filters(tools). Skills and MCP were the only two missing it — structurally identical otherwise, so this was an oversight.On boot,
boot.rsloads each agent from the substrate, reads itsagent.toml, and when the projection differs overwrites the DB with the disk manifest ("Agent TOML on disk differs from DB, updating"). Anything written only to the DB is therefore lost.Change
self.persist_manifest_to_disk(agent_id);toset_agent_skillsandset_agent_mcp_servers, after the successfulsave_agent, mirroring the sibling setters.routes/agents.rs→routes/agents/module split (refactor(api): split routes/agents.rs into per-concern modules #5975) and any future API refactor.Verification
cargo clippy -p librefang-kernel --all-targets -- -D warnings— clean.test_set_agent_skills_persists_allowlist_to_agent_toml(kernel lib): boots a kernel, installs a skill, spawns an agent with a knownsource_toml_path, callsset_agent_skills, and asserts the on-diskagent.tomlcontains the assigned skill. Passes (1 passed).