Skip to content
Merged
2 changes: 2 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -81,6 +81,8 @@ jobs:
"mcp_server/__init__.py",
"mcp_server/cli.py",
"mcp_server/import_cli.py",
"mcp_server/server.py",
"mcp_server/tools.py",
]
missing = [r for r in required if r not in names]
assert not missing, f"{whl} is missing: {missing}"
Expand Down
1 change: 1 addition & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,7 @@ When running via Docker or as a standalone MCP server, you can pass the followin
* `HEXUS_DB_PASS` - Used by our `compose.yml` to set the Postgres password (and the default DSN's password).
* `HEXUS_TRANSPORT` - MCP transport: `"stdio"` (default) or `"http"`.
* `HEXUS_AGENT_IDENTITY` - Default agent identity for tool calls that don't supply one (default: `"default"`).
* `HEXUS_MEMORY_ISOLATION` - Multi-agent read isolation: `"shared"` (default) lets any agent recall/search/read every agent's memory — a single shared knowledge base for a trusted fleet; `"strict"` scopes reads to the calling agent's own identity. Cross-agent **mutations** (confirm/reject/remove/forget/summarize by id) are always scoped to the caller in **both** modes. On the HTTP transport the caller's identity is taken server-side from the `X-Hermes-Session-Key` header and overrides any client-supplied `agent_identity`, so an authenticated client cannot act as another agent.
* `HEXUS_EMBED_EAGER_LOAD` - Set to `"1"` to pre-load the local embedding model at startup (saves ~1-2s on first use).
* `HEXUS_EMBED_DEVICE` - Torch device for the embedder (default: `"cpu"`).
* `HEXUS_WEBHOOK_URL` / `HEXUS_WEBHOOK_SECRET` - (Optional) POST a signed webhook on memory writes.
Expand Down
7 changes: 4 additions & 3 deletions hexus/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -1649,7 +1649,7 @@ def _handle_confirm_memory(self, args: Dict[str, Any]) -> str:
return tool_error("id must be an integer")

try:
success = self._store.confirm_entry(entry_id)
success = self._store.confirm_entry(entry_id, self._agent_identity)
return json.dumps({"id": entry_id, "success": success})
except Exception as exc:
return json.dumps({"error": f"db: {exc}"})
Expand All @@ -1668,7 +1668,7 @@ def _handle_reject_memory(self, args: Dict[str, Any]) -> str:
return tool_error("id must be an integer")

try:
success = self._store.reject_entry(entry_id)
success = self._store.reject_entry(entry_id, self._agent_identity)
return json.dumps({"id": entry_id, "success": success})
except Exception as exc:
return json.dumps({"error": f"db: {exc}"})
Expand All @@ -1691,6 +1691,7 @@ def _handle_summarize_session(self, args: Dict[str, Any]) -> str:
res = self._store.summarize_session(
session_id=session_id,
limit=limit,
agent_identity=self._agent_identity,
)
return json.dumps(res)
except Exception as exc:
Expand All @@ -1710,7 +1711,7 @@ def _handle_headroom_retrieve(self, args: Dict[str, Any]) -> str:
return tool_error("id must be an integer")

try:
content = self._store.fetch_full(entry_id)
content = self._store.fetch_full(entry_id, self._agent_identity)
if content is None:
return json.dumps({"id": entry_id, "found": False, "content": None})
return json.dumps({"id": entry_id, "found": True, "content": content})
Expand Down
Loading
Loading