basemouse/basemouse-core
📇 ☁️ 🏠 - Shared, versioned memory for your agents across Claude Code, Cursor, Kiro and Grok. One MCP server, sourced answers, full history. Remote Streamable HTTP; anonymous browses a public demo corpus. Tools: search, getcontextpack, upsertdocument. https://basemouse.com/mcp
Quick Install
{
"mcpServers": {
"basemouse-basemouse-core": {
"command": "npx",
"args": [
"-y",
"basemouse-basemouse-core"
]
}
}
}Using an AI coding agent (Claude Code, Cursor, etc.)? Copy a ready-made prompt that tells it to fetch the setup instructions and install this server for you.
Documentation Overview
BaseMouse
Domain: basemouse.com
GitHub org: https://github.com/basemouse
Status: live (paid plans)
Version: v0.3
BaseMouse is an AI-native document/notes repository for workspaces and agents: a local-first knowledge base that exports structured, versioned context packs agents can actually use.
What's in this repo
This is a small zero-dependency Node.js app:
- durable in-repo seed repository in
data/seed/*.json /api/repositoryendpoint with count + normalized documents/api/search?q=...search endpoint with scores and matched terms/api/context-pack?q=...&limit=...agent-readybasemouse.context_pack.v1export- Faceted retrieval filters
typeandtagon both/api/searchand/api/context-pack retrieval=lexical|hybridmode on both endpoints (lexical is the default, fully back-compatible).hybridblends three signals —lexicalterm overlap, one-hopgraphexpansion along document links, and a localvectorsimilarity — and annotates every result with a per-signalretrievalblock explaining why it surfaced. The vector signal uses local, offline hashed-feature embeddings built in Node (no external vector DB, no paid embedding API, no network); it is honest token-overlap-in-a-dense-space, not a semantic model. Disable it withBASEMOUSE_VECTOR_RETRIEVAL=off(graph+lexical hybrid still works).- context-pack citations, provenance, document versions, checksums, relevance, truncation, and agent instructions
- graph-aware relationships: each entry carries its outbound
linksand a resolvedrelatedlist, plus a pack-levelrelationshipsedge list, so agents can follow how documents connect - safer static file serving with path containment, nosniff headers, malformed URL handling, and API validation/limits
- web UI for search, context-pack generation, raw JSON inspection, copy, and download
- public Agent Governance Demo page at
/agent-governance-demo.html, showing the synthetic governance corpus, sample auditor/operator queries, and the lexical vs hybrid retrieval-quality baseline - public Design Partner Intake page at
/design-partner.html, asking for one small real corpus, real questions, and a concrete agent workflow to benchmark - lightweight JavaScript and Python API clients in
clients/(seedocs/client-libraries.md) - Slack Socket Mode connector for local LLM + BaseMouse grounding in
integrations/slack/ - Dockerfile plus self-hosted Docker Compose examples in
deployment/compose/(seedocs/self-hosted.md) - retrieval quality eval harness (
npm run eval:retrieval) with golden queries indata/retrieval-eval/ - Kubernetes manifests in
k8s/ - GitHub Actions workflow for test/build/push/deploy on
main
Local development
npm test
npm run lint
npm run eval:retrieval
npm run eval:retrieval:demo
npm run dev
Open:
http://localhost:3000
http://localhost:3000/agent-governance-demo.html
http://localhost:3000/design-partner.html
Useful endpoints:
GET /healthz (liveness, process-only)
GET /readyz (readiness; 200 + degraded:true in demo-fallback mode)
GET /api/repository?limit=&offset= (paginated; anonymous sees the public demo corpus)
GET /api/search?q=agent%20context
GET /api/search?q=agent&type=feature
GET /api/context-pack?q=memory&limit=3
GET /api/context-pack?tag=memory
GET /api/billing/config
POST /api/checkout
POST /api/documents (requires Authorization: Bearer bm_...)
GET /api/documents/:id (current revision, workspace-scoped)
PUT /api/documents/:id (optimistic lock: expectedVersion or If-Match)
PUT /api/documents/:id?mode=upsert (idempotent: created/updated/unchanged — no version needed)
DELETE /api/documents/:id (tombstone — history preserved)
GET /api/documents/:id/history
GET /api/usage (plan, documents, pack pulls, storage vs limits)
POST /api/keys/claim (exchange a paid checkout session for a key — shown once)
POST /api/keys/rotate (authenticated; old key dies immediately)
POST /api/billing/portal (authenticated; Stripe-hosted cancel/payment management)
POST /api/stripe/webhook (Stripe events; SDK-verified signature)
GET /claim?session_id=... (post-checkout claim page, five designed states)
Write API and persistence
With DATABASE_URL set (managed Postgres — Supabase), BaseMouse runs a durable
store: API keys scope private workspaces, writes are append-only revisions, and
the public demo corpus survives database outages by degrading to the in-repo
seeds (X-BaseMouse-Degraded: true). Without DATABASE_URL the app runs the
in-memory seed store exactly as before. Provide DATABASE_CA_CERT (PEM) when
the provider's server cert chains to a private CA — TLS verification is never
disabled.
# issue a design-partner key (run via kubectl exec, never from a workstation)
DATABASE_URL=... node scripts/issue-key.mjs --plan demo
# import a folder of markdown into your workspace
BASEMOUSE_API_KEY=bm_... node scripts/import.mjs ./docs --base-url https://basemouse.com
# post-deploy smoke check
node scripts/smoke.mjs --base-url https://basemouse.com
# apply migrations (CI does this automatically before deploy)
DATABASE_URL=... node scripts/migrate.mjs
The round trip (write a doc, watch an agent cite it)
# 1. write a document into your workspace
curl -s -X POST https://basemouse.com/api/documents \
-H "Authorization: Bearer $BASEMOUSE_API_KEY" -H "Content-Type: application/json" \
-d '{"id":"release-policy","title":"Release Policy","body":"Never deploy on Fridays.","type":"policy"}'
# 2. pull a context pack that cites it — note the checksum and version
curl -s "https://basemouse.com/api/context-pack?q=release+policy" \
-H "Authorization: Bearer $BASEMOUSE_API_KEY" | head -40
# 3. the record is append-only — edit it, then ask for the history
curl -s https://basemouse.com/api/documents/release-policy/history \
-H "Authorization: Bearer $BASEMOUSE_API_KEY"
MCP (connect your agent natively)
BaseMouse speaks the Model Context Protocol at POST /mcp (stateless
Streamable HTTP, JSON-RPC). Tools: search, get_context_pack, and
upsert_document (the write door — agents can persist decisions and session
context by stable id, idempotently; unchanged content writes nothing) — same
auth, scoping, and quota metering as REST. Claude Code:
claude mcp add --transport http basemouse https://basemouse.com/mcp \
--header "Authorization: Bearer bm_..."
(Omit the header to browse the public demo corpus. OAuth-based hosted
connectors are not yet supported — config-file clients work today. The
endpoint is tool-agnostic: node integrations/cli/basemouse.mjs register
prints ready-to-paste MCP config for Claude Code, Cursor, Windsurf, Codex
CLI, Gemini CLI, Grok CLI, AWS Kiro, and Google Antigravity — and SSE-only
clients like IBM Bob via the mcp-remote bridge, which basemouse register bob
emits.)
Sync your workspace (any platform, any coding tool)
New here? docs/getting-started.md maps your situation to the right import path (coding workspace vs. any Markdown folder vs. GitHub repo) — the
syncCLI below is tailored to the AI-coding-workspace layout (CLAUDE.md/PROGRESS.mdper project); for arbitrary Markdown usescripts/import.mjsinstead.
integrations/cli/basemouse.mjs is a zero-dependency Node CLI that keeps a
projects workspace synced into BaseMouse as project:<slug>-tagged, versioned
documents. Node-only — no bash/curl/jq — so it behaves identically on
Windows, macOS, and Linux:
# one-shot: push every project's CLAUDE.md/PROGRESS.md under ~/projects
BASEMOUSE_API_KEY=bm_... node integrations/cli/basemouse.mjs sync
# continuous: reconcile once, then auto-push a project the moment its docs are saved
BASEMOUSE_API_KEY=bm_... node integrations/cli/basemouse.mjs watch
# one project directory (what CI uses)
BASEMOUSE_API_KEY=bm_... node integrations/cli/basemouse.mjs sync --single . --slug myproject
# MCP config for your coding tool (claude|cursor|windsurf|codex|gemini)
node integrations/cli/basemouse.mjs register
# the CLAUDE.md "Context retrieval" block for a project
node integrations/cli/basemouse.mjs snippet myproject
Sync is idempotent and cheap: one PUT ?mode=upsert per doc — the server
decides created/unchanged/updated next to its own normalization (no client-side
comparison to drift), merges tags additively so tags you added elsewhere are
never destroyed, and an unchanged save writes nothing. Per-doc failures warn
and continue (empty stub files are skipped, not failed, so CI stays green).
Requires Node 20+ and a server with upsert support (basemouse.com, or
self-hosted at the D9 release or later — older servers get a clear upgrade
message). Override BASEMOUSE_BASE_URL for self-hosted, --base-dir/BASE_DIR
for a different workspace root.
Sync on git push (GitHub Action)
For the most hands-off setup, let sync ride on git push — no daemon, no
per-machine key, works from any OS/editor. Add the repo secret
BASEMOUSE_API_KEY, then in .github/workflows/basemouse-sync.yml:
name: basemouse-sync
on:
push:
branches: [main]
paths: ['CLAUDE.md', 'PROGRESS.md']
jobs:
sync:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- uses: basemouse/basemouse-core/integrations/github-action@master
with:
api-key: ${{ secrets.BASEMOUSE_API_KEY }}
The action syncs the repo's CLAUDE.md/PROGRESS.md tagged
project:<repo-name> (override with the slug input; base-url targets a
self-hosted instance).
integrations/claude-code/basemouse-integration.sh(bash) is deprecated in favour of the CLI — it still works, but only receives fixes.
Operations
GET /metrics exposes Prometheus-format counters (pack pulls, quota denials,
claims, degraded state). Set ALERT_WEBHOOK_URL (ntfy/Slack) and the app
pages you when degraded mode persists >5m or claim failures spike. The
OpenAPI spec lives at /api/openapi.json.
GET /healthz reports liveness plus non-secret deployment posture: billing
and meshai enablement and a license object (mode, tier, whether a license
key is present, expiry). The license key value is server-only and never appears
in any response.
Faceted filters
Both /api/search and /api/context-pack accept optional type and tag query
parameters:
type— case-insensitive match against the document type (concept,feature,experience,principle,note,policy).tag— case-insensitive match against a document's tags.
Empty parameters are treated as "no filter". A value longer than 256 characters
returns 400 { "error": "invalid_filter", "message": "..." }.
Both endpoints echo the applied filters back in a filters field, e.g.
"filters": { "type": "feature", "tag": null }. For context packs the filter is
applied to the candidate set before the limit, so totalMatches and
truncated reflect the post-filter count.
GET /api/search?q=agent&type=feature -> only feature-type results
GET /api/context-pack?tag=memory -> pack entries all tagged "memory"
Example context-pack shape:
{
"schema": "basemouse.context_pack.v1",
"query": "memory",
"filters": { "type": null, "tag": null },
"entryCount": 1,
"totalMatches": 1,
"truncated": false,
"citations": [
{
"id": "memory-capsules",
"label": "[memory-capsules] Memory Capsules v1"
}
],
"entries": [
{
"id": "memory-capsules",
"links": ["agent-context-engine", "ghost-doc"],
"relevance": { "score": 3, "matchedTerms": ["memory"] },
"related": [
{ "id": "agent-context-engine", "title": "Agent Context Engine", "inPack": true },
{ "id": "ghost-doc", "title": null, "inPack": false }
],
"provenance": {
"source": { "kind": "seed", "path": "data/seed/memory-capsules.json" },
"checksum": "..."
}
}
],
"relationships": [
{ "from": "memory-capsules", "to": "agent-context-engine", "resolved": true },
{ "from": "memory-capsules", "to": "ghost-doc", "resolved": false }
]
}
Billing / Stripe setup
BaseMouse renders paid Starter, Team, and Enterprise plans from /api/billing/config.
POST /api/checkout creates a Stripe Checkout Session for self-serve tiers when Stripe is configured. If the env vars are absent, the UI and API degrade to a clear contact-sales state; no payment or customer data is stored locally.
Environment variables:
CHECKOUT_ENABLED # Master switch for self-serve Stripe checkout (required to enable paid tiers)
STRIPE_SECRET_KEY # server-only restricted key (rk_ preferred; sk_ also works)
STRIPE_WEBHOOK_SECRET # endpoint signing secret from Stripe → Webhooks
STRIPE_PRICE_STARTER # Stripe recurring Price ID for Starter
STRIPE_PRICE_TEAM # Stripe recurring Price ID for Team
STRIPE_PUBLISHABLE_KEY # optional public key for future Stripe client surfaces
STRIPE_API_VERSION # optional; defaults to the pinned app version
APP_BASE_URL # optional; defaults to https://basemouse.com for checkout return URLs
BILLING_SUCCESS_URL # optional explicit Checkout success URL
BILLING_CANCEL_URL # optional explicit Checkout cancellation URL
BILLING_CONTACT_URL # optional mailto/CRM URL for Enterprise/contact-sales fallback
STRIPE_PRICING_TABLE_ID # optional public ID reserved for future pricing table embed
To take real payments, a hosted operator provisions a Stripe product with
recurring prices (each tagged with tier metadata) and then:
- Set the GitHub repo secrets (
STRIPE_SECRET_KEY,STRIPE_PRICE_STARTER,STRIPE_PRICE_TEAM,STRIPE_WEBHOOK_SECRET, optionalSTRIPE_PUBLISHABLE_KEY) with the price IDs from the Stripe account — never commit them to git. - Create a webhook endpoint pointing at
/api/stripe/webhookand copy its signing secret intoSTRIPE_WEBHOOK_SECRET. CHECKOUT_ENABLED=truealready ships ink8s/deployment.yaml; for local dev set it in.env.- Verify
/api/billing/configshows checkout-enabled tiers without exposing secrets, and/api/stripe/webhookaccepts Stripe test events.
On the deployed cluster, the basemouse-billing Secret is materialized by CI: set
STRIPE_SECRET_KEY, STRIPE_PRICE_STARTER, STRIPE_PRICE_TEAM,
STRIPE_PUBLISHABLE_KEY, and STRIPE_WEBHOOK_SECRET as GitHub repo secrets and
the deploy workflow (.github/workflows/deploy.yml) syncs them into the
basemouse-billing Secret on every deploy. CHECKOUT_ENABLED=true already ships in
k8s/deployment.yaml, so checkout arms automatically once STRIPE_SECRET_KEY and at
least one price ID are present — and degrades to contact-sales if they are absent.
Seed documents
Seed documents live in:
data/seed/*.json
Each document is normalized by src/store.js, gets deterministic provenance metadata, and receives a stable 16-character SHA-256 checksum from the normalized content.
Deployment
The hosted service runs on Kubernetes. Continuous deployment is handled by
.github/workflows/deploy.yml: a runner builds and pushes the image, then
applies the k8s/ manifests and rolls out the new revision. Self-hosters can
deploy the same image with the Docker Compose examples in deployment/compose/
(see docs/self-hosted.md).
Key docs
docs/getting-started.md— first calls against the API and MCP endpointdocs/agent-integration.md— wiring BaseMouse into agents and MCP clientsdocs/client-libraries.md— JavaScript and Python API clientsdocs/retrieval-eval.md— golden-query retrieval quality harnessdocs/demo-corpus-agent-governance.md— public Agent Governance Demo corpus, page, and eval baselinedocs/self-hosted.md— run BaseMouse + local LLM + Slack inside a company network
Product thesis
The repository that agents actually love.
Shipped today:
- Agent Context Engine — structured/versioned
basemouse.context_pack.v1exports - retrieval: lexical + faceted + graph-aware linking + metadata, with citations and provenance
- hybrid retrieval — opt-in
retrieval=hybridblends one-hop graph expansion over document links, lexical term overlap, and a local hashed-vector similarity, with per-result signal explanations (lexical/vector/graph). Vectors are local/offline hashed-feature embeddings (no external vector DB, no paid embedding API), toggled withBASEMOUSE_VECTOR_RETRIEVAL. - retrieval quality harness —
npm run eval:retrievalscores search and context-pack output against strict golden-query suites; the seed suite is a smoke test and partner-corpus suites are the next quality gate. - local-first / self-hosted privacy
- append-only history & audit trail
Vision / roadmap (not implemented yet — listed as direction, not claims):
- real-corpus retrieval eval suites (human-reviewed expected docs, CI quality gates) before further retrieval tuning
- semantic vector retrieval (today's vectors are local hashed-feature embeddings — shared-vocabulary overlap in a dense space, not a learned semantic model; a real embedding provider can be plugged into the same vector path)
- full GraphRAG (multi-hop traversal + learned embeddings over the relationship graph; today's hybrid mode is one-hop graph expansion plus local hashed vectors)
- memory capsules
- built-in agent sandbox
- precision canvas UX
MeshAI integration (OpenTelemetry)
BaseMouse emits a standard OTLP/HTTP trace span for every context pack it generates, so MeshAI (or any OpenTelemetry backend) can observe, attribute, and audit what context agents pull. The wire format is vendor-neutral OTLP, so the same emission also works with Datadog, Honeycomb, or Grafana Tempo.
It is disabled by default and is a no-op until configured. No document bodies are ever sent: spans carry retrieval evidence only (query, counts, document ids).
Configure via environment variables:
MESHAI_OTLP_ENDPOINT # e.g. https://api.meshai.dev/api/v1/ingest (no-op if unset)
MESHAI_API_KEY # MeshAI API key (msh_...) with the telemetry:write scope
MESHAI_SERVICE_NAME # optional, defaults to "basemouse"
MESHAI_OTLP_TIMEOUT_MS # optional, defaults to 3000
Spans are POSTed to ${MESHAI_OTLP_ENDPOINT}/v1/traces with a Bearer token.
Each /api/context-pack request emits one span named basemouse.context_pack
with service.name, gen_ai.system=basemouse, gen_ai.operation.name=context_pack,
and basemouse.* evidence attributes. Emission is fire-and-forget with a hard
timeout: if MeshAI is slow or down, the context pack is still returned normally.
GET /healthz reports whether the integration is configured ("meshai": true).