learning-loop-mcp
# learning-loop-mcp

`learning-loop-mcp` is a continuity layer for projects developed with Hermes or
other AI agents. It documents and makes the project's journey queryable—not
only its final lessons—so an agent can recover important context between
sessions through MCP or the CLI instead of starting every conversation from
scratch.
## Install in Hermes in 60 seconds
If you use Hermes Desktop or the Hermes MCP screen, choose **Add custom MCP**
and enter:
- **Name:** `learning-loop-mcp`
- **Transport:** `stdio`
- **Command:** `uvx`
- **Arguments:** `--from learning-loop-mcp==0.5.2 learning-loop-mcp-server`
- **Environment:**
- `LEARNING_LOOP_PROJECTS_ROOT=/home/your-user/Proyectos`
- `LEARNING_LOOP_MCP_DB=/home/your-user/.local/share/learning-loop-mcp/index.db`
Use the actual path where your project repositories live. The index path is
optional.
From a terminal, the equivalent command is:
```bash
hermes mcp add learning-loop-mcp \
--command uvx \
--env LEARNING_LOOP_PROJECTS_ROOT=/home/your-user/Proyectos \
--env LEARNING_LOOP_MCP_DB=/home/your-user/.local/share/learning-loop-mcp/index.db \
--args --from learning-loop-mcp==0.5.2 learning-loop-mcp-server
hermes mcp test learning-loop-mcp
```
- **Preflight:** before changing files or installing dependencies, run the read-only
project gate:
```bash
learning-loop-mcp project-preflight PROJECT \
--kanban-board BOARD --task-id TASK_ID --json
```
The equivalent MCP tool is `project_preflight`. It requires an explicit board,
an existing workspace with `README.md`, `AGENTS.md`, `docs/lessons.md`,
`docs/metrics/errors.yaml`, and `docs/metrics/solutions.yaml`, a Hermes project
linked to that board and workspace, and an initial card containing `Purpose`,
`Expected result`, `Acceptance criteria`, and `Planned tests`.
A result with `ready: false` is a blocking stop signal. The tool is read-only:
it never creates or changes a board, project, card, file, dependency, or
private Hermes database. Use the official Hermes CLI to repair the reported
condition, read the board and card back, then run preflight again. Set
`--hermes-bin` or `HERMES_BIN` when the MCP process cannot resolve `hermes` on
its own.
`uvx` downloads the pinned release from PyPI and starts the server. For Hermes,
use **`learning-loop-mcp-server`**. The command **`learning-loop-mcp`** is the
separate CLI for indexing, searching, validation, backups, recovery, and
preflight.
### Running the real Hermes E2E
The full workflow E2E runs inside a disposable Ubuntu container. The Fedora
host only needs rootless Podman and a built wheel:
```bash
uv build --wheel
podman run --rm --network host \
-v "$PWD:/mnt/repo:Z" \
-v "$PWD/dist:/mnt/dist:Z" \
ubuntu:24.04 \
bash /mnt/repo/scripts/e2e-hermes-learning-loop.sh
```
The script installs Python and the build tools inside the container before it
locates the wheel. `DIST_DIR`, `PROJECTS_ROOT`, and `DB` can be overridden for
local runners. The script creates an isolated Hermes home, board, project, and
MCP registration; it does not use the host Hermes state.
After the server is connected, initialize each project once from a checkout:
```bash
./scripts/init-project.sh /path/to/your-project
learning-loop-mcp index /path/to/your-project
```
## What problem does it solve?
A conversation may contain important decisions, but a conversation is not a
durable memory source. When a session ends or the agent changes, the project can
lose:
- its original purpose;
- decisions and the reasons behind them;
- constraints that must not be broken;
- investigated failures and their checks;
- task state and the concrete next action.
The result is repeated work, contradictory decisions, and agents that appear to
continue successfully but actually depend on someone retelling the history.
## How does it solve it?
The project keeps this context in versioned files inside the repository being
developed. `learning-loop-mcp` validates, indexes, and exposes those files for
queries:
1. **At the start of a task**, the agent queries relevant project context and
applicable lessons.
2. **While working**, it can capture a task outcome as a validated draft without
automatically turning it into canonical knowledge.
3. **When closing the task**, a person or authorized agent explicitly decides
what should be promoted to a lesson, solution, ADR, or runbook.
4. **In another session**, the next agent queries that context through MCP or the
CLI and continues with evidence, constraints, and the next action.
The source of truth is versioned Markdown/YAML. Together, those files form a
queryable project log: they record not only what was decided, but also why, what
was tried, what failed, which check confirmed it, and what remains to be done.
SQLite is only a rebuildable local index for fast queries; it is not the primary
memory or a second source of truth.
The practical consequence is important: for a question such as “why is it
designed this way?” or “what have we already tried?”, the agent can recover an
answer with citations and state. If the evidence is missing or insufficient,
the system reports that it is unknown instead of filling the gap with a guess.
```text
Project repository
├── docs/lessons.md purpose and lessons
├── docs/metrics/errors.yaml error classes and checks
├── docs/metrics/solutions.yaml verified solutions
├── docs/adr/ decisions and rationale
└── docs/runbooks/ operational procedures
│
│ parser + validator + derived index
▼
Local SQLite (FTS5 + sqlite-vec)
│
├── learning-loop-mcp-server ← MCP stdio for Hermes/agents
└── learning-loop-mcp ← CLI for people and scripts
```
## Why install it?
Because current code rarely explains its entire history.
Three months later, someone may return to the project and ask:
- Why was this architecture chosen?
- Which alternative was rejected?
- What constraint existed at the time?
- Is this strange behavior intentional or is it a bug?
- What was tried before, and why did it not work?
Without durable memory, they have to search old conversations, inspect commits
without context, or ask the person who made the decision. Sometimes that person
is no longer available.
With `learning-loop-mcp`, those answers can remain documented together with the
decision, its circumstances, the tests, and the sources. They can be queried by
question without manually reading the entire repository:
```text
Why does this service use a queue instead of calling the API directly?
```
The answer can include the decision, the rejected alternative, the failure that
motivated it, and the evidence that confirmed it. If there is not enough
information, the system says so instead of inventing an explanation.
That is the reason to install it: to turn the project's technical history into
recoverable context for the people and agents who will maintain it later.
## What does the loop add?
The loop is not just a document search tool. It is a way to make work accumulate
instead of disappearing when a session ends.
### For maintainers
- Reconstruct decisions months later, including their circumstances and rejected
alternatives.
- Distinguish intentional odd behavior from a pending bug.
- Find what was tried and what failed without repeating experiments.
- Understand the real work state: done, blocked, verified, or pending.
- Onboard another person without transferring the entire history orally.
### For AI agents
- Start with relevant context instead of an anonymous repository.
- Receive previous constraints and decisions before proposing changes.
- Query concrete sources instead of blindly summarizing documents.
- Know which next action was expected.
- Report that something is unknown when there is not enough evidence.
### For the long-term project
- Decisions survive sessions, agents, and people.
- Failures become reusable checks.
- Verified solutions stay separate from drafts and assumptions.
- Documentation becomes a log of how the system evolved rather than a static
snapshot.
- Knowledge remains versioned, reviewable, and recoverable alongside the code.
The cycle is simple:
```text
query → work → capture what happened → verify → decide what to promote
↑ │
└──────────── next session / next agent ─────────────────┘
```
## Simple example: continuing a project journey
Imagine a project that develops an online store.
During one session, the team discovers that payments must be confirmed through a
webhook, not through Stripe's immediate response. They document the decision,
the reason, and the test that confirmed it. They also record that the webhook
still lacks retries and that this is the next task.
In another session, the agent receives a short request:
```text
Add retries for the payment webhook.
```
Without context, it would have to guess how payment confirmation works and might
use Stripe's immediate response again. With `learning-loop-mcp`, it queries the
project journey and finds:
```text
Decision: confirm payments through a webhook.
Reason: the immediate response does not guarantee that payment completes.
Check: asynchronous confirmation tests.
Pending: add webhook retries.
Source: docs/adr/0003-payment-webhook.md, docs/lessons.md:42-55.
```
The agent now knows not only *what* code to write, but why the system is designed
that way, what must not be broken, and which task is pending. If the answer is
not documented, the system must say so instead of inventing it.
## Who is it for?
It is for teams and individuals who:
- work in repositories over many sessions;
- use Hermes, MCP, or other programming agents;
- need decisions and constraints to survive session changes;
- want Git-auditable memory rather than an opaque conversation;
- prefer retrieving relevant context instead of loading complete documents into
every prompt.
It is not a task manager, a remote database of conversations, or a system that
decides by itself which knowledge is correct. Hermes Kanban state can be queried
read-only through the official Hermes CLI, but the board remains Hermes'
responsibility.
## Quick path
### 1. Add the server through Hermes Custom MCP (recommended)
The current published version is `0.5.2` and requires Python `>=3.13`.
Hermes can install and run it from PyPI without a checkout or a manually managed
virtual environment.
In Hermes, open the MCP screen and choose **Add custom MCP**. Enter:
- **Name:** `learning-loop-mcp`
- **Transport:** `stdio`
- **Command:** `uvx`
- **Arguments:**
```text
--from learning-loop-mcp==0.5.2 learning-loop-mcp-server
```
- **Environment variables:**
```text
LEARNING_LOOP_PROJECTS_ROOT=/home/your-user/Proyectos
LEARNING_LOOP_MCP_DB=/home/your-user/.local/share/learning-loop-mcp/index.db
```
Use the actual path to the directory that contains your project repositories.
The index path is optional; the default XDG data path is also valid.
`uvx` downloads the pinned package from PyPI and launches the MCP server. You
do not need to clone this repository, create a virtual environment, find the
server executable, or edit Hermes' `config.yaml`.
The equivalent Hermes configuration is:
```yaml
mcp_servers:
learning-loop-mcp:
command: uvx
args:
- --from
- learning-loop-mcp==0.5.2
- learning-loop-mcp-server
env:
LEARNING_LOOP_PROJECTS_ROOT: /home/your-user/Proyectos
LEARNING_LOOP_MCP_DB: /home/your-user/.local/share/learning-loop-mcp/index.db
```
The equivalent CLI command is:
```bash
hermes mcp add learning-loop-mcp \
--command uvx \
--env LEARNING_LOOP_PROJECTS_ROOT=/home/your-user/Proyectos \
--env LEARNING_LOOP_MCP_DB=/home/your-user/.local/share/learning-loop-mcp/index.db \
--args --from learning-loop-mcp==0.5.2 learning-loop-mcp-server
hermes mcp test learning-loop-mcp
```
Restart Hermes, or use its MCP reload action if available, so the tools and
`learning-loop://` resources are discovered.
### Alternative: install the executable manually
For a manually managed Hermes host:
```bash
uv tool install learning-loop-mcp==0.5.2
hermes mcp add learning-loop-mcp \
--command "$HOME/.local/bin/learning-loop-mcp-server" \
--env LEARNING_LOOP_MCP_DB="$HOME/.local/share/learning-loop-mcp/index.db" \
--env LEARNING_LOOP_PROJECTS_ROOT="$HOME/Proyectos"
hermes mcp test learning-loop-mcp
```
If `uv tool install` prints a different executable path, use that path in
`--command`. Restart Hermes after registering the server.
### 2. Prepare a project
The initialization scripts are available from a repository checkout. Clone the
repository and run:
```bash
git clone https://github.com/tiempor3al/learning-loop-mcp.git
cd learning-loop-mcp
./scripts/init-project.sh /path/to/your-project
```
The script creates canonical templates under `docs/` and adds the ritual
reference to `AGENTS.md`. It does not overwrite existing files and is safe to
run more than once.
### 3. Index and query
```bash
learning-loop-mcp index /path/to/your-project
learning-loop-mcp learning-context \
/path/to/your-project \
"continue the pending task while respecting project decisions"
```
In Hermes, the agent can use the `learning_context` MCP tool to receive relevant
context. The response can include read-only Kanban state when
`LEARNING_LOOP_KANBAN_BOARD` is configured.
## What it preserves and what it does not do automatically
- **Durable memory versus conversation:** context is kept in project files and
Git; prompts and complete conversations are not stored. The documentation
preserves the journey: decisions, attempts, failures, tests, constraints, and
next steps.
- **Source of truth versus index:** versioned Markdown/YAML is primary; SQLite
can be deleted and rebuilt with `index`.
- **Capture versus promotion:** `capture-outcome` writes a draft to the explicit
path and returns `promoted: false`; it does not automatically edit canonical
lessons, ADRs, runbooks, or solutions.
- **MCP versus CLI:** MCP lets an agent query during a session; the CLI serves
people, scripts, and reproducible operations.
- **Checks versus semantic judgment:** deterministic checks verify facts,
citations, and state; the Amnesia Test also requires explicit evaluation. The
system returns `score: unknown` when that evaluation cannot be determined and
never invents a score from the mere presence of documents.
## Features
- Parser and validator for the canonical `docs/lessons.md` format, including
`Error class:`, `Check:`, and `Task:` markers.
- Hybrid search: SQLite FTS5 for citable lexical matches and `sqlite-vec` for
semantic search, fused with RRF.
- Local embeddings through small `fastembed` models, with an offline FTS5
fallback and no external APIs.
- Append-only verified-solution registry with explicit states and gates,
write-through YAML, and drift detection.
- Typed discovery and indexing of ADRs and runbooks while keeping their files
authoritative.
- `amnesia-check` for deterministic continuity checks.
- `amnesia-evaluate` for combining verifiable facts with an explicit Amnesia
Test report evaluation.
- Export, consistent SQLite backups, and recovery bundles with manifests and
checksums.
- Configurable project root through `LEARNING_LOOP_PROJECTS_ROOT`; one
installation can serve repositories in different paths.
## Installation from a checkout
For developing the project or installing its scripts and skill as well:
```bash
uv sync --extra dev
uv run pytest
uv run ruff check src tests
./scripts/install.sh
```
`./scripts/install.sh` is idempotent. It can migrate a legacy index and accepts
these overrides:
- `LEARNING_LOOP_MCP_DB` — explicit index path;
- `LEARNING_LOOP_PROJECTS_ROOT` — repository root;
- `LEARNING_LOOP_INSTALL_SKIP_HERMES=1` — sync without registering MCP;
- `LEARNING_LOOP_INSTALL_WITH_SKILLS=1` — also install `skills/` into
`$HERMES_HOME/skills`;
- `LEARNING_LOOP_INSTALL_DEV=0` — skip development extras.
After installation, restart the Hermes gateway so the tools and
`learning-loop://` resources appear.
## CLI
The `learning-loop-mcp` entry point includes, among others, these commands:
```bash
learning-loop-mcp index PROJECT [--lessons PATH] [--with-embeddings] [--db PATH]
learning-loop-mcp search QUERY [--project PROJECT] [--with-embeddings] [--json]
learning-loop-mcp learning-context PROJECT TASK [--version 1|2] [--kanban-board BOARD] [--json]
learning-loop-mcp capture-outcome PROJECT --draft PATH --output PATH [--json]
learning-loop-mcp amnesia-check PROJECT [--kanban-board BOARD] [--json]
learning-loop-mcp amnesia-evaluate PROJECT [--evaluation PATH] [--ignore-evaluation]
learning-loop-mcp validate PROJECT [--errors PATH] [--tests-dir PATH] [--json]
learning-loop-mcp status PROJECT [--json]
learning-loop-mcp register-solution PROJECT --solution-id X --title T --status E [--json]
learning-loop-mcp solutions PROJECT [--solution-id X] [--status E] [--json]
learning-loop-mcp reindex-solutions PROJECT [--solutions-path PATH] [--json]
learning-loop-mcp backup [--db PATH] [--out PATH]
learning-loop-mcp backup --recovery --kanban-board BOARD [--checkpoint PATH] [--out PATH]
learning-loop-mcp export PROJECT... [--out PATH] [--json]
learning-loop-mcp import BUNDLE [--projects-root PATH] [--db PATH] [--json]
learning-loop-mcp import-recovery BUNDLE [--projects-root PATH] [--db PATH] [--json]
learning-loop-mcp resume PROJECT [--checkpoint PATH] [--json]
```
`export` creates a versioned bundle with canonical documents and a checksum
manifest. `backup --recovery` adds a consistent SQLite snapshot and a Kanban
archive exported through `hermes kanban boards export`, without reading Hermes'
private database. Extraction validates members and prevents path traversal.
Restores operate in a new directory and do not modify the original project or
board. The technical `backup` command also creates a SQLite snapshot using
`sqlite3.Connection.backup()` and runs `PRAGMA integrity_check`.
## MCP server
The server uses stdio and runs with:
```bash
learning-loop-mcp-server
```
It exposes the `search`, `learning_context`, `capture_outcome`, `amnesia_check`,
`amnesia_evaluate`, `learning_status`, `index`, `register_solution`,
`reindex_solutions`, and `solutions` tools. It also serves
`learning-loop://format/...` and `learning-loop://templates/...` resources.
`learning_context` keeps the legacy response by default. With
`context_version=2`, it returns the ADD continuity package, including warnings,
sources, and—when configured—read-only Kanban state. It only invokes the
official `hermes kanban ... list --json` CLI; it never modifies cards or reads
Hermes' private SQLite database.
For SDK-based MCP clients, `stdio_client` uses a curated environment by default.
Pass `env=dict(os.environ)` in `StdioServerParameters` so the server receives
`LEARNING_LOOP_MCP_DB` and `LEARNING_LOOP_PROJECTS_ROOT`.
## Canonical sources and contracts
- [ADD contract](docs/add-contract.md)
- [Requirements](docs/requirements.md)
- [Amnesia Test evaluation](docs/amnesia-test.md)
- [Decision format](docs/decision-format.md)
- [Lessons format](docs/lessons-format.md)
Lessons and all new project content are written in English by decision of
ADR-0001, keeping local search and embeddings consistent. Spanish exceptions
belong to historical migration files.
## Environment variables and exit codes
- `LEARNING_LOOP_PROJECTS_ROOT` — repository root, resolved on every call;
- `LEARNING_LOOP_MCP_DB` — SQLite index path;
- `LEARNING_LOOP_KANBAN_BOARD` — Hermes board that can be queried read-only;
- `0` — operation succeeded;
- `1` — error-severity findings;
- `2` — usage or I/O error.
By default, documents live under
`<LEARNING_LOOP_PROJECTS_ROOT>/<project>/docs/` and the index lives at
`$LEARNING_LOOP_MCP_DB` or `$XDG_DATA_HOME/learning-loop-mcp/index.db`.
## Detailed architecture
```text
project repositories (versioned Markdown/YAML) [source of truth]
↓ parser / validator
local SQLite FTS5 + sqlite-vec [derived index]
↓ loop.py, shared domain
CLI ───────── MCP stdio ───────── learning-loop:// resources
```
No absolute host paths are embedded in the package: the project root is
configured through the environment and the installed kit locates its own
resources through `__file__`.
## Limits and debugging
- Prompts, complete conversations, tokens, and invasive telemetry are not
stored.
- The presence of files alone does not prove that an architecture is
understandable. Semantic evaluation and automatic evaluation remain separate.
- If sources are missing or a result cannot be determined, the system reports
`unknown` instead of guessing.
- FastMCP logs go to **stderr**; stdout is reserved for JSON-RPC.
- Tests are offline and require no credentials. Embeddings use synthetic vectors
or the cached model.
## CI and publishing
`.github/workflows/ci.yml` runs tests, lint, and compilation on every PR and push
to `main`, using Python 3.13. Dependabot maintains the `uv` dependencies and
official GitHub Actions.
Publishing uses PyPI Trusted Publishing with GitHub OIDC. The workflow requests
only `contents: read` and `id-token: write`; it uses no persistent PyPI token. To
publish a new version, merge the change first, then create a `vX.Y.Z` tag and
GitHub Actions publishes the artifact through the publisher configured in PyPI.
## License
MIT — see [LICENSE](LICENSE).
TDQS
Scored across 11 tools
Most tools have distinct purposes, but several pairs overlap in surface intent: amnesia_check vs amnesia_evaluate both concern continuity/Amnesia validation, and learning_context vs search both return lesson-related content. The descriptions help a careful agent differentiate them, but the boundaries are not immediately obvious.
All names use snake_case and are readable, but the pattern is mixed: some are verb_noun (capture_outcome, register_solution, reindex_solutions), some are noun phrases (learning_status, learning_context, project_preflight), and some are bare words (index, search, solutions). This is not chaotic, but it lacks a consistent convention.
Eleven tools is well within the ideal range for a domain-specific server. Each tool serves a distinct role in the learning-loop lifecycle, and none feel redundant or purely decorative.
The toolset covers the main learning-loop workflow: preflight, outcome capture, Amnesia validation, indexing, solution registration, status, and retrieval. Minor gaps exist—such as no explicit promotion tool or lesson deletion—but these may be intentional given the append-only and forward-only design.