The full upstream README, mirrored here for reference. Install config, tool schemas, adoption signals, and an original overview live on the Basemouse Core listing page.
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.
This is a small zero-dependency Node.js app:
data/seed/*.json/api/repository endpoint with count + normalized documents/api/search?q=... search endpoint with scores and matched terms/api/context-pack?q=...&limit=... agent-ready basemouse.context_pack.v1 exporttype and tag on both /api/search and /api/context-packretrieval=lexical|hybrid mode on both endpoints (lexical is the default, fully back-compatible). hybrid blends three signals — lexical term overlap, one-hop graph expansion along document links, and a local vector similarity — and annotates every result with a per-signal retrieval block 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 with BASEMOUSE_VECTOR_RETRIEVAL=off (graph+lexical hybrid still works).links and a resolved related list, plus a pack-level relationships edge list, so agents can follow how documents connect/agent-governance-demo.html, showing
the synthetic governance corpus, sample auditor/operator queries, and the
lexical vs hybrid retrieval-quality baseline/design-partner.html, asking for one
small real corpus, real questions, and a concrete agent workflow to benchmark/compare.html, covering the five
things people use instead of BaseMouse and where BaseMouse is the wrong toolsrc/billing.js and the visible FAQ by
test/structured-data.test.js so the markup cannot drift from the productclients/ (see docs/client-libraries.md)integrations/slack/deployment/compose/ (see docs/self-hosted.md)npm run eval:retrieval) with golden queries in data/retrieval-eval/mainOpen:
Useful endpoints:
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.
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:
Unauthenticated POST /mcp returns 401 with WWW-Authenticate so Cursor
marketplace Connect starts OAuth. Paste an existing bm_ key on the consent
page, or continue with the public demo. Config-file clients still send
Authorization: Bearer bm_.... REST anonymous demo is unchanged. 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.
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:
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.
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:
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.
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.
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.
Example context-pack shape:
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:
To take real payments:
tier metadata (starter or team). The app matches tiers by that tag,
not by price ID order./api/stripe/webhook and copy its
signing secret into STRIPE_WEBHOOK_SECRET.CHECKOUT_ENABLED=true. Never commit them. For local development put the same
names in .env (see .env.sample)./api/billing/config shows checkout-enabled tiers without exposing any
secret, and that /api/stripe/webhook accepts Stripe test events.A restricted key (rk_…) is preferred over a secret key. The minimum scopes are
write on Checkout Sessions and Billing Portal Sessions, plus read on Checkout
Sessions for the claim verification path.
Checkout arms itself once STRIPE_SECRET_KEY and at least one price ID are
present, and degrades to a contact-sales state when they are absent, so a
deployment with no Stripe configuration still runs.
Seed documents live in:
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.
The hosted service runs on Kubernetes and deploys continuously from main: a
build pushes the image, migrations run against the production database, and the
cluster 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).
Set CANONICAL_HOST to your bare domain (e.g. example.com) if you serve the
same site on both the apex and www. hostnames: GET and HEAD requests arriving
on www.<CANONICAL_HOST> are then 308'd to the bare host, so crawlers index one
origin instead of two. Only GET and HEAD are redirected, so the POST traffic that
carries every API, MCP, and webhook call is never moved. Leave it unset
to disable the redirect entirely — that is the default.
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 networkThe repository that agents actually love.
Shipped today:
basemouse.context_pack.v1 exportsretrieval=hybrid blends 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 with BASEMOUSE_VECTOR_RETRIEVAL.npm run eval:retrieval scores 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.Vision / roadmap (not implemented yet — listed as direction, not claims):
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:
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).