Metadata-Version: 2.4
Name: leaxp
Version: 0.5.0
Summary: Agentic experience kit — package and distribute agent skills as portable .xp files.
Project-URL: Homepage, https://leaxp.com
Project-URL: Repository, https://github.com/vunone/leaxp
Project-URL: Issues, https://github.com/vunone/leaxp/issues
Author: Leaxp Authors
License-Expression: Apache-2.0
License-File: LICENSE.txt
Keywords: agent,ai,experience,llm,mcp,rag,skill
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: License :: OSI Approved :: Apache Software License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Scientific/Engineering :: Artificial Intelligence
Classifier: Topic :: Software Development :: Libraries
Classifier: Typing :: Typed
Requires-Python: >=3.11
Requires-Dist: anyio>=4.7.0
Requires-Dist: fastembed>=0.8.0
Requires-Dist: fastmcp>=2.0.0
Requires-Dist: httpx>=0.28.0
Requires-Dist: numpy>=2.0.0
Requires-Dist: platformdirs>=4.3.0
Requires-Dist: pydantic>=2.10.0
Requires-Dist: pyyaml>=6.0.0
Requires-Dist: rich>=13.9.0
Requires-Dist: tomli-w>=1.1.0
Requires-Dist: typer>=0.15.0
Description-Content-Type: text/markdown

# Leaxp

