| 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 three agent integrations, a standalone CLI, and a small Astro site.
| Path | Role |
|---|---|
server/ |
Go API server, business logic, TiDB SQL, tenant provisioning |
cli/ |
Standalone Go CLI for exercising mnemo-server endpoints |
openclaw-plugin/ |
OpenClaw memory plugin (kind: "memory") |
opencode-plugin/ |
OpenCode plugin (@mem9/opencode) |
claude-plugin/ |
Claude Code plugin (hooks + 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 |
k8s/ |
Deployment and gateway manifests |
benchmark/MR-NIAH/ |
Benchmark harness for OpenClaw memory evaluation |
# Go server build / verify
make build
make vet
make test
make test-integration
# Single Go test
cd server && go test -race -count=1 -run TestFunctionName ./internal/service/
# TypeScript verification
cd openclaw-plugin && npm run typecheck
cd opencode-plugin && npm run 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- 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.- 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 |
| CLI command wiring | cli/main.go |
| Claude hooks | claude-plugin/hooks/ |
| 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 |
| Beta SKILL.md | site/public/beta/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 |
site/public/beta/SKILL.md |
Beta SKILL.md — served at https://mem9.ai/beta/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 tomainsite/public/beta/SKILL.md— beta, same deployment pipeline
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/service/AGENTS.mdserver/internal/repository/tidb/AGENTS.mdserver/internal/tenant/AGENTS.mdcli/AGENTS.mdopenclaw-plugin/AGENTS.mdopencode-plugin/AGENTS.mdclaude-plugin/AGENTS.mdsite/AGENTS.mde2e/AGENTS.mdk8s/AGENTS.mdbenchmark/MR-NIAH/AGENTS.md
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> --comments- No
.cursor/rules/,.cursorrules, or.github/copilot-instructions.mdwere found. - No TypeScript test runner is configured for the plugin packages.
- No repo-wide lint config exists for the TypeScript code.