v0.51.28 — Release E2 (MCP server Option A rewrite + WebUI /goal command)
Two-PR contributor batch shipping the MCP server rewrite and the new /goal command.
Highlights
/goal command — track multi-turn goals with budget enforcement
New /goal slash command lets you set a multi-turn objective and track progress automatically:
/goal "build a counter app in react" budget=15
/goal status
/goal pause
/goal resume
/goal clear
The agent emits goal and goal_continue SSE events after each completed turn, so the UI can show progress and queue continuation prompts when the goal isn't finished. SQLite-backed state per profile, fully integrated with the streaming chat path.
By @Michaelyklam — closes #1808.
MCP server Option A rewrite
mcp_server.py is now a clean 567-LOC implementation that imports api.models and api.profiles canonically rather than carrying duplicate slug-matching helpers. The _profiles_match helper now lives in api/profiles.py as the single source of truth (mcp_server.py and api/routes.py both import the canonical version — re-introducing a local copy in either trips a parity test immediately).
Notable improvements:
- Env-aware
WEBUI_URL(HERMES_WEBUI_HOST/HERMES_WEBUI_PORT) - Data-loss safety:
delete_projectnow refuses to touch session JSONs whenHERMES_WEBUI_PASSWORDis unset, returning{ok: true, unassigned_sessions: 0, warning: "…"}instead. Prevents data corruption when an MCP client tries to delete a project on an unauthenticated server. - 53-test coverage in
tests/test_mcp_server.pyincluding HTTP wire-format integration tests, profile-scoped isolation, legacy untagged row visibility, and--profile fooCLI ordering regression.
By @samuelgudi — closes #1616.
Test isolation infrastructure
The MCP test suite addition exposed three separate sys.modules pollution bugs in the broader test infrastructure. All three are fixed in this release:
-
mock.patch.dict(sys.modules, ...)deletes lazy submodules —tests/test_issue1857_usage_overwrite.pywas usingpatch.dict, which on__exit__deletes any keys added during the patched scope. Lazily-imported pydantic submodules (e.g.pydantic.root_model) were silently evicted, producingKeyError: 'pydantic.root_model'in unrelated downstream tests. Replaced with manual save/restore using a sentinel. -
Module-attribute restoration —
tests/test_mcp_server.pymutated module-level constants onapi.config/api.models/mcp_serverwithout restoring; downstream tests read deleted tmpdirs. Now snapshot/restore on first_reimport_mcp()call. -
Parent-package attribute leak —
test_profiles_match_single_source_of_truthre-importsapi.routes/api.profilesfor the canonical-helper identity check. When restoringsys.modulesonly, fresh modules still leaked through becauseimport api.routes as rresolves viasys.modules['api'].routes(parent-package attribute), NOT directly viasys.modules['api.routes']. Fix: also restore parent-package attributes.
CI updates
Added pytest-asyncio to CI deps and best-effort mcp install. tests/test_mcp_server.py uses pytest.importorskip as a safety net so the matrix stays green even if the optional mcp package fails to install on a future Python version.
Verification
- Tests: 4898 → 4947 passing (+49 net new)
- Browser API harness (port 8789): all 11 endpoints + 20 QA tests PASS
node -con all modifiedstatic/*.jsfiles: clean- Opus advisor pre-release verdict: SHIP-READY
- v0.51.27 carry-overs preserved:
_strip_workspace_prefix,on_interim_assistant,_max_iterations_cfg, input-token guard
Follow-up items filed
- #1932 — Goal hook fires on every assistant turn including unrelated user messages
- #1933 — Goal command runtime status strings need i18n keys
Full diff
16 files, +2692/-105.
Full Changelog: v0.51.27...v0.51.28