Skip to main content
Loss of provenance

A previous release had provenance metadata, but this release does not. View details.

livespec

PyPI Python 3.10+ License: AGPL v3 Tests

Public beta (v0.33). Local-first code intelligence for AI agents. Call graph, impact analysis, and Spec ↔ code traceability. Search is FTS5-only (no embeddings). Dead/legacy findings are graph evidence, not production traffic — confirm with APM/logs before deleting. Spec and docs mutation tools are plugin-gated. Pin: uvx livespec@0.33.0.

License: GNU AGPL v3 (AGPL-3.0-only). If you modify livespec and offer it over a network (MCP host, SaaS, internal API), you must provide the corresponding source under the same license. Corporate adoption notes and a first-contact compliance template: docs/AGPL_COMPLIANCE_CONTACT.md.

Code intelligence for AI agents — call graph, impact analysis, and bidirectional Spec ↔ code traceability (functional requirements, ADRs, NFRs, and other spec kinds). Local-first, zero external services at query time (tree-sitter grammars are fetched once on first index — see Stack).

livespec ui — every indexed project, grouped by polyrepo group, with languages, symbols, Specs and coverage

livespec ui — one local, read-only page over every project you have indexed, grouped by polyrepo group.

Who this is for / not for

For Not for
Agents cold-opening an unfamiliar repo “Delete all unused code” without APM/logs
Impact analysis before a refactor or PR Deep semantic search (vectors removed in 0.29)
Spec ↔ code / OpenSpec traceability Indexing a parent folder of many unrelated repos
Polyrepo HTTP flows via group_db Replacing tests, human review, or runtime debugging

Ships as a Claude Code plugin bundling three things: the MCP server (the tools), a specialized subagent, and a preloaded Skill (the operating manual). Everything an agent sees — the plugin, subagent, Skill, and MCP tool namespace — is livespec. The PyPI distribution and console command are also livespec (uvx livespec@0.33.0 / pip install livespec). The legacy command alias livespec-mcp still works on the same entry point.

Battle-tested on real codebases. Four releases of compounding wins on the same Django 5.1.4 queries:

Tool on Django (40K symbols) v0.8 v0.9 v0.10 v0.14
find_dead_code candidates 824 514 348 344 (−58% cumulative)
find_endpoints(framework='django') 20 162 (+8×) 162 162
quick_orient p95 ~60 ms ~60 ms ~60 ms ~60 ms
Partial reindex (touch 1 file, Django) — ~7 s — 1.4 s

Validated across 5 distinct agent profiles (exploration, refactor, Spec flow, Django bugfix, TypeScript feature) — see docs/AGENT_USAGE_DATA.md.

Want the agentic flow without reading further?

30-second tour

# Wire as an MCP server next to your editor (claude.ai/code, Cursor, ...).
# Every tool call carries workspace="/abs/path" — one server, N repos.
uvx livespec@0.33.0
# alias still works: livespec-mcp
// First call: cold-index the workspace once
> index_project()
{ "files_total": 2898, "symbols_total": 39789, "edges_total": 465179,
  "languages": {"python": 2786, "javascript": 112}, "watcher_started": false }

// Composite first-contact on an unfamiliar symbol
> quick_orient(qname="django.contrib.auth.middleware.AuthenticationMiddleware.process_request")
{ "kind": "method", "is_entry_point": false,
  "callers_count": 56, "callees_count": 3,
  "top_callees": [
    {"qualified_name": "django.contrib.auth.middleware.get_user", "pagerank": 0.000024},
    {"qualified_name": "django.utils.functional.SimpleLazyObject", "pagerank": 0.000209},
    {"qualified_name": "django.core.exceptions.ImproperlyConfigured", "pagerank": 0.000872}
  ],
  "specs": [] }

// Wider blast radius on a Spec-active codebase
> analyze_impact(target_type="spec", target="auth-user-login")
{ "spec_id": "auth-user-login", "implementing_symbols": [...],
  "dependent_specs": ["auth-session-rotation", "auth-audit-trail"],
  "impacted_callers": [...] }

Built for the questions an agent asks on an unfamiliar codebase:

  • ¿Qué código implementa la requirement auth-user-login?
  • Si modifico auth.verify, ¿qué Specs y qué llamadores se ven afectados?
  • ¿Qué módulos no tienen ningún Spec asociado?
  • ¿Qué Specs dependen de auth-user-login transitivamente?
  • Do my frontend, backend and database schemas agree?
  • What breaks in the other repos if I rename this field?

Spec traceability is the differentiator. Most code-intel tools stop at "what calls this function?". livespec layers Spec ↔ code links (functional requirements, ADRs, NFRs, and other kinds) on top so an agent on a serious-software-shop codebase can answer "changing this function affects auth-user-login, auth-session-rotation and 3 dependent Specs" in one round-trip. Spec agentic tools ship in the default surface; Spec mutation/management tools live in the livespec-spec plugin. Plugins register at boot (multi-tenant: every workspace= has its own DB), but PluginVisibilityMiddleware hides mutation/doc tools from tools/list until that workspace has spec/doc rows — or you set LIVESPEC_PLUGINS=spec / =all in MCP config.

What "living" actually means here

Layer Lives How
Symbol index ✅ xxh3 content-hash incremental, run index_project on demand
Call graph + edges ✅ re-resolved on every change; persistent symbol_ref
Spec ↔ code links ✅ auto-scan of @spec: annotations after every index_project
Spec ↔ Spec graph ✅ explicit, cycle-checked; link_spec_dependency (plugin)
Drift detection ✅ body_hash + signature_hash on every symbol; list_docs(only_stale=True) (plugin)
Generated docs content ❌ on-demand generate_docs (plugin) needs an LLM-capable caller or an MCP host that supports sampling. Drift is detected, not fixed.

So: traceability is live, docs are not. If your workflow is "give me an agent that always knows which code implements which spec, and which tests probably break when X changes" — this is exactly what the project is good at. If you wanted "writes my doc comments while I sleep" — not yet.

Stack

  • FastMCP 3.x (stdio transport; fastmcp>=3,<4)
  • SQLite (single docs.db file, ACID, WAL, explicit migration framework)
  • tree-sitter + tree-sitter-language-pack for multi-language parsing
  • Python ast for high-precision Python extraction
  • NetworkX for call graph and topological impact analysis (cached per index run)

Zero external services at query time, zero API keys, ever. One caveat worth stating plainly: tree-sitter-language-pack 1.x downloads each grammar from GitHub on first use rather than bundling them in the wheel, so the first index on a fresh machine needs network access for the non-Python languages (Python itself uses the stdlib ast and never needs one). After that, indexing is fully offline.

For an air-gapped box, a Docker image or a CI runner without egress, prefetch them once:

livespec grammars            # download the 9 grammars livespec extracts
livespec grammars --check    # report what is cached; exit 1 if any is missing

If a grammar cannot be loaded, index_project skips those files and says so in languages_failed, and deliberately leaves them unindexed so the next run retries. It never records a file as having zero symbols when it was never read — that used to make every symbol in an unreadable language look like dead code.

