feat: add /bm-* slash commands and bm_recent tool - #3
Conversation
Surface recently-updated notes through the curated Hermes tool map so the agent can answer "what's been touched lately?" without a specific search query. Maps to BM's recent_activity MCP tool; exposes a trimmed parameter set (timeframe, limit, type). Refs #2 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
Plugin-owned slash commands for in-session Basic Memory operations: search, read, context, recent, status, remember, project, workspace. Handlers close over the provider for live actor + config access, catch their own exceptions so users see specific messages rather than the generic "Plugin command error" line Hermes substitutes. /bm-remember writes to a separate remember_folder (default "bm-remember") so manual captures don't intermix with auto-generated session transcripts in capture_folder. Tag "manual-capture" disambiguates further. Title derives from the first non-empty line, trimmed to 80 chars, with a UTC timestamp fallback. /bm-workspace short-circuits in local mode with an explanatory line — workspaces are a BM Cloud concept and the listing call would otherwise return a generic "no workspaces" message. Registration is gated on hasattr(ctx, "register_command") for parity with the register_skill pattern; Hermes < v0.11.0 simply doesn't get the slash-command surface. Closes #2 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
CHANGELOG entry summarizes the slash-command surface, bm_recent tool, and remember_folder config. README adds a Slash commands section and the new config key. Plugin manifest + __version__ → 0.2.0. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Review notes from Codex:
Verification: I ran |
Two fixes for the issues raised on PR #3. P1 — ctx.register_command and ctx.register_skill silently no-op in real Hermes installs. Memory-provider plugins are loaded through a stripped- down _ProviderCollector (plugins/memory/__init__.py) that captures only register_memory_provider; other registration methods are not delegated to PluginManager. The bundled SKILL.md has been hitting this same path since 0.1.5 — the call ran but the entry never landed. Workaround: write directly to PluginManager._plugin_commands and _plugin_skills from inside register(). Mirror the exact entry shape, name normalization, and built-in-conflict guard from PluginContext.register_command (plugins.py:401-453) and register_skill (plugins.py:622-665). When the upstream collector is patched, ctx.register_command/register_skill will write identical entries — the reach-in becomes a redundant idempotent overwrite. Recursion is safe: PluginManager.discover_and_load is idempotent (plugins.py:699) and explicitly skips memory-provider plugins at the manifest-routing stage (plugins.py:792-802), so calling _ensure_plugins_discovered() from inside register() cannot re-enter. New tests in tests/test_commands.py use a _ProviderCollector-shaped ctx (no register_command attribute) and assert the reach-in actually populates the fake PluginManager. The original tests used MagicMock, which masked the silent skip by making every attribute exist. P2 — bm_recent dropped real results. recent_activity(output_format= "json") returns a bare list[dict] per the BM signature; the handler only checked dict keys. Added the list branch + regression test matching the real JSON shape. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
|
Thanks for the review — addressed all three. P1 (register_command silent skip): confirmed Codex is right. Hermes's Rather than waiting on an upstream patch, this commit reaches into Verified recursion is safe: Tests now use a Forward-compat: P2 ( P3 (PR title): renamed to Suite: 221 passed, 12 skipped. Still haven't run |
groksrc
left a comment
There was a problem hiding this comment.
Re-reviewed commit 6513a63. The three items from my earlier pass look addressed:
- P1: I checked the Hermes clone again: memory providers still load through
_ProviderCollector, while slash commands route throughPluginManager._plugin_commands. The new fallback writes the same command/skill registry shapes thatPluginContext.register_command/register_skilluse, and the tests now cover a collector-shaped context instead of relying onMagicMock. - P2:
/bm-recentnow handles Basic Memory's barelist[dict]JSON return shape, with a regression test. - P3: the semantic PR title check is now passing.
Verification:
- Local:
uv run --with pytest pytest->221 passed, 12 skipped - GitHub checks: Python 3.11/3.12/3.13/3.14 unit jobs pass;
semantic-pr-titlepasses
No new blocking findings from this pass. Remaining caveat is expected: the PluginManager reach-in is private and temporary, so it should be removable once Hermes delegates register_command / register_skill from the memory-provider collector.
Summary
/bm-search,/bm-read,/bm-context,/bm-recent,/bm-status,/bm-remember,/bm-project,/bm-workspace. Registered viactx.register_command(...)with ahasattrguard so older Hermes installs silently skip the surface.bm_recenttool (curated wrapper around BM'srecent_activity) so the agent can also surface recently-updated notes by timeframe.remember_folderconfig key (defaultbm-remember) — manual captures via/bm-rememberland here, kept separate from auto session transcripts incapture_folder. Captures are taggedmanual-capture; titles derived from the first non-empty line (≤80 chars), with a UTC timestamp fallback.Read-only by design:
/bm-projectand/bm-workspacelist but don't switch. Mid-session project/workspace switching is deferred to a follow-up to avoid auto-capture landing in the wrong place.Closes #2
Test plan
uv run --with pytest pytest) — 213 passed, 12 skipped (integration, gated onBM_INTEGRATION=1).tests/test_commands.pycovers: registration viaregister_command,hasattrfallback for old Hermes, registration errors logged without breaking memory provider registration, per-handler usage strings, uninitialized state, happy path for each command, exception → plain-text error./bm-*command, confirm output renders verbatim and/bm-statusreflects live state. (Manual — depends on a Hermes install.)BM_INTEGRATION=1) — unchanged from prior; new slash handlers are exercised by unit suite against a fake MCP session.🤖 Generated with Claude Code