v0.2.21
moorcheh-ai/memantov0.2.21Sep 9, 2026by het0814
AI Summary
MEMANTO v0.2.21 introduces a client-identity layer to track which AI tools interact with the system, accompanied by an append-only activity log. The UI gains a live context mesh and session timelines, while CLI commands like `recall` and `answer` receive a `--tool` flag for explicit attribution. Additionally, the project moves to PyPI Trusted Publishing and updates its Python classifier.
Key Highlights
- Client identity and activity tracking system for AI tools.
- Live context mesh and session timelines in the Connections page.
- Append-only activity log for all memory operations.
- New `--tool` flag for explicit tool attribution in CLI reads.
- Migration to PyPI Trusted Publishing.
New Features
- Tool identity resolution via environment markers, MCP handshake, or headers.
- ActivityService for append-only JSON logging of memory operations.
- Session and liveness API endpoints (`GET /api/ui/sessions`).
- Live context mesh visualization in the UI with live node indicators.
- MCP tool calls attributed to handshake client.
- Trimmed sdist packaging excluding assets and integrations.
- Python 3.13 support and Production/Stable classifier.
Full Release Notes
# Release Notes for v0.2.21
This release makes MEMANTO aware of *which* AI tool is talking to it. A new client-identity layer and append-only activity log record the tool and MEMANTO session behind every remember, recall, and answer, and the Connections page grows a live context mesh and session timeline built on top of them. Alongside it, `recall`/`answer` gain a `--tool` flag so agents can name themselves on reads, the MCP server attributes tool calls to its handshake client, connect templates embed each agent's own slug, and packaging moves to PyPI Trusted Publishing with a trimmed sdist.
## New Features
- **Tool identity and activity tracking** (`memanto/app/utils/client_identity.py`, `memanto/app/services/activity_service.py`)
- New `client_identity` module resolves the calling tool from, in order: `MEMANTO_CLIENT` / `X-Memanto-Client`, an MCP `initialize` handshake's `clientInfo`, or environment markers specific to a single tool (`CLAUDECODE`, `CURSOR_TRACE_ID`, `CODEX_HOME`, `WINDSURF_HOME`, `GEMINI_CLI`, `GOOSE_PROVIDER`, `OPENCODE`, `CLINE_SESSION_ID`, `CONTINUE_GLOBAL_DIR`, `PI_AGENT`, `ANTIGRAVITY_HOME`). Detection is conservative — an unidentified caller stays `unknown` rather than being guessed at.
- Free-text client names are folded onto registry slugs via an alias table, so a Cursor MCP write and a Cursor CLI write land on the same connection instead of two lookalike rows.
- New `ActivityService` writes one `O_APPEND` JSON line per memory operation (`remember`, `recall`, `answer`) recording tool, agent, MEMANTO session, and count. Logging is best-effort and never raises — a telemetry line is never worth failing a durable write over. Files older than `RETENTION_DAYS` (30) are pruned once per process.
- Liveness is derived on read: a tool that touched memory within `LIVE_WINDOW_SECONDS` (300) counts as connected now.
- Identity is bound per-request via a `ContextVar` (not a module global) so concurrent API requests cannot read each other's attribution.
- **Session and liveness API** (`memanto/app/ui/routes/ui_router.py`, `memanto/app/main.py`)
- `GET /api/ui/sessions` returns MEMANTO sessions with the tools that took part, per-tool liveness, and a `live_count`. Complements `/api/ui/connections`, which reports where MEMANTO is *installed*; this reports what has actually been running.
- `GET /api/ui/sessions/{session_id}` returns one session's summary plus its full event timeline, `404`-ing on an unknown id.
- Both clamp the `days` window to `ACTIVITY_MAX_DAYS` (30), matching the log's own retention.
- New `attribute_calling_tool` HTTP middleware binds `X-Memanto-Client` (and optional `X-Memanto-Project`) to the request. An anonymous HTTP call is bound to `UNKNOWN` rather than falling through to environment detection — otherwise an editor that started `memanto server` would be credited with every request it never made.
- Both endpoints stay local-only behind `_require_local`.
- **Live context mesh and session list in the UI** (`memanto/app/ui/static/index.html`)
- The Connections page now renders a live context mesh: a MEMANTO hub with one node per tool active in the last 7 days, live nodes and edges highlighted, and a live-count readout. The hub animates only when a tool is genuinely live, and respects `prefers-reduced-motion`.
- A collapsible **Sessions (last 7 days)** list shows each MEMANTO session, its status, and the tools that took part, expanding into a per-session event timeline.
- Live badges decorate the existing connection cards, and the mesh polls on an interval so a stale page stops claiming a tool is connected.
- **`--tool` flag on `recall` and `answer`** (`memanto/cli/commands/memory.py`)
- Reads carry no `--source`, so a new hidden `--tool` option lets an agent name itself exactly instead of relying on environment sniffing — the only way tools that leave no distinctive marker can be attributed at all. Hidden from `--help` because a human running `memanto` by hand has nothing to declare.
- `remember --source` now defaults to the detected calling tool instead of the hardcoded `"user"`; an explicit `--source` always wins, and a bare terminal still records `user`.
- Sources that name a person (`user`, `agent`, `human`) fall through to environment detection rather than putting "user" on the connected-tools diagram.
## Improvements
- **MCP tool calls are attributed to the handshake client** (`integrations/mcp/memanto_mcp/tools.py`)
- New `_attributed(ctx)` context manager binds the MCP `clientInfo` name for the duration of a tool call. The MCP server runs as its own process, so its environment says nothing about the driving editor — this is the only way a recall through MCP gets credited to Cursor rather than to an anonymous caller.
- `recall`, `recall_recent`, `recall_as_of`, `recall_changed_since`, and `answer` now accept `ctx`; `remember` and `batch_remember` were rewrapped to run their whole body under the attribution scope.
- **Activity logging wired through every read and write path** (`memanto/app/services/memory_read_service.py`, `memanto/app/services/memory_write_service.py`, `memanto/cli/client/direct_client.py`, `memanto/cli/client/sdk_client.py`, `memanto/app/routes/auth_deps.py`)
- Semantic recall, `--recent`, `--as-of`, `--changed-since`, `answer`, single `remember`, and `batch_remember` all emit an activity event.
- `get_current_session` and the CLI clients' `_get_validated_session_for_agent` bind the session id, since the memory services below them only ever receive an `agent_id`.
- The CLI `answer` RAG path calls Moorcheh directly rather than through `MemoryReadService`, so it logs its own event — otherwise `answer` would be the one memory operation leaving no trace.
- Generated instructions and `SKILL.md` now interpolate the connected agent's real slug into `--source "<slug>"` and `--tool "<slug>"` examples, instead of a generic `<your_agent_name>` placeholder. `_install_skill` passes `agent.name` through to `get_skill_content`.
- Recall/answer examples and the recall trigger matrix were updated to always pass `--tool`, with a new anti-pattern entry explaining why reads need it.
- **Packaging and publishing** (`pyproject.toml`, `.github/workflows/publish.yml`)
- PyPI publishing moved to Trusted Publishing: `PYPI_API_TOKEN` is gone, `id-token: write` added, and the workflow's OIDC identity is what PyPI authenticates — the action attaches PEP 740 provenance attestations by default.
- New `[tool.hatch.build.targets.sdist]` include list trims the sdist to `memanto/`, `tests/`, and build metadata; `assets/`, `examples/`, `integrations/`, `docs/`, and `sdks/` (whose demo GIFs and architecture PNGs dominated the archive) are excluded.
- Classifier bumped from `3 - Alpha` to `5 - Production/Stable`, Python 3.13 added, and project URLs repointed to `memanto.ai` / `docs.memanto.ai`.
## Tests
- `tests/test_tool_sessions.py` — new 500-line suite covering environment detection precedence, alias normalization, append-only event writing, failure-swallowing on broken storage, session grouping, liveness expiry, quiet-but-unexpired and zero-activity sessions, dead-session flooding, torn-line recovery, session timelines, HTTP header attribution, anonymous-caller safety, and the `--tool` flag on `recall`/`answer`.
- `tests/test_cli.py` — `remember` attributes the write to the calling tool, and an explicit `--source` overrides detection.
- `tests/test_connect_engine.py` — each connected agent gets its own slug in both its instructions and its installed `SKILL.md`.
- `tests/test_remaining_ui_auth.py` — both new session endpoints are rejected from remote callers.
- `tests/conftest.py` — new autouse fixture resets the bound client identity and session between tests, so one test's `--tool` cannot decide the attribution of every test after it.
## Full Changelog
Full Changelog: https://github.com/moorcheh-ai/memanto/compare/v0.2.20...v0.2.21