asaki14-pi-memory

内容来源:README.md(说明文档) · 原始地址 · 查看安装指南

原始内容

🧠 Asaki Memory Manager

A Cloudflare-native long-term memory layer for AI agents.

Give your coding agents durable memory — preferences, project conventions, decisions, bug fixes, and workflows — without a Docker stack or an external vector database. Just Workers, D1, and Vectorize.

Runtime Framework Language License

Quick start · Architecture · Integrations · API · Configuration · Security


Why

AI coding agents are far more useful when they remember. But most memory stacks mean standing up a vector DB, a queue, and a service to babysit. Asaki Memory Manager is a single-operator, self-hosted alternative that runs entirely on your Cloudflare account: the Worker is the API, D1 is the source of truth, and Vectorize is a recoverable semantic index. No servers to run, no data leaving your account.

Single-operator by design — this is a personal memory layer, not a multi-tenant/team product. Every query is scoped to one user_id.

Features

  • Cloudflare-native — Workers + D1 + Vectorize + Workers AI. Nothing else to host.
  • REST-first, MCP-ready — a small HTTP API, plus the same tool surface served over remote MCP straight from the Worker.
  • Scoped memoryglobal / project / session with strict project & session isolation.
  • Hybrid retrieval — Vectorize semantic search fused with a D1 lexical fallback, so search still works when AI/Vectorize are down.
  • Classifier-first capture — agents submit pre-distilled candidates directly; local background classifiers queue unsupervised candidates for human review. Server-side raw-text extraction is deprecated compatibility only.
  • Human-in-the-loop — unsupervised background classifiers never auto-write; their candidates land in a review queue you approve via a /memory audit.
  • Deterministic dedup guards — exact, subset, and technical-token paraphrase checks run before any LLM decision.
  • Self-improving — classifier regression eval turns audit misses into permanent few-shot cases; the extraction eval remains only for the deprecated compatibility path.
  • First-class agent integrations — a Claude Code plugin, a Pi extension, and a stdio MCP server for Codex.

Architecture

flowchart TD
    A["AI Agent · App · Pi · Claude Code"] -->|"REST / MCP (bearer auth)"| W["Cloudflare Worker<br/>Hono router + auth + rate limit"]
    W --> AI["Workers AI<br/>bge-m3 embeddings · LLM merge/ignore decisions"]
    W --> D1[("D1<br/>source of truth<br/>memories · events · reviews")]
    W --> V[("Vectorize<br/>semantic index + metadata filters")]
    V -. "rebuildable from D1<br/>(index_status=pending on failure)" .-> D1

D1 is the source of truth; Vectorize is an index. If a vector upsert fails, the memory is still stored and marked index_status=pending for later backfill — no write is ever lost to an indexing hiccup.

Quick start

Prerequisites
  • A Cloudflare account with Workers, D1, Vectorize, and Workers AI enabled
  • Node.js 20+ and the wrangler CLI (installed via npm install)
# 1. Install
npm install

# 2. Create Cloudflare resources
npx wrangler login
npx wrangler d1 create asaki-memory-manager
npx wrangler vectorize create asaki-memory-manager --dimensions 1024 --metric cosine
for p in user_id scope project_id session_id kind; do
  npx wrangler vectorize create-metadata-index asaki-memory-manager --propertyName "$p" --type string
done

# 3. Configure Wrangler (then set your D1 database_id in wrangler.jsonc)
cp wrangler.example.jsonc wrangler.jsonc

# 4. Apply migrations
npm run db:migrate:local
npm run db:migrate:remote

# 5. Set the required API auth secret
npx wrangler secret put ADMIN_API_KEY

# 6. Run locally
npm run dev
curl http://127.0.0.1:8787/health

# 7. Deploy
npm run deploy

wrangler.jsonc is gitignored — only wrangler.example.jsonc is tracked. Never commit your real config.

Integrations

Claude Code

Distributed as a self-contained plugin — no manual settings.json hook/MCP editing, no absolute paths (everything resolves via ${CLAUDE_PLUGIN_ROOT}), and the MCP tools come from the remote Worker endpoint, so there's no local process or repo checkout to maintain.

claude plugin marketplace add Asaki14/asaki-memory-manager
claude plugin install asaki-memory@asaki-memory

Set your credentials once in ~/.claude/settings.json:

{
  "env": {
    "ASAKI_MEMORY_API_KEY": "your-admin-api-key",
    "ASAKI_MEMORY_BASE_URL": "https://your-worker.your-subdomain.workers.dev"
  }
}