Language support

Honest table — only languages with a passing test suite are claimed.

Language Status What's covered
Python ✅ Tested Functions, classes, methods, decorators, calls — uses ast for full precision. Imports drive scoped resolution (P0.4).
Go ✅ Tested Functions, struct types via type_spec, struct methods, calls. Scoped resolution via import + alias (P1.A2 v0.4).
Java ✅ Tested Classes, methods, calls (method_invocation)
JavaScript ✅ Tested Function declarations, arrow functions assigned to const/let, classes, methods. Scoped resolution via ES6 import and CommonJS require (P1.A1 v0.4).
TypeScript ✅ Tested Same as JS plus typed signatures (.ts and .tsx). Scoped resolution via ES6 import (P1.A1 v0.4).
Rust ✅ Tested Free functions, struct/enum types, impl block methods as Type::method, traits. Scoped resolution via use declarations (P4.A3 v0.5).
Ruby ✅ Tested def, class, module, singleton_method, calls. Best-effort scoped resolution via require_relative + receiver field (P1.A4 v0.4).
PHP ✅ Tested Classes, methods, function/method/scoped call expressions. Best-effort scoped resolution via use Namespace\X for Class::method() (P1.A4 v0.4); instance-method calls are not scoped.
C, C++, C#, Kotlin, Swift, Scala ⚠️ Untested The generic tree-sitter extractor will attempt to parse these (they're listed in EXT_LANGUAGE) but no test suite covers them. Symbol coverage may be partial — open an issue with a fixture if you need a specific language hardened.

The extractor is a heuristic over hardcoded tree-sitter node types (_DEF_NODE_TYPES, _CALL_NODE_TYPES in extractors.py); it intentionally trades completeness for simplicity. Use the per-language tests in tests/test_extractors.py as the contract.

Install

uv venv --python 3.12
uv pip install -e ".[dev]"

Behind a TLS-intercepting proxy, set SSL_CERT_FILE (or REQUESTS_CA_BUNDLE) to the proxy's CA: livespec fetches the tree-sitter grammars itself when the grammar pack's own downloader rejects that CA, and index_project reports parser_errors with a fix instead of indexing 0 symbols.

Run as MCP server

uvx livespec@0.33.0   # preferred — PyPI distribution name is `livespec`
livespec              # after `pip install livespec` / `uv tool install livespec`
livespec-mcp          # console alias of the same entry point

The product, package, and primary command are livespec (pip install livespec, uvx livespec@0.33.0). The livespec-mcp command remains as a back-compat alias only.

Every tool call requires workspace="/abs/path" (no cwd or env fallback since v0.12). Persistent state lives in <workspace>/.mcp-docs/docs.db.

Headless CLI (v0.14)

The same indexing pipeline without an MCP host — for cron, systemd timers, pre-commit hooks, CI:

livespec index /path/to/repo [--force]                 # JSON stats to stdout
livespec status /path/to/repo                          # index status JSON
livespec grammars [--check] [lang ...]                 # prefetch tree-sitter grammars

Claude Code / Cursor wiring

Claude Code plugin — published in the rixmerz owner marketplace:

claude plugin marketplace add Rixmerz/claude-plugins
claude plugin install livespec@rixmerz

Update with:

claude plugin marketplace update rixmerz
claude plugin update livespec

A plugin update takes effect on restart. To install from a clone instead, run claude plugin marketplace add <path-to-clone> and claude plugin install livespec@livespec-dev — a clone registers under its own name so it cannot displace the published index.

Or wire the MCP server directly in Cursor / Claude (local checkout or uvx):

{
  "mcpServers": {
    "livespec": {
      "command": "uv",
      "args": ["--directory", "/path/to/livespec", "run", "livespec-mcp"]
    }
  }
}

Multi-repo: pass workspace="/abs/path/to/project" on every tool call (required). No LIVESPEC_WORKSPACE — switching repos is only a different workspace= value. The server caches up to 8 workspaces (LRU); no MCP restart.

Keep the index fresh (Claude Code hook)

The watcher (index_project(watch=True)) works but is a race trap when multiple agents write concurrently. For single-user Claude Code sessions a PostToolUse hook is simpler and exact — re-index incrementally after every file edit (hash-skip makes no-op runs cheap):

{
  "hooks": {
    "PostToolUse": [
      {
        "matcher": "Edit|Write|NotebookEdit",
        "hooks": [
          {
            "type": "command",
            "command": "livespec-mcp index \"$CLAUDE_PROJECT_DIR\" >/dev/null 2>&1 &"
          }
        ]
      }
    ]
  }
}

The trailing & keeps the hook non-blocking; the next tool call sees a fresh index.

Browse every indexed project — livespec ui

livespec ui                 # → livespec ui: http://127.0.0.1:<random port>/
livespec ui --port 8765 --open
livespec ui --add /path/to/repo   # register an index made before the registry existed
livespec ui --list                # print the registry as JSON

One local web server (stdlib, bound to 127.0.0.1, random free port unless --port) over every project you have indexed, read from the database — no export step, no build step, and nothing written into any repository:

  • Home — all projects grouped by polyrepo group (repos sharing a [workspace] group_db are one group) plus the ungrouped ones; toggle to a flat list. Per project: languages, symbols, Specs, Spec coverage (the audit_coverage numbers, never recorded as a trend snapshot), last indexed.
  • Project — Specs by capability with coverage, symbol search, Spec detail (scenarios, implementing symbols at file:line, dependencies both ways), endpoints, and a symbol's call-graph neighbourhood (who calls it / what it calls).
  • Group — the repos in one group DB, cross-repo Specs (xrepo-* or any id mirrored in more than one repo) and resolved HTTP route hops.

Where the list comes from: every index_project / livespec index records the workspace in a user-level registry — $LIVESPEC_HOME/registry.json, else $XDG_DATA_HOME/livespec/registry.json, else ~/.livespec/registry.json. An entry whose index is gone is shown as missing with a Forget action; it is never pruned silently. Each project's index is opened with SQLite mode=ro (immutable when no writer has it open, so not even -shm/-wal files appear). In Claude Code, /livespec-ui starts it in the background and gives you the URL.

Workflows — livespec + OpenSpec

OpenSpec is a spec-driven-development framework: you author the intent (requirements + scenarios) in an openspec/ tree before writing code. livespec is the code-graph and traceability layer beneath it — it does not replace OpenSpec authoring; it links those specs to the code that implements them and keeps the link live. Since v0.22 livespec reads and writes the OpenSpec format (round-trip).

The pieces you invoke (Claude Code plugin):

Invocation What it is When
/livespec-onboard <path> slash command → delegates to the subagent (cold open) start on any repo
/livespec-ui slash command → starts livespec ui in the background, reports the URL browse every indexed project
livespec subagent specialized agent, preloads the Skill heavy exploration / spec work
/openspec_workflow MCP prompt: the sync → trace → validate → export loop a repo with openspec/
/onboard_project, /extract_specs_from_module, /audit_spec_coverage MCP prompts brownfield

The one rule: every tool takes workspace="/abs/repo/root" (no cwd/env fallback).