![Leaxp](https://github.com/vunone/leaxp/blob/main/docs/assets/hero.webp?raw=true)

[![CI](https://github.com/vunone/leaxp/actions/workflows/ci.yml/badge.svg)](https://github.com/vunone/leaxp/actions/workflows/ci.yml)
[![codecov](https://codecov.io/gh/vunone/leaxp/branch/main/graph/badge.svg)](https://codecov.io/gh/vunone/leaxp)
[![PyPI](https://img.shields.io/pypi/v/leaxp.svg)](https://pypi.org/project/leaxp/)
[![Python](https://img.shields.io/pypi/pyversions/leaxp.svg)](https://pypi.org/project/leaxp/)
[![License](https://img.shields.io/pypi/l/leaxp.svg)](https://github.com/vunone/leaxp/blob/main/LICENSE.txt)

> **Lea**rn -> e**xp**erience — a bridge sharing experience between agentic sessions.

**Leaxp gives your coding agent a memory it can carry between sessions — and lets you package that memory as a file other projects can install.**

Every new agent session starts from zero: it greps the same files, rediscovers the same conventions, and repeats the mistake the last session already worked out. Leaxp fixes that with a per-project knowledge database — `.xp/`, plain Markdown records indexed by a small local embedding model — that agents search, read and write through five MCP tools.

|  | Leaxp |
| --- | --- |
| **Where knowledge lives** | Markdown files in `.xp/`, git-tracked and human-editable |
| **Who writes it** | your own agent CLI (`claude` / `codex`) and your agent at runtime |
| **How it is searched** | a small local ONNX embedding model — vectors in `index.npy` |
| **What it costs** | no LLM API, no API keys, no services, no torch |
| **How it travels** | `.xp` files — zip of Markdown + a sha256 manifest, installable anywhere |

The payoff: smaller context, cheaper inference, model-agnostic knowledge, and 3–5 turns of orientation instead of a full-repo grep.

> **Status: MVP** — file and GitHub repository installs work end-to-end; the hosted registry is coming.

## How it works

```
  your codebase                                        teammate / another project
       │                                                          ▲
       │ exp learn / exp forge / exp fuse                         │ exp install
       ▼                                                          │
  your agent CLI  ───────►  .xp/local/*.md  ───── exp share ─────► my-skills.xp
  (claude / codex)          (Markdown, yours)                     (zip + sha256)
                                   │
                                   ▼  local embeddings
                            index.npy + index.json
                                   │
                                   ▼  recall / expand / read / remember / forget  (MCP)
                            your agent, every next session
```

## Install

```bash
pip install leaxp
```

Python 3.11+. Search runs on a small local ONNX embedding model ([fastembed](https://github.com/qdrant/fastembed)) that downloads itself on first use — no torch, no services, no API keys.

## Quickstart

Four commands take you from an empty project to an agent with memory.

### 1. Wire Leaxp into your agent

```bash
exp use --with claude
```

Creates `.xp/`, `leaxp.toml` and `leaxp.lock`, then registers the MCP server and the prompt hook in `.mcp.json` and `.claude/settings.json`. Claude Code is the supported target today.

> Run it **from the environment Leaxp is installed in** — the wiring stores that environment's absolute `exp` path, because your coding agent runs outside the project's virtualenv. Start a fresh agent session afterwards to pick it up.

### 2. Teach it your codebase

```bash
exp learn --goal "onboard new contributors"
```

Drives your own `claude` / `codex` CLI over the repo. It distills the recurring patterns into one Markdown record per topic under `.xp/local/`, and Leaxp indexes whatever appeared. The records are yours: git-tracked, reviewable in a PR, editable in your editor.

### 3. Install skills from GitHub

```bash
exp install https://github.com/org/repo --skill name
```

Pulls a repository's `SKILL.md` skills into `.xp/share/org-repo/` and declares the package in `leaxp.toml` + `leaxp.lock`. Drop `--skill` to install every skill the repo publishes.

### 4. Upgrade an installed package

```bash
exp install https://github.com/org/repo --upgrade
```

Re-resolves the source to its newest version and moves the lock to it. Without `--upgrade`, installs replay the locked version, so they stay reproducible.

That is the whole loop. From here your agent gets a memory recall on its first prompt of every session and writes back what it learns.

## Repository knowledge management

Day-to-day upkeep once memory is in place.

| Command | Reach for it when |
| --- | --- |
| `exp sync --upgrade` | you pulled a `leaxp.toml` change, edited records by hand, or want newer skill releases |
| `exp share -o pkg.xp` | you want to hand your project's knowledge to a teammate or another repo |
| `exp install -f pkg.xp` | you received an `.xp` file and want it in this project |
| `exp exec "…"` | you want to see exactly what an agent gets back for a query |
| `exp forge` | memory has drifted: duplicates, stale statements, rules buried in long records |
| `exp fuse` | you adopted several packages about the same job and want one guided package out of them |

### Keep dependencies and the index current

```bash
exp sync             # install declared packages at their locked version, then reindex .xp/
exp sync --upgrade   # ...and check every unpinned package for a newer version
```

Three steps in one pass: install every `[[packages]]` entry that is missing or drifted from the lock → with `--upgrade`, re-resolve unpinned packages against their source → reindex `.xp/`, so hand-edited records become searchable too.

### Share your project's knowledge

```bash
exp share -o my-project.xp
```

Packs `.xp/local/` into a portable `.xp` file — a zip of the Markdown plus a sha256-signed manifest. Embeddings are **not** shipped; they are recomputed on install, so the same pack works with any embedding model.

### Install from a file

```bash
exp install -f my-project.xp          # → .xp/share/<name>/ — a read-only dependency
exp install -f my-project.xp --self   # → .xp/local/ — adopted as your own, editable
```

### See exactly what your agent sees

```bash
exp exec "create stripe subscription"
exp exec "define new cli subcommand" -s "error handling" -n 5
```

Prints the raw `recall` tool output, byte for byte what a connected agent receives — the fastest loop for tuning record titles and descriptions.

### Consolidate memory that drifted

```bash
exp forge
```

`remember` keeps the database consistent one write at a time, but a long series of sessions still drifts: near-duplicates accumulate, statements go stale against the code they describe, and rules stay buried in long records instead of being flagged as conventions.

`exp forge` is the periodic repair pass. It drives your own agent through a consolidation flow:

1. cluster `.xp/local/` by file name;
2. write the clusters down as a plan in `.xp/consolidation-<dtime>.md`;
3. walk that plan — grounding every statement in the real codebase, merging duplicates found via `recall`, splitting rules out as one-paragraph conventions;
4. run the full `exp sync` pass, so the reshaped memory is reindexed.

The plan file doubles as a review log: every cluster gets a *Consolidation Result*, plus *Consolidation Gaps* where the agent noticed knowledge that is missing.

### Fuse many sources into one guided package

```bash
exp install -f ui-design-a.xp --self   # adopt each source into .xp/local/
exp install -f ui-design-b.xp --self
exp fuse
```

Install a dozen skills for the same job and `.xp/local/` holds a dozen authors' takes on it: the same rule stated three ways, two flows that contradict each other, and no order to read them in. `exp fuse` rewrites that pile as one coherent package:

1. cluster `.xp/local/` by subject and write the clusters down as a plan in `.xp/fusion-<dtime>.md`;
2. fuse each cluster into `.xp/temp/` — duplicates merged, every contradiction resolved **autonomously** in favour of the better-grounded, better-argued, more specific instruction;
3. write one [workbook](#workbook) record last: the table of contents and end-to-end execution flow of the fused package;
4. replace `.xp/local/` with the staged package and run the full `exp sync` pass.

The agent stages into `.xp/temp/` rather than editing in place, so a fusion that dies halfway leaves your memory untouched — the swap only happens if records were actually produced. The plan file doubles as a review log: per cluster, a *Fusion Result*, the *Resolved Conflicts* and why each winner won, plus any *Fusion Gaps*.

## What your agent sees

Once wired, agents get an initial memory recall on their first prompt and five tools:

| Tool | What it does |
| --- | --- |
| `recall(query, subquery?, limit?)` | Search records. Returns scored titles + expected outcomes, grouped into `<package>` blocks, low-relevance hits already filtered out. Conventional records come fully expanded as `<rule>` entries in a separate `<conventions>` block; the workbook of every package that matched is listed collapsed in a `<guides>` block. |
| `expand(id \| [ids])` | Fetch full Markdown bodies — one record or several at once. |
| `read(name)` | Fetch a record by file name, with or without `.md` — how a workbook's links are followed. |
| `remember(title, description, content, id?, convention?)` | Write new knowledge, or update a record in place by passing its `id`. Pass `convention=true` for a one-paragraph rule. |
| `forget(id \| [ids])` | Delete records that became duplicates or went out of date. |

Two things make this a *consistent* memory rather than an append-only log:

- **`remember` reviews itself.** Its answer replays a `recall` against the title just written, so duplicates and stale neighbours surface at write time instead of piling up — the agent is told to merge them and `forget` the leftovers.
- **Only `local` is writable.** `remember` and `forget` refuse ids from installed packages and say why; shared records are dependency content that `exp sync` would restore anyway.

## Concepts

### Record

One Markdown file with YAML frontmatter, under `.xp/local/` (yours, git-tracked) or `.xp/share/<pkg>/` (installed, git-ignored):

```markdown
---
index: create stripe subscription
description: Know which helper to call and which webhook confirms the charge
tags: []
---

# create stripe subscription

Call `billing.subscribe(customer, plan)` — never the Stripe SDK directly.

## Confirming the charge

...
```

Titles follow `[action] [package|entity] [subject?]` — `create stripe subscription`, `define new cli subcommand`, `downgrade alembic migration` — so queries and titles speak the same language. One topic per file; 5–20 focused records beat one huge dump.

### Convention

A record flagged `convention: true`: a single short paragraph stating one rule (naming, structure, which tool or skill to use) plus its rationale. Conventions are searched separately and rendered **in full** on every matching recall, no `expand` needed — which is how a project rule gets *followed* instead of merely found.

### Workbook

A record flagged `workbook: true`: a package's guide, written by `exp fuse` — the table of contents plus the end-to-end flow of executing a task with that package (*read this, then that, then decide*), linking its records by file name so the agent follows them with `read`. One per package, and it never competes in search: it surfaces collapsed in a `<guides>` block whenever any record of its package matched, so the flow is offered exactly when the package becomes relevant.

### Index

`index.npy` + `index.json`. Exactly one vector per Markdown-heading breadcrumb (`Stripe API > Webhooks > Error Handling`), searched by cosine similarity with a relevance floor so agents never wade through noise. Results are grouped by package and labelled with its description — from `leaxp.toml` for `local`, from the install manifest for shared packages.

Record ids are row numbers, and **rows never move**: rewriting a record reuses its rows, forgetting one tombstones them. An id an agent recalled keeps pointing at the same record until the next full reindex.

### `.xp` file

A zip of record Markdown plus a sha256-signed manifest (`xp_version`, name, version, digest, record counts). Portable and model-agnostic — embeddings are recomputed locally on install.

### Dependency

A `[[packages]]` entry in `leaxp.toml` (what you *declare*) resolved into a `leaxp.lock` entry (what is *installed*: version, exact ref, digest). `exp sync` installs whatever is missing or drifted at the locked version; `--upgrade` re-resolves each unpinned package.

Skill repos have no versioning convention, so a GitHub package's version is its newest release tag (`v1.2.3`) when it publishes one, and the default branch's commit sha otherwise. Pin a specific one with `/tree/<ref>` in the source or `version = "…"` in `leaxp.toml` — `--upgrade` leaves pins alone.

### Wiring

`exp use` writes `.mcp.json` and `.claude/settings.json` with the **absolute launcher of the environment it ran in** (`<venv>/bin/exp mcp`, or `<python> -m leaxp mcp` when no console script exists). A bare `exp` would only work for a global install, since your coding agent runs outside the project's virtualenv.

That makes the wiring machine-specific: after cloning, run `exp use` once in your own environment — it repoints a stale command instead of adding a second one.

## What lives where

```
your-project/
├── leaxp.toml                 # what you declare: project meta, models, packages
├── leaxp.lock                 # what is installed: version, exact ref, digest
├── .mcp.json                  # MCP wiring (absolute launcher) — written by `exp use`
└── .xp/
    ├── .gitignore             # written by `exp use` — tracks local/, ignores everything else
    ├── local/                 # your records — git-tracked, editable, the only writable package
    │   └── create-stripe-subscription.md
    ├── share/                 # installed packages — git-ignored, read-only
    │   └── org-repo/
    ├── index.npy              # one vector per heading breadcrumb
    ├── index.json             # record metadata + package descriptions
    ├── .sessions/             # once-per-session hook markers
    ├── consolidation-*.md     # one review log per `exp forge` run
    └── fusion-*.md            # one review log per `exp fuse` run
```

`exp fuse` also stages the package it is building in `.xp/temp/`, and removes that folder once it has replaced `.xp/local/`.

## Command reference

| Command | What it does |
| --- | --- |
| `exp use --with claude` | Create `.xp/`, config and lock; wire the MCP server + prompt hook. |
| `exp learn [--goal …] [--agent …]` | Drive your agent CLI over the codebase into `.xp/local/`, then index. |
| `exp forge [--agent …]` | Consolidate `.xp/local/` — verify, dedupe, split conventions — then sync. |
| `exp fuse [--agent …]` | Fuse `.xp/local/` into one deduplicated, conflict-free package led by a workbook. |
| `exp share -o pkg.xp` | Pack `.xp/local/` into a shareable `.xp` archive. |
| `exp install <url\|name> [--skill …] [-U]` | Install from GitHub or the registry; index and lock it. |
| `exp install -f pkg.xp [--self]` | Install from a local archive; `--self` adopts it into `.xp/local/`. |
| `exp sync [-U]` | Install declared packages, optionally upgrade, reindex `.xp/`. |
| `exp exec "<query>" [-s …] [-n …]` | Print the raw `recall` output for a query. |
| `exp mcp [-t stdio\|http]` | Run the MCP server (your agent does this for you). |
| `exp --version` | Print the installed version. |

Every command accepts `--path` to target a project directory other than the current one.

## Docs

| Document | Contents |
| --- | --- |
| [CLAUDE.md](https://github.com/vunone/leaxp/blob/main/CLAUDE.md) | Package architecture overview — modules, data flow, key abstractions |
| [AGENTS.md](https://github.com/vunone/leaxp/blob/main/AGENTS.md) | Ground rules for coding agents working on this repo |
| [CHANGELOG.md](https://github.com/vunone/leaxp/blob/main/CHANGELOG.md) | Per-version release notes |
| [RELEASING.md](https://github.com/vunone/leaxp/blob/main/RELEASING.md) | How a new version gets published |

## Development

```bash
uv sync                                  # create venv, install deps
uv run pre-commit install                # enable hooks
uv run ruff check . && uv run pyright    # lint + typecheck (pyright strict)
uv run pytest --cov                      # tests with coverage (100% gate)
uv run exp --help
```

## License

Apache-2.0 — see [LICENSE.txt](https://github.com/vunone/leaxp/blob/main/LICENSE.txt).