The plugin injects a real project-history digest at session start, a per-turn memory precheck so the agent decides for itself whether to search, a visible 🧠 Asaki memory … line whenever a memory tool runs, and a /memory slash command (/memory status checks connectivity; any other args run a full audit). A background Stop hook also runs a local classifier: with cloud auto-extract off (the default), it judges each conversation delta against a 6-criteria checklist and writes qualifying candidates itself over plain HTTP — no forced extra turn. Full details: integrations/claude-code/README.md.

Pi

Pi doesn't support remote MCP, so it ships as a self-contained single-file extension, published as a standalone npm package:

pi install npm:@asaki14/pi-memory

On every session_start it renders a compact, transcript-local [Memory] status banner (user, project, memory count, pending reviews, auto-extract/classifier state). It appears with Pi's startup resource information, scrolls away with the conversation, and does not enter LLM context. On agent_end it runs a background classifier that pre-distills one candidate and writes it to the review queue — throttled, and skipping anything that trips the sensitive-text gate.

Common Pi environment variables
export ASAKI_MEMORY_API_URL="https://your-worker.your-subdomain.workers.dev"
export ASAKI_MEMORY_API_KEY="your-admin-api-key"
export ASAKI_MEMORY_USER_ID="alice"
export ASAKI_MEMORY_PROJECT_ID="demo-app"
export ASAKI_MEMORY_AUTO_INJECT="1"
export ASAKI_MEMORY_AUTO_MIN_SCORE="0.67"
export ASAKI_MEMORY_AUTO_EXTRACT="0"
export ASAKI_MEMORY_AUTO_CLASSIFIER="1"
export ASAKI_MEMORY_CLASSIFIER_MODEL="openai-codex/gpt-5.6-luna"
export ASAKI_MEMORY_EXTRACT_MIN_INTERVAL_SECONDS="300"

The classifier model can also be set via classifierModel in ~/.pi/agent/asaki-memory.json. Keep ASAKI_MEMORY_AUTO_EXTRACT=0: server-side /v1/memories/extract is deprecated compatibility behavior and must not be enabled for routine capture.

The extension exposes asaki_memory_search, asaki_memory_add, asaki_memory_list, asaki_memory_update, asaki_memory_delete, asaki_memory_review_create, asaki_memory_review_list, asaki_memory_review_resolve, and the /memory command.

MCP