Case 1 — New project from scratch (spec-first)

Intent leads (OpenSpec); livespec ties code↔spec as you build.

  1. Author capabilities as specs — openspec/specs/<capability>/spec.md with ## Purpose / ### Requirement: / #### Scenario: (WHEN/THEN). Ask the livespec subagent to draft them.
  2. Ingest + gate the design before coding — sync_openspec() → validate_openspec(strict=True) (mirrors openspec validate --strict: every requirement needs ≥1 scenario).
  3. Implement feature by feature, linking code with link_scenario_symbol / bulk_link_spec_symbols (and @spec: when the store id is annotation-friendly); run index_project() after each batch.
  4. Trace tests to individual scenarios — link_scenario_symbol(spec_id, scenario_name, symbol_qname, relation="tests").
  5. Track coverage live — audit_coverage() and get_spec_implementation(spec_id) (per-scenario verified flag).
  6. Behaviour changes = an OpenSpec change — author openspec/changes/<name>/, then sync_openspec() → apply_spec_change(name, dry_run=True) → apply_spec_change(name) → archive_spec_change(name).
  7. Before a PR — git_diff_impact(base, head); cite spec ids.

Shortcut: /openspec_workflow loads this whole loop.

Case 2 — Undocumented project (brownfield)

livespec reverse-engineers the structure; you curate specs as OpenSpec (preferred authoring SSoT) and livespec keeps the links live.

  1. Onboard — /livespec-onboard /abs/path (subagent runs index_project → get_project_overview → list_specs).
  2. Understand the shape — quick_orient, who_calls, find_endpoints, find_dead_code.
  3. Propose specs from the code — propose_specs_from_codebase() + scan_docstrings_for_spec_hints; per-module /extract_specs_from_module <module>.
  4. Curate + persist as OpenSpec (human in the loop) — write openspec/specs/<capability>/spec.md (### Requirement: + #### Scenario:) then sync_openspec() / import_specs_from_markdown(..., fmt="openspec"). Or create_spec(...) with an OpenSpec slug id.
  5. Link code↔spec — bulk_link_spec_symbols / link_scenario_symbol, or @spec: annotations when ids are annotation-friendly; re-index_project.
  6. Audit + iterate — /audit_spec_coverage (orphan specs, uncovered modules).
  7. Validate the OpenSpec tree — validate_openspec(strict=True). If you started from DB-only rows, export_openspec() once then treat openspec/ as SSoT going forward (do not re-sync_openspec that export blindly — see Skill).

In one line each: new → OpenSpec defines the contract, validate_openspec gates it, you build with live links; brownfield → /livespec-onboard orients, propose_specs_from_codebase reconstructs intent, author OpenSpec first (export only as a bootstrap dump).

Tools (56 total: 41 core + 12 Spec plugin + 3 docs plugin)

Every tool requires workspace (absolute project root). Pass it on each call; omitting it is an error (no env fallback). LRU cache (8 workspaces) — one MCP server, many projects, no restart.

Menu (v0.19): plugins register at boot but PluginVisibilityMiddleware hides Spec mutation / doc tools from tools/list until the workspace has spec / doc rows, or you set LIVESPEC_PLUGINS. import_specs_from_markdown and sync_openspec stay always visible (brownfield bootstrap). After the first workspace= call on a repo with Specs, the menu grows to 53 tools (56 with doc rows). Reconnect the MCP host if your client cached an old tool list.

Default surface — code intel + Spec agentic (41)

These tools answer the questions an agent ASKS on an unfamiliar codebase. Always registered (including markdown Spec import + OpenSpec sync).

Indexing (2)

  • index_project(force=False, watch=False) — walk, parse, persist. Also rebuilds search chunks idempotently. Respects .gitignore (root + nested, negations included) on top of the built-in ignore list (v0.14). Records the workspace in the user-level registry livespec ui reads (outside the repo). Read the project://index/status resource for current status (the legacy get_index_status tool was dropped in v0.9).

    Optional per-repo tuning via .livespec.toml at the workspace root (v0.14) — config patterns outrank .gitignore:

    [index]
    ignore = ["assets/", "*.min.js"]      # gitignore syntax, "!" re-includes
    languages = ["python", "typescript"]  # allow-list; absent = all 9
    max_file_bytes = 2000000              # skip files larger than this
    
    [specs]
    # OpenSpec tree re-synced after every index_project
    openspec_dir = "openspec"
    # Optional extra OpenSpec markdown (### Requirement: only):
    # sync_from = ["docs/extra-requirements.md"]
    links_seed = "docs/requirements/livespec-spec-links.json"  # optional bulk_link seed
    
    [graph]
    # External code graph (Graphify). Corroborating evidence for
    # find_dead_code / find_orphan_tests, community grouping for Spec
    # proposals, and the default source for ingest_external_graph.
    # Never a source of SYMBOLS — those stay livespec's, always. Edges it
    # contributes are only ever written by an explicit ingest_external_graph
    # call, are tagged origin='external:graphify', and come back out with
    # remove=True. A graph at the default path announces itself but is not
    # used until you point at it here.
    external = "graphify-out/graph.json"
    # Re-apply the recorded ingest after an index run that changed files. Off by
    # default: an ingest writes rows into symbol_edge, and a write that happens
    # because someone saved a file is not something to opt into silently.
    auto_ingest = false
    
    [workspace]
    group_db = "../.livespec-group/docs.db"  # cross-project: several repo roots
                                             # share one DB so a Spec can link
                                             # symbols across repos (each keeps
                                             # its own project_id). Absent = the
                                             # per-repo .mcp-docs/docs.db.
    
  • ingest_external_graph(graph_path=None, dry_run=True, remove=False, relations=None) — add a second extractor's edges to the call graph (v0.33). Reads a Graphify graph.json and writes the dependency edges livespec's resolver missed into symbol_edge, tagged origin='external:graphify'. Where corroborate_with can only remove dead-code candidates, these are real edges: who_calls, who_does_this_call, analyze_impact and find_dead_code all see them, and label them.

    Measured on livespec itself against a code-only Graphify run of its own tree (3564 nodes, 6089 edges, 0 LLM tokens): 1394 of 1593 symbols matched a node, 1250 calls edges already agreed (95%), and 165 edges livespec lacked were added — 63 calls, 2 indirect_call, 83 uses, 17 references. who_calls(ExternalNode) went from 1 caller to 5: the four methods that take it as a type annotation, which livespec does not model.

    Three guarantees: no symbol is ever created (both endpoints must already be livespec symbols); reversible and idempotent (remove=True deletes exactly its own rows; every apply rewrites rather than accumulates); and dry_run=True by default, so the first call reports what it would add.

    An ingested reference is not a caller. who_calls counts invocation edges only, so a type-position use or an inheritance edge is reported under excluded_by_edge_type rather than inflating the caller list — measured on this repo, one class went from 2 callers to 40 before this, and 38 of the 40 were parameter annotations. Pass edge_types=["calls","references"] to include them, or use analyze_impact, which counts every dependency.

    It remembers what it read (migration 23): the graph path, its content hash and the time. Every graph-reading tool's external_edges block reports stale when a re-extract cascaded rows away, the file changed, or it is gone. [graph] auto_ingest = true re-applies it after an index that changed files. Over a [workspace] group_db it maps across every project in the group, so a graphify merge-graphs output contributes cross-repo edges — surfaced as cross_repo_callers / cross_repo_callees, since the per-project call graph cannot hold an edge whose ends are in two repos. Import relations (imports, imports_from, re_exports) are available via relations= but off by default — who_calls does not distinguish edge types, so ingesting them would make importers read as callers. On this repo they add zero edges anyway: Graphify hangs them off per-file nodes, which never map to a livespec symbol. Re-run after any index_project that changed files — it reports external_edges_stale when a re-extract invalidated ingested rows.

Search (1, v0.12; vectors removed)

  • search(query, scope='all'|'code'|'specs', limit=20) — FTS5 keyword retrieval over AST-aware chunks of symbols + Specs (splits snake_case into OR tokens). Use when you want "code that talks about X" without an exact symbol-name match. Dense-vector / sqlite-vec / embed_chunks were removed — keyword search is the only lane.

Code intelligence (14)

  • find_symbol(query, kind, limit) — separator-agnostic name lookup.
  • read_unit(qname, depth=1, token_budget=2000) — contract closure: body + callee signatures + the definitions of the types in them + what it raises
    • which tests cover it. The unit an agent needs to change one symbol, without paying for the file layout around it. Reports unresolved_types (real gaps) separately from external_types (things a dependency owns), and declares budget.degraded when callees were dropped to fit.
  • debt_baseline_capture(reset=False) / debt_baseline_status() — freeze today's duplication as accepted debt so search_similar reports only what is new. Run once at install; without it, a legacy repo lights up everywhere and the check gets switched off before it ever catches a fresh duplicate.
  • search_similar(code, threshold=0.80) — "does this already exist?" before writing a helper. Level 0 matches a structural copy with every identifier renamed; level 1 matches a near-duplicate that was edited after pasting. Fingerprints are cached by body hash (764 ms → 19 ms on this repo).
  • resolve_location(path, line) — inverse lookup: which symbol owns a stack-trace line. Returns the innermost symbol, its enclosing scopes, and the read_unit call to make next.
  • get_symbol_source(qname) — body slice only (lighter than full info).
  • who_calls(qname, max_depth=1) — backward cone, slim agentic alias. Adds route_callers when the symbol is an HTTP endpoint that a frontend calls over a route (cross-repo via group_db) — "I changed this endpoint, what frontend breaks?".
  • who_does_this_call(qname, max_depth=1) — forward-direction counterpart. Adds invokes_endpoints: backend routes this symbol hits via fetch/axios/requests.
  • quick_orient(qname) — composite snapshot: metadata + docstring lead + top-5 callers/callees by PageRank + linked Specs + entry-point flag. Replaces 3-4 calls with one when an agent first lands on a symbol.
  • analyze_impact(target_type, target, max_depth) — symbol/file/Spec blast radius. max_depth=1 covers the old "find references" use case.
  • get_project_overview(include_infrastructure=False) — top symbols by PageRank; infra noise filtered by default.
  • git_diff_impact(base_ref='HEAD~1', head_ref='HEAD', max_depth=5) — changed files → impacted callers → affected Specs → suggested test files. PR-review entry point. (v0.33) changed_symbols is symbol-precise: only what the range added, modified (normalised body hash) or removed, not every symbol of a touched file (a Deno Fresh app's 39-file commit: 274 → 25). (v0.34) When the range changes a schema bound with @schema:, the payload gains schema_impact (see Schemas below) and counts.schema_entities; otherwise it is unchanged. affected_specs are reached through code; spec_definitions_changed lists the requirements whose own text the range added, modified or removed under openspec/specs/ (read from git).
  • find_dead_code(include_infrastructure=False, corroborate_with=None) — symbols with zero callers and zero Spec links. Skips entry-point paths, framework decorators, __main__ guards, list-stored callbacks. filtered_out reports what each default filter excluded, keyed by the flag that would include it — two runs on the same repo can differ several-fold purely by flags. Corroboration: point corroborate_with at a Graphify graph.json and candidates a second extractor still sees referenced are dropped. livespec's blind spots are systematic — no inheritance edge, no type-position usage, some cross-file calls lost by the resolver — and each manufactures a false "dead". Across 13 repos it cut 382 candidates to 264 (helped in 11 of them; median 50% where it helped), and spot-checked drops were genuine misses. Graphify's code pass is tree-sitter with no LLM, so this costs nothing in determinism; see docs/COMPETITIVE_GRAPHIFY.md. Corroboration and ingest_external_graph are complementary, not alternatives: corroboration asks the broader "does anything refer to this?" (so imports counts) and writes nothing; ingestion adds the dependency edges to the graph so every other tool sees them too.
  • find_legacy_flows(project?, include_infra_routes=False) — likely-unused HTTP flows (route_ref + invokes_route, best with group_db): servers with no indexed client hop + clients with no matched server. Graph only — confirm with traffic before deleting.
  • find_orphan_tests(max_depth=10, corroborate_with=None) — test functions whose forward cone never reaches a non-test symbol. Only what a runner collects is a candidate (pytest test*, Go TestX, @Test, a function passed to test(/it(); helpers in test files are counted in test_helper_symbols_skipped, never reported. corroborate_with drops tests a Graphify graph sees reaching production (a Java service went 17 → 9; livespec's own suite went 26 → 26, because its in-process harness is a blind spot both extractors share — corroboration only helps where blind spots differ).
  • find_endpoints(framework=None) — framework entry points. Decorator markers (framework ∈ {flask, fastapi, click, pytest, fastmcp, celery, django, spring, angular}), filesystem routing ({nextjs, fresh, sveltekit, remix}), Django CBV bases, and call-style routing (Express + Hono — both included in the default sweep when framework=None; pass framework='express'|'hono' to filter). (v0.19) FastAPI/Flask decorators also yield http_method + http_path in MCP payloads and the livespec ui endpoints view. Default sweep excludes tests/** and @pytest.fixture handlers (use framework='pytest' for fixtures).
  • grep_in_indexed_files(pattern, path_glob?, kind?, limit=50) — search only files present in the index (avoids node_modules / .venv).
  • audit_coverage() — Spec coverage report: modules without direct Spec, modules implicitly covered (transitively reached), modules truly orphan, modules in languages whose annotation extractor isn't wired yet (modules_unsupported_language), Specs without implementation, Specs with low avg confidence. (v0.16) Also reports auto-derived per-Spec test coverage (spec_coverage, avg_test_coverage, specs_with_derived_test_coverage): an implementing symbol counts as tested when a test's forward call-cone reaches it (depth 3) or an explicit relation='tests' link exists — so Spec test-coverage works with no hand-linking for projects whose tests call the code directly. livespec ui renders this as a per-Spec test coverage meter with its coverage_source.

Spec agentic — query + bootstrap (5)

  • bulk_link_spec_symbols(mappings) — batch-link N (spec_id, symbol_qname) pairs in one transaction. Escape hatch for files/languages where the in-source annotation extractor doesn't reach (configs, SQL, YAML). Idempotent: re-linking an existing pair is a no-op. Test symbols must be functions (tests.pkg.test_mod.test_fn), not modules (tests.pkg.test_mod).
  • import_specs_from_markdown(path, fmt="openspec") — bulk-create/update Specs from OpenSpec (Fission-AI) ### Requirement: / #### Scenario: markdown — point path at a single file or at an openspec/ directory to walk its tree. The former native ## SPEC-NNN: catalog is removed. Always visible; warns on duplicate Spec headings; idempotent.
  • list_specs(status, module, priority, kind, has_implementation) — Spec discovery surface.
  • get_spec_implementation(spec_id) — answers "¿qué código implementa auth-user-login?".
  • propose_specs_from_codebase(module_depth=2, min_symbols_per_group=3, max_proposals=30, skip_already_covered=True) — heuristic Spec discovery on a Spec-empty repo. Groups symbols by module + PageRank, proposes Spec candidates with humanized title + suggested_symbols.

OpenSpec interop — round-trip + change lifecycle (5, v0.22)

Make livespec a first-class citizen of an OpenSpec openspec/ repo. Scenarios (#### Scenario: WHEN/THEN) are first-class rows since v0.22 — get_spec_implementation returns them (with per-scenario linked symbols + a verified flag) and list_specs counts them. Link code/tests to an individual scenario with link_scenario_symbol (Spec plugin).

  • sync_openspec(openspec_dir?) — import an entire OpenSpec tree in one call: canonical requirements from specs/ and every change under changes/ (proposed) / archive/ (archived); reads openspec.json. Always visible (bootstrap). For a single file use import_specs_from_markdown.
  • export_openspec(out_dir="openspec", include_changes=True) — the inverse: write the DB back to specs/<capability>/spec.md (+ changes/, archive/). Closes the round-trip. Capability == the spec's module.
  • validate_openspec(strict=False) — mirror openspec validate [--strict]; the load-bearing check is every requirement MUST have ≥1 scenario.
  • list_spec_changes(status?) / get_spec_change(name) — inspect change proposals (proposal/design/tasks prose + ADD/MODIFY/REMOVE/RENAME deltas).

Annotation hygiene (1)

  • scan_annotation_verbs(sample_per_group=10) — surfaces @word: annotation-shaped comments the matcher will not link, so they stop being silently invisible to every other Spec tool. Two failure modes reported separately: unrecognized_verb (the @word isn't in the recognized vocabulary — did_you_mean suggests the nearest by edit distance) and token_shape (verb is fine, the payload isn't a linkable Spec id).

Cross-repo discovery (1, v0.31.3)

  • get_cross_repo_guide() — the polyrepo how-to (group_db, mirrored xrepo-* Specs, the livespec ui group view, traps) plus a live group snapshot, as a tool so it works on hosts that cache a stale resources/list and refuse reads for URIs missing from that cache. Same content as the project://cross-repo resource.

Tracks — the history of code ↔ spec (4, v0.33)

A track is a macro-commit: a named git range (base..head — a branch, a PR, a run of commits) plus why it exists. CHANGESPEC.md at the workspace root is its versioned source of truth — newest first, per Spec: the OpenSpec requirement deltas and the symbols the range added / modified / removed, and why. The index is derived from it and rebuilt on every index_project. livespec writes into a project in exactly two ways: CHANGESPEC.md, only on an explicit record_track call, and plan_schema_change(apply=True), only into the declaration files of apply_workspaces and only when each still hashes as indexed.

## 2026-10-18 · Gamma lands (68f903d..d67bdc8)
<!-- livespec:track id=68f903d-d67bdc8 base=<sha> head=<sha> -->
Why: ship gamma
OpenSpec: add-gamma
Also touched: core-cache, core-log <!-- livespec:touched -->

### core-beta
- Spec: MODIFIED "Beta"
- Code: + new_fn (pkg/core.py), ~ Box.open (pkg/core.py)
- Why: beta grows new_fn

Specs come in two tiers. changed: the range carries an OpenSpec delta for the Spec, or the Spec is the first id of the first @spec: / @implements: line of a symbol it changed. touched: every other Spec, reached only through shared code (secondary ids, verb-anchored mentions, link-table rows) — one marked line, no section. On a Deno Fresh app, a range with 7 requirement deltas went from 37 Specs, all with sections, to 7 changed + 30 touched.

  • propose_track(base_ref, head_ref) — draft, writes nothing: changed_specs and touched_specs (paginated, exact counts), symbols added / modified (normalised body hash — reformat-only edits do not count) / removed per Spec, OpenSpec deltas from openspec/changes/**/specs/, and code changed with no Spec (unlinked). Renamed files pair their symbols. In OpenSpec repos a Spec that did not exist yet at the range's head is never credited.
  • record_track(base_ref, head_ref, title, why, spec_reasons, include_touched_sections=False) — write the entry into CHANGESPEC.md (created if absent) and the index; the same range again updates it and keeps the whys it does not restate. A touched Spec gets a section when asked or when it has a why. Call it after the person confirmed the whys.
  • get_spec_history(spec_id) — timeline of tracks for one Spec (aliases accepted), each tier changed or touched.
  • get_symbol_history(symbol) — tracks that changed a symbol and the Specs involved; removed symbols keep their history.

Schemas — one entity, many declarations (3, v0.34)

Schemas stay where they live: a Zod schema or TypeScript types in the frontend, a Pydantic model or dataclass in the backend, a CREATE TABLE in a migration. A @schema: <entity> line binds each one to a named entity — in a Python docstring, a TS/Zod leading comment, or a -- line right above the SQL CREATE TABLE. Inside a shared [workspace] group_db the declarations of every repository of the group are compared; without one, only the repo's own.

  • schema_drift(entity=None) — compares the schemas of each entity field by field and reports missing_field, type_mismatch, nullability_mismatch and optional_mismatch, each naming every side with project, file and line. snake_case and camelCase names are one field. Types JSON carries losslessly are not mismatches (a TS string vs a UUID / datetime, a TS number vs an int, a SQL JSON column vs a nested model), optional is never judged against a SQL column (a default is not an omittable field), and a type no rule maps is counted as uncomparable. Paginated (limit, cursor, summary_only, exact counts); an unknown entity returns did_you_mean.
  • schema_impact(entity, change, field, new_name=None, new_type=None, max_depth=3) — what breaks in the other repos if I rename this field? For a proposed add, remove, rename or retype of one field, lists every declaration of the entity across the group with the action it needs (add/present, remove/absent, rename/both_present/renamed, retype/compatible) and the matched field's line, then every reader of the declarations that must change: callers through the call graph (across repos through HTTP routes), symbols bound with @schema: and symbols sharing a Spec, each with project, file, line and role (endpoint with its method and path, test, symbol). Readers are per declaration, not per field. analyze_impact does not follow schema links; this is the explicit path. Paginated like the aggregators; a hint says when type-position uses (TS types, Zod, SQL) left the call graph empty.
  • plan_schema_change(entity, change, field, new_name=None, new_type=None, optional=None, nullable=None, apply=False, apply_workspaces=None, max_depth=3) — which exact lines make this change in every repo? Call it after schema_impact. For an add, remove, rename, retype or optionality (optional / nullable) change of one field, lists every declaration of the entity across the group with a status: edit with exact line edits (file, start_line, end_line, old_text, new_text), none, manual with the reason no exact edit exists, or stale when the file changed since indexing. Names follow each side's convention (contact_email in Python and SQL, contactEmail in TS and Zod) and a Pydantic Field(alias=...) is renamed through its alias. An edited SQL table carries a PostgreSQL ALTER TABLE migration hint, text that is never written. Readers are schema_impact's. Read-only by default: apply=True, once the person agreed with the plan, writes the edits of the projects in apply_workspaces (default: this workspace), lists the rest in apply.not_applied, refuses the whole apply (nothing written) when any file it would write changed since indexing, and never re-indexes (apply.reindex lists the roots to index again). Paginated like the aggregators (readers; declarations are never paged).
  • git_diff_impact schema_impact — one entry per entity whose schema the range changed: the fields added, removed, retyped or modified (base vs head), the action each asks of the other declarations, reader counts per project with a sample of 5 each (summary_only drops it), and follow_up schema_impact(...) calls.

livespec-spec plugin — Spec mutation (12)

Visible in tools/list when the workspace DB has spec rows, or when LIVESPEC_PLUGINS includes spec. Tools an operator runs to mutate Spec state.

bulk_link_spec_symbols and import_specs_from_markdown live in the default surface (always visible) so brownfield repos can bootstrap without setting LIVESPEC_PLUGINS.

  • create_spec(title, ...), update_spec(spec_id, ...), delete_spec(spec_id) — cascade-removes spec_symbol links.
  • link_spec_symbol(spec_id, symbol_qname, relation, confidence, source, unlink) — link / unlink a single Spec↔symbol pair.
  • link_scenario_symbol(spec_id, scenario_name, symbol_qname, ...) — scenario-level traceability: link code/tests to an individual OpenSpec #### Scenario: (finer than the whole requirement). Surfaced per-scenario in get_spec_implementation (verified + linked symbols).
  • link_spec_dependency(parent_spec_id, child_spec_id, kind='requires') / unlink_spec_dependency / get_spec_dependency_graph — Spec→Spec graph. kind ∈ {requires, extends, conflicts}; cycles rejected at insert time.
  • scan_spec_annotations() — two-level matcher (@spec:auth-user-login vs. verb-anchored implements auth-user-login); auto-runs after every index_project. Ids nothing answers to come back as unknown_annotation_ids instead of being dropped.
  • scan_docstrings_for_spec_hints() — surfaces Spec candidates from existing docstrings (first sentence, leading verb). Returns verb_histogram_top for noticing dominant action verbs.
  • apply_spec_change(name, dry_run=False) / archive_spec_change(name) — OpenSpec change lifecycle: fold a change's deltas into the canonical Spec set (ADDED/MODIFIED upsert+activate, REMOVED deprecate, RENAMED moves the old requirement's traceability links onto the new name and drops the old spec), then mark it archived. dry_run=True returns the plan + applicability warnings (missing target, would-overwrite) without mutating.

Brownfield bootstrap (no Python one-liner)

index_project(workspace=...)
  → import_specs_from_markdown(path="docs/REQUISITOS_FUNCIONALES.md")
  → bulk_link_spec_symbols(mappings=[...])

Or add [specs].sync_from to .livespec.toml and run uv run python scripts/sync_livespec_specs.py /path/to/repo after editing the spec without a full re-index.

livespec-docs plugin — generated docs (3)

Visible when the workspace has doc rows or LIVESPEC_PLUGINS includes docs. Human-tier ceremony for generated Markdown docs. (The browsable view of the index is livespec ui, not a tool.)

  • generate_docs(target_type, identifier, content?, max_tokens?) — three modes: caller_supplied / sampling / needs_caller_content. Works in Claude Code (caller mode) and Cursor/Desktop (sampling mode).
  • list_docs(target_type, only_stale=False) — list or surface drifted docs (drift triggers on body_hash OR signature_hash mismatch).
  • export_documentation(format, out_subdir) — markdown or JSON.

Migrating from older versions

Removed Use instead
find_references (v0.1) analyze_impact(target_type='symbol', target=qname, max_depth=1)
get_symbol_info (v0.7) quick_orient (composite) + get_symbol_source (body)
get_call_graph (v0.7) who_calls + who_does_this_call
agent_scratch / _get / _clear (v0.29) drop — use host chat notes / Spec links
export_explorer, export_flow_explorer, index_project(explorer=) (Unreleased) livespec ui — one read-only server over every indexed project; nothing is written into the repo
livespec explorer serve, livespec fastapi init, mount_explorer / enable_explorer (Unreleased) livespec ui (/livespec-ui in Claude Code); remove the mount_explorer(app) line fastapi init appended to your app
search, rebuild_chunks (v0.7, dropped v0.8) search is back in v0.12 as FTS5 over AST-aware chunks (dense vectors removed v0.29). rebuild_chunks is now auto-run inside index_project (no separate tool). find_symbol + quick_orient still cover exact-name lookup.
list_files (v0.7) grep / ripgrep host with path glob
start_watcher / stop_watcher / watcher_status (v0.7) re-run index_project on demand (watcher race-condition trap for editing agents)
link_requirement_to_code (v0.6 alias) link_spec_symbol
link_requirements / unlink_requirements (v0.6 alias) link_spec_dependency / unlink_spec_dependency
get_requirement_dependencies (v0.6 alias) get_spec_dependency_graph
get_index_status (v0.9, deprecated in v0.8) read the project://index/status resource
list_requirements / get_requirement_implementation / create_requirement / etc. (RF nomenclature, removed v0.20 — hard cut) list_specs / get_spec_implementation / create_spec / etc.
## SPEC-NNN: native catalog / fmt="livespec" / @spec:SPEC-001 shape-match / create_spec(spec_id="SPEC-…") (removed — hard cut in 0.31.0) OpenSpec slugs under openspec/; sync_openspec / import_specs_from_markdown(..., fmt="openspec"); @spec:auth-user-login (id must exist in store)

Resources

  • project://overview
  • project://index/status
  • project://specs
  • project://specs/{spec_id}
  • project://files/{path*}
  • project://symbols/{qname*}
  • doc://symbol/{qname*}
  • doc://spec/{spec_id}
  • code://symbol/{qname*} — raw symbol source slice
  • project://schemas — @schema: entities with their schemas and drift counts
  • project://schemas/{entity} — every drift finding of one entity, unpaginated

Prompts (slash commands)

  • agent_playbook — primary agent guide: tool tiers, call patterns, @spec: commenting, brownfield Spec workflow, anti-patterns
  • onboard_project
  • analyze_change_impact
  • audit_spec_coverage
  • extract_specs_from_module
  • document_undocumented_symbols
  • refresh_stale_docs
  • explain_symbol

Performance

Numbers from the v0.8/v0.9 battle-test harness (4 sessions / 4 profiles / 65+ logged calls in docs/AGENT_USAGE_DATA.md). Cold = first run; warm = cached run on the same workspace. Latency p95 measured with the in-process middleware (src/livespec_mcp/instrumentation.py).

Repo Files / Symbols index_project cold quick_orient p95 get_project_overview p95
tiny demo app (Python) 4 / 23 ~50 ms <5 ms ~10 ms
livespec itself (Python+8 langs) 84 / 495 ~400 ms ~60 ms ~75 ms
mid-size Python CLI 130 / 1173 ~600 ms ~50 ms ~80 ms
Django (Python, stress) 2898 / 39789 ~25 s <100 ms ~250 ms
large Rust monorepo (stress) 5K / 50K ~30 s <100 ms ~300 ms

For repos > 30K symbols, pass summary_only=True on aggregator and traversal tools (audit_coverage, find_dead_code, find_orphan_tests, find_endpoints, find_legacy_flows, git_diff_impact, who_calls, who_does_this_call, analyze_impact, plan_schema_change) to keep payloads under ~200 KB. Counts stay exact regardless of pagination — see bench/run.py --large for the Django stress profile.

Django precision series (same queries, across releases)

Tool v0.8 v0.9 v0.11 v0.14 Why
find_dead_code 824 514 348 344 non-Python skip → dotted-path string refs → runtime registration → closure-capture
find_endpoints(django) 20 162 162 162 class-based view detection via inheritance from View / mixins
Partial reindex (Django, 1 file) — ~7 s — 1.4 s targeted _resolve_refs walk
index_project cold (Django) — ~148 s — 54 s (v0.14 re-run on Ryzen 7 4800H; edges 1.05M → 465K from scoped-resolution precision, DB 124 → 71 MB, RSS post-PageRank 609 → 294 MB — those three are machine-independent)

Tests

uv run pytest -q

In-memory FastMCP Client(mcp) so tests run without subprocess or network.

Agent vs human user

livespec ships two user shapes deliberately:

  • Agents see the 27-tool always-visible core (code intel + Spec agentic reads + OpenSpec interop) plus plugin tools when Specs/docs unlock them. The composite quick_orient is the canonical first-contact tool — it returns metadata, docstring lead, top callers/callees by PageRank, linked Specs, and entry-point flags in one call.
  • Humans (or operator scripts) reach for the Spec/docs plugin tools to mutate Spec state and manage docs. Auto-load happens once the DB shows real Spec or doc rows; before that, set LIVESPEC_PLUGINS=all (or =spec / =docs) to bootstrap.

Historical note: early curation dropped several tools that agents never called in battle-tests (get_symbol_info, watcher trio, …). search stayed and is FTS5-only in v0.29 — do not confuse that with the old “drop search” opinion.

Roadmap

Fase Estado Contenido
0 — Bootstrap ✅ FastMCP server, project structure
1 — Indexing ✅ tree-sitter + Python AST, file-incremental, call graph
2 — Analysis ✅ NetworkX, impact, PageRank
3 — Requirements ✅ CRUD + linking + annotation matcher
4 — RAG/Embeddings ✅ AST chunking + FTS5 (dense vectors removed; was optional sqlite-vec/RRF)
5 — Doc generation ✅ generate_docs (dual-mode), drift detect (body+signature), export
6 — Polish ✅ 7 prompts, doc:// resources, two-level @rf: matcher with negation guard
7 — v0.2 ✅ Multi-tenant state, tool consolidation 25→23, persistent refs, watcher, bench suite
8 — v0.3 ✅ Auto-scan post-index, PageRank infra filter, scoped resolution by imports, git_diff_impact, embeddings smoke real, Ruby+PHP fixtures, hypothesis property tests, memory bench, GitHub Actions CI, code:// resource, delete_requirement, markdown RF importer
9 — v0.4 ✅ Scoped resolution for TS/JS/Go/Ruby/PHP, find_dead_code / audit_coverage / find_orphan_tests, did_you_mean on Symbol-not-found errors, watcher atexit cleanup, CI venv fix
10 — v0.5 ✅ Bug fixes from real-repo demo, decorators as first-class field + find_endpoints, RF dependency graph (requires/extends/conflicts) with analyze_impact cascade, matcher multi-RF + confidence override + @not_rf: negation + golden dataset, Rust use scoped resolution
11 — v0.6 ✅ Hardening: explicit migration framework, unified error shape, RF link tools renamed, deprecated use_workspace removed, Django stress test (40K symbols), graph cache, README pitch reframe
12 — v0.7 ✅ Brownfield onboarding: propose_requirements_from_codebase, bulk_link_rf_symbols, scan_docstrings_for_rf_hints. Pagination on aggregator tools. Rust pub visibility-aware dead-code filter. find_symbol separator-agnostic
13 — v0.8 ✅ Curation pass driven by 3-session battle-test data: 4 quick-win agentic tools (quick_orient, who_calls, who_does_this_call, get_symbol_source). 11 P2 bug fixes on find_dead_code, audit_coverage, git_diff_impact, propose_requirements_from_codebase. Plugin auto-detect framework — RF mutation (11 tools) and doc management (3 tools) move into auto-loading plugins. Tier-4 drops: list_files, search, rebuild_chunks, get_call_graph, get_symbol_info, watcher trio. Default surface 39 → 17 tools
14 — v0.9 ✅ Django readiness: targeted _resolve_refs walk on partial reindex (closes v0.7 deferred). Pagination on who_calls / who_does_this_call / analyze_impact. min_weight=0.6 filter mutes resolver fan-out. Django dead-code accuracy (skip non-Python, recognize dotted-path strings + class Meta:). Django CBV detection in find_endpoints (LoginView/FormView/LoginRequiredMixin/etc.). Drop get_index_status. Default surface 17 → 16. Wire-validated: Django find_dead_code 824 → 514, find_endpoints(django) 20 → 162
15 — v0.10 ✅ Library codebase release: from .x import Y re-exports + __all__ lists protect names from find_dead_code (closes the largest remaining false-positive bucket on Django). README lift — Django numbers above the fold + 30-second tour. Battle-test session 05 against Deno Fresh (TS/TSX/JS) — 5/5 profiles covered. Wire-validated: Django find_dead_code 514 → 348 (−58% cumulative from v0.8 baseline of 824)
16 — v0.11 ✅ TS framework readiness: bundler/build dir filter (_fresh/, dist/, build/, .next/, out/, node_modules/, .svelte-kit/, target/, …), TS framework entry-point detection (Fresh islands/, Next pages/ + app/, SvelteKit routes/, Remix app/routes/), JSX element refs as call-graph edges, runtime-registration name protection (Field.register_lookup / signal.connect / add_middleware). Closes session-05 bugs #18-#20. Wire-validated: Fresh find_dead_code 974 → 0 (default), 974 → 118 (include_non_python=True); find_endpoints(fresh) returns 340 entry points; top_symbols from _fresh/ 18/20 → 0/20. Three sonnet subagents in parallel worktrees
17 — v0.12 ✅ Multi-repo workspace: workspace required on every call, one server instance serves N repos (LRU per-workspace state). RAG layer wired: index_project runs AST-aware chunking, search (FTS5 + optional sqlite-vec via RRF) + embed_chunks exposed. JSDoc extraction for TS/JS (@rf: annotations in JSDoc now scanned). bulk_link_rf_symbols promoted out of the RF plugin. Banner-comment filter. force=True preserves manual RF links
18 — v0.13 ✅ Framework coverage sprint: Spring Boot (Java annotations → endpoints + DI-aware dead-code), Angular (TS decorators, template-reachability method protection, lifecycle hooks), Hono (call-style route extraction with method+path, named-handler callback refs, module-level registration scan — also covers Express-style apps). TS decorator + Java annotation extraction (migration v8 auto re-extract). Dual-decorator alias fix: find_dead_code on livespec-mcp itself 22 → 0
19 — v0.14 ✅ Personal-fit sprint: gitignore-aware indexing (root + nested + negations via pathspec), .livespec.toml per-repo config (ignore/languages/max_file_bytes, outranks .gitignore), headless CLI (`livespec-mcp index
20 — v0.15–0.17 ✅ RF Explorer static bundle (export_explorer), derived RF test coverage + explorer meters, Changes/drill-down/trend/freshness, reproducible self-RFs (livespec-rf-links.json)
21 — v0.18 ✅ PluginVisibilityMiddleware (per-workspace tool menu, 19→33 after index). livespec-mcp explorer serve + FastAPI mount_explorer autowire. Explorer landing + Swagger API tab. Search: FTS snake_case + offline vector fallback. 342 default tests
22 — v0.19 ✅ FastAPI HTTP paths + Explorer Try-it; fastapi init; brownfield RF bootstrap (import_requirements_from_markdown always visible, [requirements].sync_from, duplicate-spec warnings); agent tools + PR RF comment CI. 368 default tests
23 — v0.20 ✅ Breaking (hard cut): RF → Spec nomenclature + taxonomy. rf/rf_symbol/rf_dependency tables renamed to spec/spec_symbol/spec_dependency with a new kind column (functional_requirement, non_functional_requirement, adr, design, constraint, epic, other); migration v11 preserves existing RF-NNN ids. @rf:/@not_rf annotations renamed to @spec:/@not_spec. All RF-prefixed tools renamed (list_requirements→list_specs, create_requirement→create_spec, etc.), livespec-rf plugin renamed to livespec-spec. No aliases — single breaking release. Followed by an 8-dimension audit whose ~50 fixes landed across six batches (packaging, storage/concurrency, domain correctness, tools, performance, docs). 403 default tests
24 — v0.23 ✅ Cross-repo route edges (route_ref, mig v14 — who_calls.route_callers / who_does_this_call.invokes_endpoints), grouped DB ([workspace] group_db), Python callback-arg edges. Full OpenSpec (Fission-AI) compatibility: scenarios first-class (migs v15/v17 spec_scenario/scenario_symbol), export_openspec round-trip, validate_openspec, change lifecycle (mig v16 spec_change/spec_change_delta; sync_openspec/apply_spec_change/archive_spec_change — RENAMED FROM/TO + dry_run/warnings, mig v18), scenario-level traceability (link_scenario_symbol), Purpose round-trip, and agent discoverability (openspec_workflow prompt). Battle-tested against the real Fission-AI/OpenSpec tree (2 layout bugs fixed). Tools 36 → 44. Rebrand: product name livespec + livespec command alias (dist/package stay livespec-mcp). Trusted-Publishing release workflow. (Supersedes the tag-only, unpublished v0.22.0.)
25 — v0.29 ✅ FTS-only search (drop vectors/embed_chunks, mig v19); find_legacy_flows; group_db symbol lookup; Tier-B noise; Express/Hono in default endpoints; demote Explorer to docs plugin + drop agent_scratch*; audit IMPROVE (propose/orphan/git_diff/JSDoc); plugin Skill+agent polyrepo/legacy-safety. 627 default tests
26 — v0.30 ✅ Explorer MCP playground (call_tool / Try it); product-only orphan KPIs; typed Explorer parameters + Cursor schema honesty (SchemaCompat + param_descriptions); OpenSpec self-tree strict-valid; harness test-credit for verified Specs; AGPL-3.0-only. 639 default tests
27 — v0.31 ✅ Breaking: native SPEC-NNN dialect removed (OpenSpec slugs only). Honest endpoints: Spring DI / Angular UI / Click / FastMCP / Celery opt-in; Go HTTP routes; Next.js pages heuristic fixed. find_dead_code excludes tests by default. Call-style route ids navigable; Spring http_method/http_path; ghost-spec retire on OpenSpec rename. 667 default tests

Contributing

Read CONTRIBUTING.md first. The short version: a green test suite is necessary but not sufficient — every change ships with before/after evidence from a real repository, and deleting a tool that the evidence cannot justify is a first-class contribution.

Metadata

Release files for livespec 0.36.0

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Loss of provenance

These files do not have provenance metadata, despite files in a prior release including this data.

We recommend further investigation before installing these files. View details.

Source distribution (sdist)

Source distribution for livespec 0.36.0
File Size Uploaded Provenance Actions
livespec-0.36.0.tar.gz 1.1 MB Without provenance Details for livespec-0.36.0.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for livespec 0.36.0
File Interpreter ABI Platform Actions
livespec-0.36.0-py3-none-any.whl Python 3 none any Details for livespec-0.36.0-py3-none-any.whl

Total release size: 1.6 MB

Release files / livespec-0.36.0.tar.gz

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL livespec-0.36.0.tar.gz
Size 1.1 MB
Tags Source
SHA-256 checksum
How to use checksums
baf78267b75c1ce10314d5c9855c3f9bfc3d224ee225af00b8c3ae0f1789d3e9
BLAKE2b-256 checksum
How to use checksums
f364776c1ed40ed69ad5b1f623825f18b788b096dadf36bd967a6a25c0a01972
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Release files / livespec-0.36.0-py3-none-any.whl

Loss of provenance

This file belongs to a release without provenance metadata, despite a prior release including this data.

We recommend further investigation before installing this file. View details.

Download URL livespec-0.36.0-py3-none-any.whl
Size 479.0 kB
Tags Python 3
SHA-256 checksum
How to use checksums
2123c4e9a830506be134793a5a817d15f4baeb23dab604c95df906b7f68af9d0
BLAKE2b-256 checksum
How to use checksums
f82ec34cf67021ea4018abc2e737f81b9100447a276b4259bf0c11b4762cc7a8
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}

Security for livespec 0.36.0

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

Loss of provenance

A previous release of these files had provenance metadata, but this release does not.

While this could reflect a routine change by the project maintainers, it may also indicate that the release files have been compromised.

Release comparison

  • Removed 0.35.0 2 files With provenance
  • Added 0.36.0 2 files Without provenance

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page