Skip to content

Add Proma integration plugin for Nowledge Mem#232

Open
HamsteRider-m wants to merge 2 commits into
nowledge-co:mainfrom
HamsteRider-m:proma-nmem-plugin
Open

Add Proma integration plugin for Nowledge Mem#232
HamsteRider-m wants to merge 2 commits into
nowledge-co:mainfrom
HamsteRider-m:proma-nmem-plugin

Conversation

@HamsteRider-m
Copy link
Copy Markdown

@HamsteRider-m HamsteRider-m commented May 11, 2026

Summary

  • New Proma integration plugin (nowledge-mem-proma-plugin) providing persistent cross-session memory through MCP tools, lifecycle hooks, and a companion skill
  • Proma is a desktop AI agent built on the Claude Agent SDK
  • Entry added to integrations.json registry

Plugin Structure

nowledge-mem-proma-plugin/
├── .claude-plugin/plugin.json    # Manifest
├── hooks/
│   ├── hooks.json                # Stop + SessionStart hook config
│   ├── save-to-nmem.py           # Session capture via REST API
│   └── read-working-memory.py    # WM injection via nmem CLI
├── skills/nmem/SKILL.md          # Companion skill
├── README.md                     # Full install & usage docs
└── CHANGELOG.md                  # 0.1.0 initial release

How It Works

  1. MCP Server — Proma's mcp.json (key: servers) connects to nmem MCP endpoint, giving the agent mcp__nowledge-mem__* tools
  2. Stop Hooksave-to-nmem.py parses Proma session JSONL (~/.proma/agent-sessions/<id>.jsonl), deduplicates by UUID, extracts text from content blocks, and uploads to nmem via REST API
  3. SessionStart Hookread-working-memory.py calls nmem --json wm read and outputs the briefing for context injection
  4. Skill/nmem-save, /nmem-search, /nmem-status slash commands as fallback

Test Plan

  • nmem API connectivity verified (POST /threads returns 200)
  • Working Memory read via nmem CLI verified
  • Session JSONL parsing tested with real Proma session (488 messages captured)
  • Hook scripts Python syntax validated
  • MCP tool availability (requires Proma restart, will test in next session)

Proma is unique among the integrations because it uses "servers" (not "mcpServers") as the MCP config key and stores sessions as JSONL in ~/.proma/agent-sessions/.

🤖 Generated with Claude Code

Summary by CodeRabbit

Release Notes

  • New Features

    • Added Proma desktop application integration with Nowledge Mem personal knowledge graph
    • Sessions automatically save to long-term memory when closing
    • Working memory automatically loaded on session start
    • New slash commands for manual memory save, search, and status checking
  • Documentation

    • Added comprehensive setup guide and architecture documentation for Proma integration

Review Change Stack

Proma is a desktop AI agent built on Claude Agent SDK. This plugin
provides the three-layer integration pattern:

- MCP server config (mcp.json with "servers" top-level key)
- Lifecycle hooks (Stop: auto-capture sessions, SessionStart: inject WM)
- Companion skill (nmem: /nmem-save, /nmem-search, /nmem-status)

Sessions are parsed from Proma's JSONL format
(~/.proma/agent-sessions/<id>.jsonl) and uploaded to nmem via REST API.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
Copy link
Copy Markdown

@coderabbitai coderabbitai Bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 3

🧹 Nitpick comments (2)
integrations.json (2)

605-605: ⚖️ Poor tradeoff

Consider updating docsUrl to follow the established pattern.

Most integrations with a directory field use the pattern "/docs/integrations/<id>" for their docsUrl. For example:

  • Cursor: "/docs/integrations/cursor"
  • Codex: "/docs/integrations/codex-cli"