The same tool surface is served two ways:

  • Remote (recommended)src/mcp.ts serves MCP over HTTP at POST /mcp, guarded by the same ADMIN_API_KEY bearer as /v1/*. Clients like Claude Code need no local process — just the Worker URL + bearer. project_id is passed explicitly (no git root on the Worker); user_id defaults to ASAKI_MCP_DEFAULT_USER_ID (or asaki).
  • Local stdiointegrations/mcp/asaki-memory.ts (bundled to dist/mcp-server.mjs) is a standalone stdio server for clients that need a local process, e.g. Codex. See integrations/codex/README.md.

API reference

All /v1/* endpoints require a bearer token. If ADMIN_API_KEY is unset, every /v1/* route returns 503.

Authorization: Bearer <ADMIN_API_KEY>
POST /v1/memories — create a memory
curl -X POST http://127.0.0.1:8787/v1/memories \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{
    "content": "Use Cloudflare Workers, D1, and Vectorize for this project.",
    "user_id": "alice",
    "scope": "project",
    "project_id": "demo-app",
    "kind": "decision",
    "importance": 0.8,
    "confidence": 0.95
  }'
POST /v1/memories/search — semantic + lexical search
curl -X POST http://127.0.0.1:8787/v1/memories/search \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{
    "query": "What stack should this project use?",
    "user_id": "alice",
    "project_id": "demo-app",
    "top_k": 5
  }'

Defaults to global + current project + current session when project_id / session_id are provided. Explicit scope=project requires project_id; explicit scope=session requires session_id. Optional min_score (0–1) drops low-scoring results.

POST /v1/memories/list — list memories
curl -X POST http://127.0.0.1:8787/v1/memories/list \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{
    "user_id": "alice",
    "project_id": "demo-app",
    "status": "active",
    "limit": 50,
    "offset": 0
  }'

Omit scope to list global + current project + current session. Use status=all to include archived and deleted memories.

GET /v1/memories/:id · PATCH /v1/memories/:id — get / update
# Get
curl "http://127.0.0.1:8787/v1/memories/<memory-id>?user_id=alice" \
  -H "Authorization: Bearer $ADMIN_API_KEY"

# Update
curl -X PATCH http://127.0.0.1:8787/v1/memories/<memory-id> \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{
    "user_id": "alice",
    "content": "Use Cloudflare Workers, D1, Vectorize, and Workers AI for this project.",
    "importance": 0.85
  }'
DELETE /v1/memories/:id · POST /v1/memories/:id/purge — delete / purge
# Soft delete: row marked status=deleted, content retained & recoverable
curl -X DELETE http://127.0.0.1:8787/v1/memories/<memory-id> \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{"user_id":"alice"}'

# Purge: irreversible — wipes content, removes Vectorize entry, deletes all
# prior memory_events, logs one content-free purge event
curl -X POST http://127.0.0.1:8787/v1/memories/<memory-id>/purge \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{"user_id":"alice","reason":"accidentally stored a credential"}'

Use purge, not delete, for content that should never have been stored.

POST /v1/memories/candidates — process candidates (dedupe/merge pipeline)
curl -X POST http://127.0.0.1:8787/v1/memories/candidates \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{
    "user_id": "alice",
    "project_id": "demo-app",
    "candidates": [
      {
        "content": "The demo-app project uses Cloudflare Workers and D1.",
        "scope": "project",
        "kind": "decision",
        "importance": 0.8,
        "confidence": 0.9
      }
    ]
  }'

Agents submit concise candidates from their own context. Local background classifiers (source: "pi:agent-end-classifier" or "claude-code:stop-classifier") are the active/default automated source and always land in reviews, never decisions. The legacy /v1/memories/extract endpoint remains for backward compatibility but is deprecated and must not receive routine/full-transcript capture.

POST /v1/memories/reviews · .../reviews/list · .../reviews/:id/resolve — review queue
# Enqueue a high-risk candidate for review
curl -X POST http://127.0.0.1:8787/v1/memories/reviews \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{
    "user_id": "alice",
    "project_id": "demo-app",
    "candidates": [
      { "content": "Use review queue for high-risk global rules.",
        "scope": "project", "kind": "workflow",
        "importance": 0.6, "confidence": 0.8 }
    ]
  }'

# List pending reviews (add "include_suggestions": true for duplicate hints)
curl -X POST http://127.0.0.1:8787/v1/memories/reviews/list \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{"user_id":"alice","project_id":"demo-app","status":"pending"}'

# Resolve a review
curl -X POST http://127.0.0.1:8787/v1/memories/reviews/<review-id>/resolve \
  -H 'Content-Type: application/json' \
  -H "Authorization: Bearer $ADMIN_API_KEY" \
  -d '{"user_id":"alice","action":"add","reason":"approved"}'

Resolve actions: add, merge, update, delete, ignore. merge/update/delete require memory_id.

Configuration

Variable Default Purpose
ADMIN_API_KEY unset Required bearer auth for /v1/* and /mcp; unset returns 503. Set as a Wrangler secret.
EMBEDDING_MODEL @cf/baai/bge-m3 Workers AI embedding model (1024-dim).
MEMORY_LLM_MODEL @cf/meta/llama-3.1-8b-instruct-fp8 Workers AI chat model for candidate merge/ignore decisions.

Data model

Table Purpose
memories Memory body, scope, project/session metadata, kind, importance, confidence, status, index state.
memory_events Append-only operational event log.
memory_reviews Pending and resolved candidate review queue.

Memory kinds: preference · rule · fact · decision · task_learning · bug_fix · workflow

Security

  • Never commit .env, .dev.vars, private keys, tokens, or generated wrangler.jsonc. Use wrangler.example.jsonc as the public template and store ADMIN_API_KEY via npx wrangler secret put.
  • Every query is filtered by user_id. Project/session memories are only visible when the matching project_id / session_id is provided.
  • Memory content is user/project context only — it never overrides system or developer safety instructions.
  • The server rejects (400) any content/text that looks like a secret or credential (API keys, Bearer tokens, private keys, credential URLs) before it reaches Workers AI or D1/Vectorize — see src/utils/sensitiveContent.ts. If one slips through, purge it.
  • AI/Vectorize-touching routes (search, candidates, extract, POST /v1/memories, PATCH /v1/memories/:id) are rate-limited per user_id (default 30 req/min → 429); tune in wrangler.jsonc.
  • Unexpected internal errors return a generic 500 — only deliberate UserFacingError messages are ever forwarded to the client.

Development

npm run typecheck        # tsc --noEmit
npm run eval:candidates  # offline dedup heuristics
npm run eval:extraction  # deprecated server-extraction compatibility path; needs a live Worker
npm run eval:classifier  # active local classifier regression suite
npm run smoke:management  # management API smoke test
npm run db:migrate:local
npm run dev

Maintenance scripts — shadow-run:extraction, backfill:index, prune:stale — are documented in AGENTS.md along with when to run each.

Roadmap & License

Priorities and deferred work live in ROADMAP.md. Licensed under MIT.