Skip to content

v0.2.18

Latest

Choose a tag to compare

@het0814 het0814 released this 28 Aug 17:46
· 3 commits to main since this release
3bfde8e

Release Notes for v0.2.18

This release adds a Pi coding-agent integration to memanto connect, hardens local management endpoints against cross-site token theft and DNS rebinding, brings the OKF export bundle up to the v0.2 spec, and fixes a Windows UnicodeEncodeError that killed the CLI whenever its output was redirected or captured by an agent harness.

New Features

  • Pi (coding agent) integration (memanto/cli/commands/connect.py, memanto/cli/connect/agent_registry.py, memanto/cli/connect/engine.py, memanto/cli/connect/templates.py)
    • New memanto connect pi command with the same --project-dir/-p and --global/-g flags as the other agents.
    • Registers a PI agent definition: AGENTS.md instructions, skills at .pi/skills (project) or ~/.pi/agent/skills (global).
    • Adds a new code extension artifact type to the connect engine (extension_file / extension_global_dir / extension_local_dir on AgentDef, plus _install_extension / _remove_extension), deploying a self-contained memanto-sync.ts into ~/.pi/agent/extensions/ or .pi/extensions/.
    • The extension runs memanto memory sync --project-dir <cwd> fire-and-forget only on a fresh session start (reason === "startup", not /resume, /fork, or /reload), swallowing errors so it can never block Pi startup; it is a no-op on session shutdown.
    • Success notification fires only on exit code 0, so a failed sync no longer reports "memory synced".
    • Extension spawn drops the platform-dependent shell option; extension removal is guarded at the call site the same way hooks and permissions already are.
    • Pi appears in the Connections UI with its official mark (memanto/app/ui/static/index.html).

Improvements

  • OKF export conforms to the v0.2 spec (memanto/app/services/okf_export_service.py, memanto/cli/migrate/mappers.py)
    • Root index now declares okf_version: "0.2"; per-section index.md files drop their non-conforming type/title/timestamp frontmatter.
    • Memory frontmatter replaces the bare timestamp field with a structured generated: {by, at} block, normalizing by into a qualified source (human:/process: prefix or a namespaced a/b form).
    • Context documents copied into the bundle without frontmatter now get a YAML-serialized type: Context Document / title header instead of being copied verbatim; the metrics overview gains type: Metrics Overview frontmatter.
    • Import (map_okf) reads extra.generated.at first and falls back to the legacy top-level timestamp, so v0.1 bundles still import with correct created_at.

Bug Fixes

  • CLI crashed with UnicodeEncodeError when output was redirected on Windows (memanto/cli/__init__.py)
    • Rich emits box-drawing characters, bullets and braille spinner frames. With stdout captured on Windows, Python encoded them with the locale code page (cp1252), killing commands mid-run: UnicodeEncodeError: 'charmap' codec can't encode character '⠹'. This hit shell pipelines, > file, CI logs, and agent harnesses that always pipe stdout — affecting recall, status, forget and the other 23 console.status() sites.
    • Redirected streams are now switched to UTF-8 once at CLI package import, before any Rich Console is constructed, so every call site is covered. isatty() is deliberately not used as the signal: on Windows NUL reports itself as a character device, so command > NUL looks like a tty while still encoding as cp1252. Streams already reporting UTF-8 are left untouched, and a failed reconfigure() can never stop the CLI from starting.
  • Hermes plugin returned 403 on profile startup (integrations/hermes-agents/hermes_memanto/provider.py)
    • Session tokens are now persisted per profile in <hermes_home>/profiles/<identity>/.memanto_session_token (created 0o600) and reloaded on startup, so a restarted profile no longer starts unauthenticated.
    • remember, recall and answer route through _call_with_auth_retry, which detects refreshable auth failures (AuthenticationError, AuthorizationError, SessionExpiredError, InvalidSessionTokenError), re-activates the agent, and retries once; refreshes are throttled to one every 5 seconds.
    • The client lock became a threading.RLock to prevent deadlock when a refresh re-enters ensure_session(), and the profile directory name is sanitized via _sanitize_agent_id.

Security

  • Cross-site requests can no longer inherit loopback trust (memanto/app/routes/auth_deps.py, memanto/app/ui/routes/ui_router.py)
    • require_management_access previously granted the server key to any request from a loopback client address. A page on any website could therefore drive the local management API from the user's browser — including activating an agent and reading back its session_token.
    • Loopback trust now additionally requires a loopback Host header and a non-cross-site browser request: the Origin must resolve to localhost/a loopback address (any port), and absent an Origin, Sec-Fetch-Site: cross-site/same-site is rejected.
    • The Host check closes DNS rebinding, where an attacker-controlled hostname resolving to 127.0.0.1 made a remote-origin request look local.
    • UI management endpoints apply the same _is_cross_site_browser_request guard in _require_local, returning 403 instead of serving the request.

Tests

  • tests/test_cli_stream_encoding.py — new suite covering the cp1252→UTF-8 switch, the NUL-as-tty case, UTF-8 alias spellings being left alone, streams lacking reconfigure, reconfigure failures never breaking startup, and Rich glyphs surviving a cp1252 stream.
  • tests/test_api.py — cross-site loopback cannot create or activate an agent (and no session_token leaks into the response), loopback and cross-port loopback origins keep local management access, DNS-rebinding Host headers are rejected.
  • tests/test_ui_auth.py — loopback cross-site Origin and Sec-Fetch-Site requests rejected; loopback origin accepted; remote origin rejected.
  • tests/test_connect_engine.py / tests/test_connect_detection.py — Pi install deploys instructions, skill and extension; install is idempotent; remove deletes the extension; global paths match the ~/.pi/agent/ layout; agents without an extension deploy none; Pi detection keys off its own skill dir since it shares AGENTS.md with codex/opencode.
  • integrations/hermes-agents/tests/test_provider.py — token persistence across restarts and auto-refresh on session expiration.
  • tests/test_unit.py — Pi instruction-file path resolution (global and project-local); tests/test_e2e.py now uses a localhost:8000 base URL so requests satisfy the new Host check.

Full Changelog

Full Changelog: v0.2.17...v0.2.18