External repo links are typically reserved for integrations without a directory field. Since Proma has "directory": "nowledge-mem-proma-plugin", consider using "/docs/integrations/proma" and creating the corresponding docs page.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations.json` at line 605, The current integration entry uses an
external repo URL in the "docsUrl" field despite having "directory":
"nowledge-mem-proma-plugin"; update the "docsUrl" value to the canonical
internal docs path "/docs/integrations/proma" and ensure a corresponding docs
page is created under that route so the integration follows the established
pattern; modify the integrations.json entry (the "docsUrl" property for the
Proma integration) to the new path and add the docs page for the "proma"
integration.

583-586: ⚡ Quick win

Consider using "plugin-capture" instead of "hook" for threadSave.method.

The value "hook" appears to be new and inconsistent with existing patterns. The Copilot CLI integration (line 70) uses "plugin-capture" with a similar approach: "Python script reads Copilot CLI transcript events from Stop, PreCompact, and SessionEnd hooks, creates threads via nmem t import."

The Proma implementation follows the same pattern (hook script reads session data and uploads). For consistency with the existing registry schema, consider using "plugin-capture".

Proposed fix
       "threadSave": {
-        "method": "hook",
+        "method": "plugin-capture",
         "note": "Stop hook runs save-to-nmem.py which parses Proma session JSONL from ~/.proma/agent-sessions/ and uploads messages to nmem via REST API. SessionStart hook injects Working Memory via read-working-memory.py."
       },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations.json` around lines 583 - 586, The "threadSave" integration entry
uses method: "hook" which is inconsistent with the existing registry pattern;
update the threadSave object's "method" property from "hook" to "plugin-capture"
so it matches similar integrations (e.g., the Copilot CLI entry) and preserves
the intent that a Python script reads Proma session JSONL and uploads threads
via nmem; ensure the surrounding metadata/note remains unchanged and validate
the JSON after the edit.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@integrations.json`:
- Around line 587-591: Update the autonomy settings for the "autonomy"
integration entry so that the "recall" and "distill" fields use "guided" instead
of "automatic" (i.e., change the values for the "recall" and "distill" keys
inside the "autonomy" object) to match the other MCP-transport integrations'
pattern.

In `@nowledge-mem-proma-plugin/hooks/hooks.json`:
- Line 8: Clarify in the README that the hooks path can be resolved two ways:
either set the PROMA_HOME environment variable (export
PROMA_HOME=/path/to/proma) so entries like "${PROMA_HOME}/hooks/save-to-nmem.py"
are expanded, or replace "${PROMA_HOME}" with a literal path (e.g.,
"~/.proma/hooks/...") in hooks.json; explicitly mention that the Python scripts
save-to-nmem.py and read-working-memory.py default to "~/.proma" when PROMA_HOME
is unset and provide one clear example for each approach so users know which
option to follow.

In `@nowledge-mem-proma-plugin/hooks/save-to-nmem.py`:
- Around line 204-210: Add a brief clarifying comment above the assistant
message filter (the block starting with elif msg_type == "assistant") explaining
why we skip entries where role == "user" (e.g., whether this handles a known
Proma format quirk, is a defensive check for malformed records, or prevents
duplicate processing), and reference the relevant symbols in the comment
(msg_type, role, extract_text_from_content, and messages) so future maintainers
understand the intent and won't remove the check.

---

Nitpick comments:
In `@integrations.json`:
- Line 605: The current integration entry uses an external repo URL in the
"docsUrl" field despite having "directory": "nowledge-mem-proma-plugin"; update
the "docsUrl" value to the canonical internal docs path
"/docs/integrations/proma" and ensure a corresponding docs page is created under
that route so the integration follows the established pattern; modify the
integrations.json entry (the "docsUrl" property for the Proma integration) to
the new path and add the docs page for the "proma" integration.
- Around line 583-586: The "threadSave" integration entry uses method: "hook"
which is inconsistent with the existing registry pattern; update the threadSave
object's "method" property from "hook" to "plugin-capture" so it matches similar
integrations (e.g., the Copilot CLI entry) and preserves the intent that a
Python script reads Proma session JSONL and uploads threads via nmem; ensure the
surrounding metadata/note remains unchanged and validate the JSON after the
edit.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 3dd31d8b-95cf-4245-9202-001c96494d82

📥 Commits

Reviewing files that changed from the base of the PR and between 0a620df and 635dcaa.

📒 Files selected for processing (8)
  • integrations.json
  • nowledge-mem-proma-plugin/.claude-plugin/plugin.json
  • nowledge-mem-proma-plugin/CHANGELOG.md
  • nowledge-mem-proma-plugin/README.md
  • nowledge-mem-proma-plugin/hooks/hooks.json
  • nowledge-mem-proma-plugin/hooks/read-working-memory.py
  • nowledge-mem-proma-plugin/hooks/save-to-nmem.py
  • nowledge-mem-proma-plugin/skills/nmem/SKILL.md

Comment thread integrations.json
Comment on lines +587 to +591
"autonomy": {
"bootstrap": "automatic",
"recall": "automatic",
"distill": "automatic",
"threads": "automatic-capture",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Compare autonomy settings for MCP-transport integrations
jq '.integrations[] | select(.transport == "mcp" or .transport == "cli+mcp" or .transport == "hybrid-cli+mcp") | {id, transport, recall: .autonomy.recall, distill: .autonomy.distill}' integrations.json

Repository: nowledge-co/community

Length of output: 625


🏁 Script executed:

fd -t f "SKILL.md" nowledge-mem-proma-plugin

Repository: nowledge-co/community

Length of output: 112


🏁 Script executed:

cat -n nowledge-mem-proma-plugin/skills/nmem/SKILL.md | head -40

Repository: nowledge-co/community

Length of output: 2296


Change proma's autonomy levels to match other MCP integrations.

The skill documentation confirms that recall and distill require agent interpretation:

  • Recall ("When user says 'before', 'last time'...") is reactive to user language cues, not truly automatic
  • Distill ("After key decisions...") requires the agent to recognize when a key decision occurs

All other MCP-transport integrations (cursor, claude-desktop, mcp-direct, gemini-cli, codex-cli) use "guided" for both recall and distill. Proma should follow this pattern:

Proposed fix
       "autonomy": {
         "bootstrap": "automatic",
-        "recall": "automatic",
-        "distill": "automatic",
+        "recall": "guided",
+        "distill": "guided",
         "threads": "automatic-capture",
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"autonomy": {
"bootstrap": "automatic",
"recall": "automatic",
"distill": "automatic",
"threads": "automatic-capture",
"autonomy": {
"bootstrap": "automatic",
"recall": "guided",
"distill": "guided",
"threads": "automatic-capture",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@integrations.json` around lines 587 - 591, Update the autonomy settings for
the "autonomy" integration entry so that the "recall" and "distill" fields use
"guided" instead of "automatic" (i.e., change the values for the "recall" and
"distill" keys inside the "autonomy" object) to match the other MCP-transport
integrations' pattern.

