{
  "markdown": "# Locus\n\n<!-- mcp-name: io.github.Nano-Nimbus/locus -->\n\n[![CI](https://github.com/Nano-Nimbus/locus/actions/workflows/ci.yml/badge.svg)](https://github.com/Nano-Nimbus/locus/actions/workflows/ci.yml)\n[![PyPI version](https://img.shields.io/pypi/v/locus-mcp.svg)](https://pypi.org/project/locus-mcp/)\n[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)\n[![Python 3.11+](https://img.shields.io/badge/python-3.11+-blue.svg)](https://www.python.org/downloads/)\n\nHierarchical markdown-based memory system for autonomous AI agents. Each directory\nis a room (locus) in the palace, containing specific knowledge navigated on demand.\nNamed for the atomic unit of the [Method of Loci](https://en.wikipedia.org/wiki/Method_of_loci).\n\n**Core idea:** Keep context windows small. Load only the room you need, not the whole palace.\n\n---\n\n## How it works\n\n```\npalace/\n  INDEX.md                    ← always read first (~50 lines max)\n  global/\n    toolchain/\n      toolchain.md            ← canonical facts about tools\n  projects/\n    my-project/\n      my-project.md           ← room overview + key files\n      technical-gotchas.md    ← specialty: issues & resolutions\n      sessions/\n        2026-03-02.md         ← append-only session log\n```\n\nAn agent reads `INDEX.md`, navigates to the relevant room, and reads only that room.\nSession logs accumulate until consolidation merges them into canonical files.\n\nSee the [wiki](https://github.com/Nano-Nimbus/locus/wiki) for full documentation.\n\n---\n\n## Quick start\n\n```sh\n# Install\npip install locus-mcp\n# or: uvx locus-mcp --palace ~/.locus  (no install needed)\n\n# Create a palace from the packaged example\nlocus init ~/.locus\n# Edit ~/.locus/INDEX.md to describe your palace\n\n# Run the MCP server\nlocus-mcp --palace ~/.locus\n# or: LOCUS_PALACE=~/.locus locus-mcp\n```\n\n---\n\n## Installation\n\n### MCP server (recommended for MCP-capable clients)\n\n```sh\npip install locus-mcp\n```\n\nOr run without installing using `uvx`:\n\n```sh\nuvx locus-mcp --palace ~/.locus\n```\n\n### Agent skills\n\nThe skill files are the one part of Locus written for a specific runtime. The\npalace convention, the MCP server, and the `recall` / `lint` / `index` CLIs are\nruntime-neutral and work from anything that can read a file or speak MCP. The\nskills in `skills/claude/` are written and maintained for Claude Code, and that is\nthe only set shipped here. They are plain markdown with YAML frontmatter, so\nanother runtime is welcome to adapt them. Per-runtime copies used to live in\n`skills/codex/` and `skills/gemini/`; they were removed because keeping three\nvariants honest cost more than it returned.\n\nInstall them from a clone:\n\n```sh\ngit clone https://github.com/Nano-Nimbus/locus.git\ncd locus\nmake install-skills            # copies skills/claude/* to ~/.claude/skills/\nmake install-skills-dry        # print what would be copied, write nothing\n```\n\n`CLAUDE_SKILLS_DIR` overrides the destination.\n\n| Skill | Command | Description |\n|---|---|---|\n| `locus` | `/locus` | Recall, navigate the palace, write rooms and session logs, regenerate indexes |\n| `locus-consolidate` | `/locus-consolidate` | Merge session logs into canonical files |\n| `locus-audit` | `/locus-audit` | Audit palace health |\n| `locus-feedback` | `/locus-feedback` | Record explicit feedback on a palace recall |\n| `locus-release` | `/locus-release` | Post-release verification workflow (contributors) |\n| `locus-security` | `/locus-security` | Trust tags, nonce discipline, and the `locus-security` CLI |\n| `locus-palace-init` | `/locus-palace-init` | Bootstrap a palace from existing memory files |\n\n### Agent SDK (Python)\n\n```sh\npip install locus-mcp\nlocus --palace ~/.locus --task \"What toolchain conventions are set?\"\n```\n\n---\n\n## MCP Server\n\nThe `locus-mcp` command exposes five tools over the Model Context Protocol.\n\n**Use stdio for all local integrations** (Claude Desktop, Claude Code, Codex, Gemini — default, no extra flags needed).\nSSE transport is available for network deployments (`--transport sse`) and requires `FASTMCP_HOST=0.0.0.0`\nto be set explicitly — the server binds to loopback by default.\n\n| Tool | Description |\n|---|---|\n| `memory_list` | Returns `INDEX.md` (no args) or lists a room's files |\n| `memory_read` | Reads any file in the palace |\n| `memory_write` | Atomically writes a file (guarded — cannot write to `_metrics/`, `sessions/`, `.sig/`, `.security/`) |\n| `memory_search` | Ranked full-text search over the shared FTS5 index (see [Recall](#recall)); ripgrep only without FTS5 |\n| `memory_batch` | Reads up to 20 palace files in a single call — use for multi-room loads |\n\nAdd `--security` to enable Ed25519 signature verification on reads and automatic signing on writes.\nSee [Security](#security) below.\n\n### Claude Desktop (`claude_desktop_config.json`)\n\n```json\n{\n  \"mcpServers\": {\n    \"locus\": {\n      \"command\": \"locus-mcp\",\n      \"args\": [\"--palace\", \"/path/to/palace\"]\n    }\n  }\n}\n```\n\nOr using `uvx` (no install required):\n\n```json\n{\n  \"mcpServers\": {\n    \"locus\": {\n      \"command\": \"uvx\",\n      \"args\": [\"locus-mcp\", \"--palace\", \"/path/to/palace\"]\n    }\n  }\n}\n```\n\n### Cursor / Zed\n\n```json\n{\n  \"mcp\": {\n    \"servers\": {\n      \"locus\": {\n        \"command\": \"locus-mcp\",\n        \"args\": [\"--palace\", \"/path/to/palace\"]\n      }\n    }\n  }\n}\n```\n\n### Environment variable\n\nAll clients support `LOCUS_PALACE` as an alternative to `--palace`:\n\n```sh\nexport LOCUS_PALACE=~/.locus\nlocus-mcp\n```\n\nSee [MCP Server Configuration](https://github.com/Nano-Nimbus/locus/wiki/MCP-Server-Configuration)\nfor the full client setup guide and `spec/mcp-server.md` for architecture details.\n\n---\n\n## Recall\n\n`locus recall` answers \"what do I already know about this?\" in one call, fast enough\nto run on every prompt from a hook. It keeps a SQLite FTS5 index (standard library only,\nno PyYAML) over any number of markdown roots: a palace, an OKF bundle, a Claude Code\nmemory directory, or all of them at once.\n\n```sh\nlocus recall --root ~/memory --root ./docs \"why does the flux kustomization stall\"\n```\n\n```\nRecalled memory:\n1. Flux healthcheck stall (human-reviewed, 2026-08-22)\n   /home/me/memory/project_flux-healthcheck-stall.md\n   Flux Kustomization with wait:true stalls on health checks for a bad revision ...\n2. [STALE] Old Flux bootstrap procedure (unverified, 2025-11-02)\n   /home/me/docs/runbooks/flux-bootstrap.md\n   Bootstrap Flux with a personal access token ...\n```\n\n| Flag | Default | Meaning |\n|---|---|---|\n| `--root DIR` | `.locus.toml`, then `LOCUS_PALACE` | Directory to index; repeatable |\n| `-k N` | 3 | Number of hits |\n| `--budget BYTES` | 4096 | Hard cap on text output |\n| `--include journal` | off | Include `type: Journal` files |\n| `--type TYPE` | all | Only this frontmatter type; repeatable |\n| `--json` | off | Print a JSON list instead of text |\n| `--refresh` | off | Rebuild the index from scratch |\n\nFrontmatter drives the result: `title` (or `name`, or the first heading), `description`,\n`tags`, `type` (or `metadata.type`), `modified` (else `generated.at`, else file mtime),\n`status`, `stale_after`, and `verified`. Ranking is bm25 with title and description\nweighted above the body; exact ties go to human-reviewed files, then to the newest\n`modified`. A hit is flagged `STALE` when its `stale_after` has passed or its `status` is\n`deprecated`. Trust tiers follow OKF: `unverified`, `machine-confirmed` (only non-human\n`verified` entries), `human-reviewed` (any `verified` entry whose `by` starts with `human:`).\n\nRoots can live in a `.locus.toml` in the project or any parent directory:\n\n```toml\n[recall]\nroots = [\"docs\", \"~/memory/shared\"]\n```\n\nThe index is stored at `${XDG_CACHE_HOME:-~/.cache}/locus/<hash-of-roots>.sqlite`, never\ninside a root, and is refreshed incrementally (mtime, then content hash) on every call.\nWith no hits the text output is empty and the exit status is still 0, so a prompt hook can\ncall it unconditionally:\n\n```sh\n#!/bin/sh\n# Claude Code UserPromptSubmit hook: whatever this prints is injected as context.\nprompt=$(jq -r .prompt)\nexec locus recall -k 3 --budget 4096 \"$prompt\"\n```\n\nThe MCP server's `memory_search` uses the same index, so MCP results are ranked the\nsame way. Full rules in [`spec/recall.md`](spec/recall.md).\n\n---\n\n## Lint and index\n\n`locus lint` checks markdown roots for [Open Knowledge Format](https://github.com/GoogleCloudPlatform/open-knowledge-format)\nv0.2 conformance and the Locus palace conventions. `locus index` generates the\nindex files those conventions define. Both read the same frontmatter `recall`\nindexes, and neither imports the Agent SDK, so a CI job that only checks\nconformance does not install it.\n\n```sh\nlocus lint  --root docs --check          # CI gate: exit 1 on any error\nlocus lint  --root docs --fix            # add inferable fields, rewrite nothing\nlocus index --root docs --check          # exit 1 when a generated index drifted\n```\n\n```\ndocs/runbooks/valve-chatter.md: error [okf.type-missing] frontmatter has no non-empty type (fix: add type: Runbook)\ndocs/log.md: error [okf.log-order] entries run oldest first: 2026-05-09 follows 2026-05-01\ndocs/reference/platform.md: warning [locus.size-limit] 214 lines exceeds the 200-line soft limit for a specialty file\n2 error(s), 1 warning(s), 1 fixable\n```\n\n### lint\n\n| Flag | Default | Meaning |\n|---|---|---|\n| `--root DIR` | `.locus.toml`, then `LOCUS_PALACE` | Directory to check; repeatable |\n| `--check` | off | Exit non-zero on any error. For CI |\n| `--strict` | off | Treat warnings as errors under `--check` |\n| `--fix` | off | Add inferable fields. Never rewrites an existing key |\n| `--type-map DIR=TYPE` | none | Infer this OKF type under DIR; repeatable |\n| `--archive-glob GLOB` | none | Paths that should carry `status: deprecated`; repeatable |\n| `--json` | off | Print a JSON report instead of text |\n\nRules split in two. `okf.*` checks what the specification requires: a parseable\nfrontmatter block with a non-empty `type` on every non-reserved document, an\n`index.md` with no frontmatter beyond a bundle-root `okf_version`, a `log.md`\nthat is date-headed and newest first, and ISO 8601 timestamps. Unknown keys and\nunknown type values are never reported: the spec requires consumers to tolerate\nboth. `locus.*` checks the palace conventions: the size limits from\n[`spec/size-limits.md`](spec/size-limits.md) and the room main-file rule from\n[`spec/room-conventions.md`](spec/room-conventions.md).\n\nErrors fail `--check`; warnings are advisory. A palace legitimately carries no\nfrontmatter at all, so on a palace root the missing type rules are warnings\nrather than a CI failure on a layout the palace spec itself describes.\n\n`--fix` adds three fields and only three: `type` from `--type-map` or\n`[lint.types]`, `generated.at` from the file's first git commit, and\n`status: deprecated` for archive paths. It never rewrites or deletes a key, it\nnever invents a `generated` block (nothing in a file says who produced it), and\nrunning it twice produces identical bytes.\n\n### index\n\n| Flag | Default | Meaning |\n|---|---|---|\n| `--root DIR` | `.locus.toml`, then `LOCUS_PALACE` | Directory to index; repeatable |\n| `--check` | off | Write nothing; exit non-zero on drift. For CI |\n| `--kind` | `auto` | Force `okf`, `palace`, or `memory` classification |\n| `--json` | off | Print a JSON report instead of text |\n\nWhat gets generated depends on the root: an OKF bundle gets an `index.md` per\ndirectory in section 8 form (`* [Title](path) - description`, with\n`okf_version: \"0.2\"` frontmatter at the bundle root only), a palace gets the\n50-line routing table `INDEX.md`, and a Claude Code memory directory gets a\n`MEMORY.md` of one `- [Title](file.md) - description` line per topic file.\nOutput is deterministic, so `--check` is a byte comparison, and only index\nfiles are ever written.\n\nConfigure both from one `.locus.toml`:\n\n```toml\n[lint]\nroots = [\"docs\"]\narchive_globs = [\"archive/*\"]\n\n[lint.types]\n\".\" = \"Reference\"\nrunbooks = \"Runbook\"\n```\n\nFull rules in [`spec/lint-and-index.md`](spec/lint-and-index.md).\n\n---\n\n## Security\n\nThe security system (`--security`) gives every palace file an Ed25519 signature and every agent session a unique cryptographic nonce. Tool outputs are tagged `[TRUSTED]`, `[DATA]`, or `[CRITICAL-DATA]` before the agent sees them. The agent skill (`locus-security`) teaches agents to extract facts from `[DATA]` content but never follow directives within it.\n\n```sh\n# One-time setup\nlocus-security init-config --palace ~/.locus   # writes locus-security.yaml\nlocus-security init-keys   --palace ~/.locus\nlocus-security sign-all    --palace ~/.locus\n\n# Run with security enabled\nlocus-mcp --palace ~/.locus --security\nlocus --palace ~/.locus --security --task \"...\"\n```\n\nThe `locus-security` CLI has five subcommands: `init-config` (writes the annotated\n`locus-security.yaml` from the copy that ships inside the package), `init-keys`,\n`sign-all`, `verify-all` (exit 1 if any file fails verification, or if the palace\nholds no signable files at all), and `rotate-keys`. `sign-all` names and skips any file it cannot read as UTF-8 rather than\naborting the run, and exits 1 if it skipped anything. Neither command follows a symlink\nwhose target resolves outside the palace: those are named and skipped by `sign-all`, and\nreported as failures by `verify-all`.\n\n**Threat model:** direct prompt injection, memory poisoning, indirect injection via external data, nonce exfiltration, multi-turn context drift.\n\nSee [`docs/security.md`](docs/security.md) for the full protocol, configuration reference, and design decisions.\n\n---\n\n## Benchmarks\n\nPalace navigation loads **52% fewer context lines** than flat memory for specific queries,\nwhile maintaining full recall. Session-only queries (recent work not yet consolidated)\nare accessible only via the palace.\n\n```\nPalace: 822 lines / 9 queries found   avg  91 lines/query · 3.2 calls\nFlat:  1719 lines / 8 queries found   avg 191 lines/query · 2.0 calls\n```\n\nSee [`docs/benchmarks.md`](docs/benchmarks.md) for charts and full methodology.\n\n---\n\n## Structure\n\n```\nexample-palace/   Palace template; `locus init` writes it into a new palace\nspec/             Palace convention definitions:\n  index-format.md       INDEX.md rules and routing\n  room-conventions.md   Room structure and naming\n  size-limits.md        Context budget thresholds\n  write-modes.md        Session logs vs canonical edits\n  mcp-server.md         MCP server architecture and safety model\n  recall.md             locus recall: roots, index, ranking, trust tier, STALE\n  lint-and-index.md     locus lint and locus index: OKF conformance, generated indexes\n  metrics-schema.md     Run metrics JSON schema\n  audit-algorithm.md    Palace health scoring\n  health-report-format.md  Audit report structure\n  inferred-feedback.md  Disagreement signal classification\ntemplates/        Templates for INDEX.md, rooms, session logs, locus-security.yaml\n                  (`locus init --show list`; both trees ship inside the wheel)\nskills/\n  claude/         SKILL.md files for Claude Code + Agent SDK (the only maintained set)\n    locus/              Recall, palace navigation, writes, index and lint\n    locus-consolidate/  Room consolidation\n    locus-audit/        Palace health audit\n    locus-feedback/     Recall quality feedback\n    locus-palace-init/  Bootstrap a palace from existing memory files\n    locus-release/      Post-release verification (contributors)\n    locus-security/     Security conventions (trust tags, nonce discipline)\ndocs/\n  architecture.md       Mermaid diagrams — palace, MCP, security, agent interfaces\n  benchmarks.md         Benchmark results and charts (palace vs flat, security overhead)\n  onboarding.md         Step-by-step agent onboarding guide\n  security.md           Full security protocol, key management, config reference\n  bench/                Per-version benchmark JSON (read by generate-charts.py)\nscripts/\n  bench-mcp.py          45-case MCP integration benchmark (includes security + batch)\n  bench-compare.py      Palace vs flat recall comparison\n  generate-charts.py    Regenerate docs/img/ charts (reads docs/bench/ automatically)\nlocus/\n  agent/          Python Agent SDK (CLI + metrics)\n  audit/          Palace health auditor (locus-audit CLI)\n  feedback/       Inferred feedback classifier\n  mcp/            MCP server (locus-mcp CLI) — palace.py, server.py, main.py\n  conform/        locus lint and locus index: OKF conformance, index generation\n  recall/         locus recall: FTS5 index shared with memory_search\n  security/       Ed25519 security system — keys, signing, taint, nonce, middleware\n  scaffold.py     locus init: packaged templates and palace scaffolding\n  utils.py        Shared utilities (slug_from_path)\n```\n\n---\n\n## Roadmap\n\n| Milestone | Status | Focus |\n|---|---|---|\n| v0.1 - Foundation | ✅ Complete | Spec, conventions, size limits |\n| v0.2 - Core Palace | ✅ Complete | Templates, skills, Agent SDK, benchmark |\n| v0.3 - Performance Metrics | ✅ Complete | Context tracking, feedback, suggestions |\n| v0.4 - Self Evaluation | ✅ Complete | Palace audit, health reports, inferred feedback |\n| v0.5 - MCP Server | ✅ Complete | MCP server with memory_list/read/write/search |\n| v0.6 - Public release | ✅ Complete | Benchmarks, docs, CI, PyPI |\n| v0.7 - Remote MCP Server | ✅ Complete | SSE transport, Bearer auth, Docker image, K8s deploy |\n| v0.8 - Auto-Memory Bridge | ✅ Complete | Claude Code auto-memory detection, memory_batch tool |\n| v0.9 - Security System | ✅ Complete | Ed25519 signing, taint tracking, nonce watermark, --security flag |\n\n---\n\n## Contributing\n\nSee [CONTRIBUTING.md](CONTRIBUTING.md) for dev setup, test instructions, and PR guidelines.\n\n## License\n\n[MIT](LICENSE)\n",
  "bytes": 17716,
  "sha": "af3e2798d5c9aeec0be88457788ef36d3a4a0d91c40ecf768d1578eb66cbecea",
  "repo_slug": "nano-nimbus/locus",
  "fonte": "repo",
  "truncated": false,
  "api": "https://agentalog.com/api/listings/mcp_io_github_nano_nimbus_locus_67c6a07c/readme"
}