| title | mnemos — Agent context |
|---|
mnemos is shared, cloud-persistent memory for coding agents. The core system is a Go REST server backed by TiDB/MySQL, plus four agent integrations, a standalone CLI, and a small Astro site.
mem9-nodeis a sibling repository at../mem9-node. It is not a directory inside this repo.dashboard/appin this repo is the frontend half of the dashboard product. In day-to-day discussion, "the dashboard backend" usually refers to code inmem9-node, especiallyapps/apiandapps/worker.dashboard/app/src/api/analysis-client.tscallsmem9-nodeendpoints forv1/analysis-jobs,v1/deep-analysis/*, and taxonomy/deep-analysis workflows.mem9-node/apps/api/src/mem9-source.service.tsdepends on this repo's Go API as the mem9 source of truth. ItsMEM9_SOURCE_API_BASE_URLdefaults tohttp://127.0.0.1:8080/v1alpha2/mem9s.dashboard/app/src/api/provider-http.tsstill sends the dashboard's standard/your-memory/api/...data requests to this repo's Go server (/v1alpha2/mem9s/...) usingX-API-KeyandX-Mnemo-Agent-Id.- When a task touches dashboard UI and backend behavior together, inspect both repos before assuming the implementation belongs only under
server/in this repo.
| Path | Role |
|---|---|
server/ |
Go API server, business logic, TiDB SQL, tenant provisioning, runtime usage |
cli/ |
Standalone Go CLI for exercising mnemo-server endpoints |
dashboard/app/ |
React dashboard SPA; frontend half of the dashboard product |
openclaw-plugin/ |
OpenClaw memory plugin (kind: "memory") |
opencode-plugin/ |
OpenCode plugin (@mem9/opencode) |
claude-plugin/ |
Claude Code plugin (hooks + skills) |
codex-plugin/ |
Codex plugin (hooks + $mem9:* skills) |
docs/design/ |
Architecture/proposal notes and design drafts |
site/ |
Astro static site — deployed to Netlify from main branch |
e2e/ |
Live end-to-end scripts against a running server |
benchmark/MR-NIAH/ |
Benchmark harness for OpenClaw memory evaluation |
# Go server build / verify
make build
make vet
make test
make test-integration
MNEMO_DSN="user:pass@tcp(host:4000)/db?parseTime=true" make dev
# Single Go test
cd server && go test -race -count=1 -run TestFunctionName ./internal/service/
# TypeScript plugin verification
cd openclaw-plugin && npm test
cd openclaw-plugin && npm run typecheck
cd opencode-plugin && pnpm test
cd opencode-plugin && pnpm run typecheck
pnpm --dir codex-plugin test
pnpm --dir codex-plugin typecheck
# Site dev/build
cd site && npm run dev
cd site && npm run build
# CLI build
cd cli && go build -o mnemo .
# Run server locally
cd server && MNEMO_DSN="user:pass@tcp(host:4000)/db?parseTime=true" go run ./cmd/mnemo-server
# Run server locally with auto-restart on server code changes
MNEMO_DSN="user:pass@tcp(host:4000)/db?parseTime=true" make dev- Architecture is strict
handler -> service -> repository; plugins always call the HTTP API. - No ORM. Server SQL is raw
database/sqlwith parameter placeholders only. embed.New()andllm.New()may returnnil; callers must branch correctly.- Vector and keyword search each fetch
limit * 3before RRF merge. INSERT ... ON DUPLICATE KEY UPDATEis the expected upsert pattern.- Atomic version bump happens in SQL:
SET version = version + 1. X-Mnemo-Agent-Idis the per-agent identity header for memory requests.- Legacy API metering uses
MNEMO_METERING_*; runtime usage quota and console metering useMNEMO_RUNTIME_USAGE_*and do not useMNEMO_METERING_URL. - Always use
maketargets for building and Docker image operations — never construct rawgo buildordocker buildcommands from scratch. Usemake build-linuxfor the server binary andREGISTRY=<ecr> COMMIT=<tag> make dockerfor images.
- Format with
gofmtonly. - Imports use three groups: stdlib, external, internal.
- Use
PascalCasefor exported names,camelCasefor unexported names. - Acronyms stay all-caps inside identifiers:
tenantID,agentID. - Sentinel errors live in
server/internal/domain/errors.go; compare witherrors.Is(). - Wrap errors with
fmt.Errorf("context: %w", err). - Validation errors use
&domain.ValidationError{Field: ..., Message: ...}. - HTTP/domain error mapping stays centralized in
server/internal/handler/handler.go.
- ESM only:
"type": "module",module: "NodeNext"or local package equivalent. - Always use
.json local imports when the package uses NodeNext. - Use
import typefor type-only imports. - Formatting is consistent: double quotes, semicolons, trailing commas in multi-line literals.
- Public methods use explicit return types.
- Nullable is
T | null; optional isfield?: T. - No
any. - Tool/error strings use
err instanceof Error ? err.message : String(err).
- Hook scripts start with
set -euo pipefail. - Use Python for JSON/url-encoding helpers instead of
jqin hook logic. curlcalls use explicit timeouts.
- Tags are JSON arrays; store
[], neverNULL. - Filter tags with
JSON_CONTAINS. - Every vector search must include
embedding IS NOT NULL. VEC_COSINE_DISTANCE(...)must match inSELECTandORDER BYbyte-for-byte.- When
autoModel != "", do not write theembeddingcolumn; it is generated. MNEMO_EMBED_AUTO_MODELandMNEMO_EMBED_API_KEYrepresent different embedding modes.
| Task | File |
|---|---|
| Add/change route | server/internal/handler/handler.go |
| Memory CRUD / search | server/internal/service/memory.go |
| Ingest pipeline | server/internal/service/ingest.go |
| TiDB SQL | server/internal/repository/tidb/memory.go |
| Tenant provisioning | server/internal/service/tenant.go |
| Runtime usage quota | server/internal/runtimeusage/ |
| Metering writer | server/internal/metering/ |
| CLI command wiring | cli/main.go |
| Dashboard frontend | dashboard/app/ |
| Dashboard backend (sibling repo) | ../mem9-node/apps/api/ |
| Dashboard worker (sibling repo) | ../mem9-node/apps/worker/ |
| Claude hooks | claude-plugin/hooks/ |
| Codex hooks and skills | codex-plugin/ |
| Architecture notes | docs/design/ |
| OpenCode wiring | opencode-plugin/src/index.ts |
| OpenClaw wiring | openclaw-plugin/index.ts |
| Site copy/content | site/src/content/site.ts |
| Production SKILL.md | site/public/SKILL.md |
/site/ is the deployment directory for the mem9.ai static website.
It is hosted on Netlify and automatically deployed from the main branch.
| File | Purpose |
|---|---|
site/public/SKILL.md |
Production SKILL.md — served at https://mem9.ai/SKILL.md |
When updating the SKILL.md that agents fetch, edit only these two files:
site/public/SKILL.md— production, changes go live within seconds after merging tomain
Do not edit any other copy (e.g. clawhub-skill/mem9/SKILL.md has been removed).
Do not manually sync to clawhub — Netlify handles publishing automatically.
Use the local file when you work in these areas:
server/AGENTS.mdserver/internal/handler/AGENTS.mdserver/internal/metering/AGENTS.mdserver/internal/service/AGENTS.mdserver/internal/repository/tidb/AGENTS.mdserver/internal/tenant/AGENTS.mdcli/AGENTS.mdopenclaw-plugin/AGENTS.mdopencode-plugin/AGENTS.mdclaude-plugin/AGENTS.mdcodex-plugin/AGENTS.mdsite/AGENTS.mddashboard/app/AGENTS.mde2e/AGENTS.mdbenchmark/MR-NIAH/AGENTS.md
Validate this map after editing:
python3 -c 'from pathlib import Path; import re, subprocess; text = Path("AGENTS.md").read_text(); paths = re.findall(r"`([^`]+/AGENTS\.md)`", text); tracked = set(subprocess.check_output(["git", "ls-files", "*AGENTS.md"], text=True).splitlines()); missing = [p for p in paths if p not in tracked]; print("\n".join(missing)); raise SystemExit(1 if missing else 0)'Prefer gh CLI to read GitHub content (issues, PRs, file contents, comments). Fall back
to curl or webfetch only when gh is unavailable or does not work. Examples:
# View a PR
gh pr view <number>
# Read a file from a specific ref
gh api repos/{owner}/{repo}/contents/{path}?ref={branch} --jq '.content' | base64 -d
# List issues or PR comments
gh issue view <number> --comments
gh pr view <number> --commentsWhen the user names a specific PR and says run the review loop, use the loop to resolve review comments, or equivalent wording, treat that as approval for a
bounded review-comment resolution loop on that PR.
This approval covers only actions required by the loop:
- Commit changes that directly address review feedback.
- Push those commits to the PR branch.
- Post GitHub review-thread replies.
- Resolve fixed GitHub review threads.
- Post the configured GitHub reviewer trigger comment, such as
@codex review. - Repeat the same sequence until the loop reaches its configured stop condition.
This approval does not cover force-pushes, rebases, merges, creating new PRs, deployments, deleting files outside the working tree, or unrelated code changes. Stop and ask before those actions. Stop and ask if a review comment requires a product or architecture decision that is not clearly implied by the PR.
- No
.cursor/rules/,.cursorrules, or.github/copilot-instructions.mdwere found. - No repo-wide TypeScript test runner is configured; plugin tests are package-local.
- No repo-wide TypeScript lint config exists, and the plugin packages do not expose
lintscripts.