"hooks": [
{
"type": "command",
"command": "python \"${PROMA_HOME}/hooks/save-to-nmem.py\"",
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

Clarify PROMA_HOME variable usage vs hardcoded path.

The hooks configuration uses "${PROMA_HOME}/hooks/save-to-nmem.py" and "${PROMA_HOME}/hooks/read-working-memory.py", but the README (lines 60, 73) instructs users to replace <proma-home> with "your actual Proma home path."

This creates ambiguity:

  1. Should users set the PROMA_HOME environment variable?
  2. Should users replace ${PROMA_HOME} with a hardcoded path like ~/.proma?

The Python scripts default to ~/.proma if PROMA_HOME is unset (e.g., save-to-nmem.py line 55), so the hooks should work either way, but the installation instructions should clarify:

  • Either explicitly tell users to use ~/.proma/hooks/... (most straightforward)
  • Or explain that ${PROMA_HOME} must be set as an environment variable for Proma to expand

Also applies to: 21-21

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nowledge-mem-proma-plugin/hooks/hooks.json` at line 8, Clarify in the README
that the hooks path can be resolved two ways: either set the PROMA_HOME
environment variable (export PROMA_HOME=/path/to/proma) so entries like
"${PROMA_HOME}/hooks/save-to-nmem.py" are expanded, or replace "${PROMA_HOME}"
with a literal path (e.g., "~/.proma/hooks/...") in hooks.json; explicitly
mention that the Python scripts save-to-nmem.py and read-working-memory.py
default to "~/.proma" when PROMA_HOME is unset and provide one clear example for
each approach so users know which option to follow.

Comment on lines +204 to +210
elif msg_type == "assistant":
role = message.get("role", "assistant")
if role == "user":
continue
text = extract_text_from_content(content)
if text:
messages.append({"role": "assistant", "content": text})
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

⚠️ Potential issue | 🟡 Minor | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Search for entries with type="assistant" but message.role="user"
# This would validate the edge case being filtered

cd ~/.proma/agent-sessions/ 2>/dev/null || exit 1

for f in *.jsonl; do
  echo "Checking $f..."
  jq -c 'select(.type == "assistant" and .message.role == "user")' "$f" 2>/dev/null | head -5
done

Repository: nowledge-co/community

Length of output: 47


🏁 Script executed:

# First, find the file being reviewed
find . -name "save-to-nmem.py" -type f

Repository: nowledge-co/community

Length of output: 115


🏁 Script executed:

# Search for test files or example JSONL data that might show the message format
find . -name "*.jsonl" -o -name "*test*" -o -name "*fixture*" | head -20

Repository: nowledge-co/community

Length of output: 1061


🏁 Script executed:

# Look for documentation or comments about Proma message structure
rg -i "proma.*format|message.*role|assistant.*role" --type py -B 2 -A 2

Repository: nowledge-co/community

Length of output: 6463


🏁 Script executed:

# Check if there's any documentation about this specific pattern
rg -i "type.*assistant|role.*user" --type py -B 3 -A 3

Repository: nowledge-co/community

Length of output: 20780


Add clarifying comment on assistant message role filter.

Lines 205-207 skip assistant-type entries where role == "user". This suggests entries can have type == "assistant" but message.role == "user" in Proma JSONL format. Without a comment explaining this edge case, the intent is unclear. Add a comment documenting whether this:

  • Handles a known Proma format quirk
  • Filters malformed entries defensively
  • Prevents duplicate message processing

This will help maintainers understand the design rationale.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@nowledge-mem-proma-plugin/hooks/save-to-nmem.py` around lines 204 - 210, Add
a brief clarifying comment above the assistant message filter (the block
starting with elif msg_type == "assistant") explaining why we skip entries where
role == "user" (e.g., whether this handles a known Proma format quirk, is a
defensive check for malformed records, or prevents duplicate processing), and
reference the relevant symbols in the comment (msg_type, role,
extract_text_from_content, and messages) so future maintainers understand the
intent and won't remove the check.

- Split unified 'nmem' skill into 5 standard skills:
  read-working-memory, search-memory, distill-memory, save-thread, status
- Add uvx fallback for nmem CLI discovery in read-working-memory.py
- Add static contract tests (tests/plugin_e2e/test_proma_plugin.py)
- Add Proma project description and GitHub link to README
- Update integrations.json skills array to standard names

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
@nowledge-co nowledge-co deleted a comment from coderabbitai Bot May 12, 2026
@nowledge-co nowledge-co deleted a comment from chatgpt-codex-connector Bot May 12, 2026
@wey-gu
Copy link
Copy Markdown
Member

wey-gu commented May 12, 2026

@codex review

Copy link
Copy Markdown

@chatgpt-codex-connector chatgpt-codex-connector Bot left a comment

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit: b7a2b3138d

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +237 to +238
result = api_request("POST", "/threads", body)
return result is not None
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P1 Badge Append to existing thread when create conflicts

The Stop hook calls POST /threads on every run using the same thread_id (proma-{session_id}), but upload_thread treats any non-2xx create response as a hard failure and only retries the same create call. In environments where the thread already exists (a common case after the first successful save), later turns will never be persisted, so automatic capture effectively stops after the initial upload. Other integrations in this repo already handle this by falling back to /threads/{id}/append with deduplication (for example nowledge-mem-opencode-plugin/src/index.ts).

Useful? React with 👍 / 👎.

Comment on lines +64 to +65
if nmem.endswith("uvx") or nmem.endswith("uv"):
cmd = [nmem, "--from", "nmem-cli", "nmem", "--json", "wm", "read"]
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Build uv fallback command correctly for nmem discovery

The fallback path returns either uvx or uv, but command construction assumes both accept --from directly ([nmem, "--from", ...]). --from is a uvx/uv tool run option, not a top-level uv option, so the fallback fails when only uv is installed. In addition, the suffix check misses executables like uvx.exe, causing the script to run uvx.exe --json wm read without the required tool name. This breaks Working Memory bootstrap exactly in the "nmem not on PATH" scenario the fallback is supposed to cover.

Useful? React with 👍 / 👎.

Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

Adds a new Proma host integration package (nowledge-mem-proma-plugin) so Proma agents can use Nowledge Mem via MCP tools plus lifecycle hooks (Stop capture + SessionStart Working Memory injection), and registers Proma in the repo’s integrations.json catalog.

Changes:

  • Introduces the Proma plugin package with hook scripts (save-to-nmem.py, read-working-memory.py), hook config, and user-facing documentation (README/CHANGELOG).
  • Adds Proma-focused skills documentation under skills/ and an e2e/static contract test suite for the plugin layout.
  • Registers Proma in integrations.json with capabilities, install guidance, and listed skills/commands.

Reviewed changes

Copilot reviewed 13 out of 13 changed files in this pull request and generated 11 comments.

Show a summary per file
File Description
tests/plugin_e2e/test_proma_plugin.py Adds static contract tests validating Proma plugin structure and registry entry.
nowledge-mem-proma-plugin/skills/status/SKILL.md Adds “status” skill guidance for Proma usage.
nowledge-mem-proma-plugin/skills/search-memory/SKILL.md Adds “search-memory” skill guidance for Proma usage.
nowledge-mem-proma-plugin/skills/save-thread/SKILL.md Adds “save-thread” skill guidance for Proma usage.
nowledge-mem-proma-plugin/skills/read-working-memory/SKILL.md Adds “read-working-memory” skill guidance for Proma usage.
nowledge-mem-proma-plugin/skills/distill-memory/SKILL.md Adds “distill-memory” skill guidance for Proma usage.
nowledge-mem-proma-plugin/README.md Documents installation, configuration, and troubleshooting for Proma integration.
nowledge-mem-proma-plugin/hooks/save-to-nmem.py Implements Stop-hook thread capture by parsing Proma JSONL and POSTing to /threads.
nowledge-mem-proma-plugin/hooks/read-working-memory.py Implements SessionStart-hook Working Memory retrieval via nmem --json wm read with uvx fallback.
nowledge-mem-proma-plugin/hooks/hooks.json Provides Proma hook configuration referencing the two hook scripts.
nowledge-mem-proma-plugin/CHANGELOG.md Adds initial 0.1.0 release notes for the new plugin.
nowledge-mem-proma-plugin/.claude-plugin/plugin.json Adds plugin manifest metadata for marketplace/discovery.
integrations.json Adds “proma” integration registry entry (capabilities, install steps, skills, commands).

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment on lines +50 to +54
# uvx fallback (per plugin development guide)
uvx = shutil.which("uvx") or shutil.which("uv")
if uvx:
return uvx # caller will prepend "uvx --from nmem-cli nmem" args
return None
Comment on lines +63 to +67
# If _find_nmem returned uvx, prepend the nmem package args
if nmem.endswith("uvx") or nmem.endswith("uv"):
cmd = [nmem, "--from", "nmem-cli", "nmem", "--json", "wm", "read"]
else:
cmd = [nmem, "--json", "wm", "read"]
Comment on lines +251 to +252
log("skip: no API key configured (set NMEM_API_KEY or ~/.nowledge-mem/config.json)")
return 0
Comment on lines +44 to +49
or _nmem_cfg.get("apiUrl")
or "http://127.0.0.1:14242"
).rstrip("/")
API_KEY = (
os.environ.get("NMEM_API_KEY")
or _nmem_cfg.get("apiKey")
Comment thread integrations.json
"Add Nowledge Mem MCP server to ~/.proma/agent-workspaces/default/mcp.json (key: servers)",
"Copy hook scripts to ~/.proma/hooks/",
"Add Stop and SessionStart hooks to ~/.proma/settings.json",
"Copy nmem skill to ~/.proma/agent-workspaces/default/skills/nmem/",
Comment on lines +1 to +4
# Status

Check Nowledge Mem connection status and configuration for Proma.

Comment on lines +1 to +4
# Search Memory

Search your Nowledge Mem knowledge base proactively when past insights would improve the response.

Comment on lines +1 to +4
# Save Thread

Save the current Proma session to Nowledge Mem on explicit user request.

Comment on lines +1 to +4
# Read Working Memory

Read your daily Working Memory briefing to understand current context for Proma sessions.

Comment on lines +1 to +4
# Distill Memory

Save durable insights to Nowledge Mem autonomously. Don't wait to be asked — save proactively when the conversation produces lasting value.

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