feat: PAM 0.4.0 — Claude & Kimi agent layers, MCP server#5
Conversation
6faeec6 to
c07bb15
Compare
Yehonal
left a comment
There was a problem hiding this comment.
Thanks for the PR. I would not approve this yet: the Claude/MCP layer is useful as a standalone base, but there are a few correctness issues that should be fixed before merge.
Findings:
- Blocking: the Claude plugin appears to use the plugin repository as the PAM workspace.
.claude-plugin/plugin.json starts the MCP server from ${CLAUDE_PLUGIN_ROOT}/tools/pam-mcp-server.mjs, while tools/lib/workspace.mjs defaults the workspace from the script path. When installed as a plugin, this means pam_version, memory_append, /pam:dream, curator/scribe, etc. can operate on the plugin copy instead of the user project. Please pass the actual Claude project directory as --workspace, or change the hosted-server default to resolve to the opened project/current working directory instead of the script location.
- High:
memory_appenddoes not enforceprotectedPaths.
tools/lib/memory-append.mjs accepts any config.managedLogs[].source inside the workspace and writes to it without checking config.protectedPaths. This contradicts the MCP docs, which say there is no MCP write path for protected files such as AGENTS.md, CLAUDE.md, and memory/agent-memory/. A wrong or malicious config can route appends into protected paths. Please apply the same protected-path guard before writing append entries.
- Medium: unified diff application is fragile for multi-hunk patches.
tools/lib/memory-proposals.mjs applies hunks in forward order using the original oldStart values against already-mutated content. If an earlier hunk adds/removes lines, later hunks can fail with a mismatch or target the wrong location. Please apply hunks from bottom to top, or track a cumulative line delta while applying them.
- Low:
/pam:statuscounts already-applied proposals as pending.
.claude/commands/status.md uses ls memory/maintenance/proposals/*.json, which includes *.applied.json. Other status surfaces exclude applied proposals correctly. Please filter those out, e.g. with find ... -name '*.json' ! -name '*.applied.json'.
Validation I ran locally:
npm test: 66/66 passednpm run memory:graph:validate: oknpm run mcp:smoke: okgit diff --check origin/main...HEAD: ok
…date Claude layer into tools/claude/
Review fixes:
- fix(workspace): default workspace root to process.cwd() so MCP server
operates on the user's project when launched as a Claude Code plugin
- fix(memory-append): enforce protectedPaths before writing; reject
appends to AGENTS.md, memory/agent-memory/, memory/sources/, etc.
- fix(memory-proposals): apply unified-diff hunks bottom-to-top to handle
multi-hunk patches with line count changes correctly
- fix(status command): exclude *.applied.json from pending proposal count
Refactor:
- Move all Claude-specific files from root into tools/claude/:
- .claude/{agents,commands} -> tools/claude/{agents,commands}
- hooks/ -> tools/claude/hooks/
- templates/pam-claude-layer/ -> tools/claude/templates/
- docs/{curator,scribe,pam-claude-layer}.md -> tools/claude/docs/
- tools/install-pam-statusline.mjs -> tools/claude/install-statusline.mjs
- Update root .claude-plugin/plugin.json with explicit paths
- Update CHANGELOG.md, package.json scripts, and all internal references
Tests: 68/68 pass (66 existing + 2 new)
0316a64 to
3d88580
Compare
|
Hi @Yehonal, thanks for the thorough review. All four findings have been addressed in the latest push:
Additional refactor: All Claude-specific artifacts have been consolidated under Verification:
Could you take another look when you have a moment? |
|
Bonus: Added a Kimi Code CLI has supported MCP since late 2025. The new node tools/kimi/install-mcp.mjs --apply
kimi mcp test pam
Docs live in |
89d6aa7 to
b7cd4d0
Compare
Yehonal
left a comment
There was a problem hiding this comment.
Looks good to merge from my side. The symlink containment issue discussed in review appears to be pre-existing rather than introduced by this PR, so I would track it as a separate security follow-up unless this PR expands the production trust boundary.\n\nVerified locally: npm test passes (68/68), and git diff --check is clean.
|
Heads up: we split semantic migration enforcement into PR #8 so it can land before this feature branch. After #8 merges, this PR should be rebased onto updated main and adjusted as the next semantic migration step:
This preserves the intended ordered upgrade chain for agents migrating older workspaces: |
PAM 0.4.0 ships the optional agent layer end-to-end: a local stdio MCP server, the curator and scribe reference subagents, and a Claude Code plugin that wires the MCP server, agents, slash commands, and hooks into a single installable unit. Runtime: - MCP server (tools/pam-mcp-server.mjs + tools/lib/*) exposes 15 typed tools over stdio (pam_version, memory_state, memory_list/read/search, graph_query/stats/validate/reindex, memory_audit, memory_propose_edit, memory_append, memory_apply_proposal, maintenance_config/run). - memory_append appends a dated section to a managed log, newest-first, validating the YYYY-MM-DD header contract. - memory_apply_proposal re-validates path safety, re-applies the diff with drift detection, archives successful applies as <id>.applied.json, and writes the archive before mutating the target so an interrupted apply leaves the proposal recoverable. Subagents: - curator: read-mostly hygiene auditor; never mutates memory; emits proposals only. - scribe: session-end closeout; append-only via memory_append. Claude Code plugin layout: - .claude-plugin/plugin.json declares the plugin and inlines mcpServers. - .claude/commands/: dream, explain, status, enable-status-line (namespaced under /pam: by the plugin). - .claude/agents/: curator, scribe. - hooks/: SessionStart freshness check and PostToolUse memory_append counter. UX: - Statusline shows graph health, pending-proposal count, catalog age, and session appends. Pending count excludes *.applied.json. - /dream calls graph_reindex (not graph_validate) to actually refresh memory/graph/catalog.json. - /explain prints a one-screen legend with live values via an inlined shell block; no LLM reasoning per invocation. - /enable-status-line toggles the statusline by renaming statusLine to/from _pamDisabledStatusLine. Reversible; never deletes. Docs: - docs/mcp-server.md, docs/curator-agent.md, docs/scribe-agent.md, docs/pam-claude-layer.md. Notes: - memory/maintenance/proposals/ is now gitignored; proposal artifacts are workspace-local audit trail and should not ship in clones.
…date Claude layer into tools/claude/
Review fixes:
- fix(workspace): default workspace root to process.cwd() so MCP server
operates on the user's project when launched as a Claude Code plugin
- fix(memory-append): enforce protectedPaths before writing; reject
appends to AGENTS.md, memory/agent-memory/, memory/sources/, etc.
- fix(memory-proposals): apply unified-diff hunks bottom-to-top to handle
multi-hunk patches with line count changes correctly
- fix(status command): exclude *.applied.json from pending proposal count
Refactor:
- Move all Claude-specific files from root into tools/claude/:
- .claude/{agents,commands} -> tools/claude/{agents,commands}
- hooks/ -> tools/claude/hooks/
- templates/pam-claude-layer/ -> tools/claude/templates/
- docs/{curator,scribe,pam-claude-layer}.md -> tools/claude/docs/
- tools/install-pam-statusline.mjs -> tools/claude/install-statusline.mjs
- Update root .claude-plugin/plugin.json with explicit paths
- Update CHANGELOG.md, package.json scripts, and all internal references
Tests: 68/68 pass (66 existing + 2 new)
- tools/kimi/install-mcp.mjs registers PAM with Kimi Code CLI by writing an absolute-path entry into ~/.kimi/mcp.json - tools/kimi/templates/mcp.fragment.json is the config template - tools/kimi/docs/pam-kimi-layer.md covers install, verify, uninstall, and ad-hoc --mcp-config-file usage - npm run kimi:mcp:install shortcut - docs/mcp-server.md and AGENT_BOOTSTRAP.md gain Kimi-specific sections The installer mirrors the Claude statusline installer UX: - dry-run by default, --apply to write - --force to overwrite existing pam entry - --uninstall to remove and restore backup - backs up existing ~/.kimi/mcp.json before writing Update-safe: absolute paths mean git pull updates the server code without touching Kimi's config.
b7cd4d0 to
d621ade
Compare
Summary
PAM 0.4.0 ships the optional agent layer end-to-end:
tools/pam-mcp-server.mjs) exposes 15 typed tools over stdio:pam_version,memory_state,memory_list/read/search,graph_query/stats/validate/reindex,memory_audit,memory_propose_edit,memory_append,memory_apply_proposal,maintenance_config/run.curator(read-mostly hygiene auditor, emits proposals only) andscribe(session-end closeout, append-only viamemory_append)..claude-plugin/plugin.json+.claude/{agents,commands}/+hooks/) wires the MCP server, agents, slash commands, and lifecycle hooks into a single installable unit. Slash commands:/pam:dream,/pam:status,/pam:explain,/pam:enable-status-line.SessionStartfreshness/proposal nag,PostToolUseappend counter, statusline showing graph health and session activity.The markdown + JSONL contract is unchanged; existing 0.3.0 graph-v1 workspaces work without modification.
Notable correctness fixes in this commit
memory_apply_proposalnow uses the validated inputproposalIdfor the archive path (notrecord.proposalId), closing a hand-crafted-artifact traversal risk. Archive is written before the target so an interrupted apply leaves the proposal recoverable./dreamcallsgraph_reindex(notgraph_validate) to actually refreshmemory/graph/catalog.json.*.applied.jsonfrom the pending-proposal count.hooks/post-memory-append.shrejects session IDs containing/,\\, or..before using them as a filename.Test plan
npm test(66/66 subtests pass)npm run mcp:smoke(MCP server starts cleanly)