PersonaSpec toolkit for LLM agents
Project description
larva
larva is a PersonaSpec toolkit for LLM agent systems. It gives you one place to validate, assemble, normalize, register, resolve, clone, update, and export canonical persona definitions.
What larva is for
Use larva when you want a stable authority for agent persona definitions instead of ad hoc prompt files scattered across tools and repos.
- Validate PersonaSpec JSON before it reaches runtime
- Assemble personas from reusable components
- Store canonical personas in a local registry under
~/.larva/ - Resolve, clone, update, delete, and export personas across tools
- Project registered personas into OpenCode with a temporary wrapper config
- Expose the same operations through MCP, CLI, Python, and a small web UI
larva does not run agents, call LLMs, enforce gateway policy, or manage memory.
larva opencode is only a launcher for the real OpenCode runtime.
Install
Install into your Python environment:
pip install larva
Or run larva without a persistent install:
uvx larva --help
Quick start
The example below creates a minimal persona, validates it, stores it in the local registry, and resolves the canonical output back out.
Create a minimal persona:
cat <<'EOF' > code-reviewer.json
{
"id": "code-reviewer",
"description": "Reviews code for correctness and style",
"prompt": "You are a senior code reviewer.",
"model": "openai/gpt-5.4",
"capabilities": {"shell": "read_only"},
"spec_version": "0.1.0"
}
EOF
Validate, register, and resolve it:
larva validate code-reviewer.json
larva register code-reviewer.json
larva resolve code-reviewer
Clone and modify it for experimentation:
larva clone code-reviewer code-reviewer-exp
larva update code-reviewer-exp --set model=openai/gpt-5.4-pro
larva list --json
Core concepts
PersonaSpec
The main larva artifact is a flat JSON object called PersonaSpec.
The canonical PersonaSpec schema is defined by opifex. larva validates,
assembles, and normalizes PersonaSpec as a downstream admission and projection
layer, not the contract authority.
{
"spec_version": "0.1.0",
"id": "code-reviewer",
"description": "Reviews code changes with read-focused tooling.",
"prompt": "You are a senior code reviewer...",
"model": "openai/gpt-5.4",
"capabilities": {
"shell": "read_only",
"filesystem": "read_write"
},
"spec_digest": "sha256:..."
}
Key rules:
idis required and must be flat kebab-casespec_versionis schema identity, not persona revisioning- v1 pins
spec_versionto"0.1.0" spec_digestis recomputed by larva from canonical content- there is no inheritance or
base:field in canonical output
Components
larva can also assemble personas from reusable components stored in
~/.larva/components/:
~/.larva/
components/
prompts/
toolsets/
constraints/
models/
registry/
Example assembly command:
larva assemble --id code-reviewer \
--prompt code-reviewer \
--prompt careful-reasoning \
--toolset read-only \
--constraints strict \
--model gpt-5
Components are read from the user-managed shell boundary at
~/.larva/components/. Those files are local input, not canonical larva state;
only the assembled and validated PersonaSpec is authoritative at runtime.
Interfaces
MCP
Primary programmatic surface:
larva_validate(spec) -> ValidationReport
larva_assemble(components) -> PersonaSpec
larva_register(spec) -> {id, registered}
larva_resolve(id, overrides?) -> PersonaSpec
larva_list() -> [{id, description, spec_digest, model}]
larva_update(id, patches) -> PersonaSpec
larva_update_batch(where, patches, dry_run?) -> {items, matched, updated}
larva_clone(source_id, new_id) -> PersonaSpec
larva_delete(id) -> {id, deleted}
larva_clear(confirm) -> {cleared, count}
larva_export(all?, ids?) -> [PersonaSpec, ...]
larva_component_list() -> {prompts, toolsets, constraints, models}
larva_component_show(type, name) -> component content
For every MCP PersonaSpec input, forbidden legacy vocabulary is tools and
side_effect_policy. Unknown top-level fields are rejected as non-canonical.
Start larva as an MCP server over stdio:
larva mcp
Or with uvx:
uvx larva mcp
If you want the packaged local web UI/runtime instead of stdio, start:
larva serve
Or with uvx:
uvx larva serve
CLI
larva validate <spec.json> [--json]
larva register <spec.json> [--json]
larva resolve <id> [--override key=value]... [--json]
larva list [--json]
larva update <id> --set key=value [--set ...] [--json]
larva clone <source-id> <new-id> [--json]
larva delete <id> [--json]
larva clear --confirm "CLEAR REGISTRY" [--json]
larva export --all [--json]
larva export --id <id> [--id <id>]... [--json]
larva assemble --id <id> [--prompt <name>]... [--toolset <name>]... [--constraints <name>]... [--model <name>] [--override key=value]... [-o output.json]
larva component list [--json]
larva component show <type>/<name> [--json]
larva doctor [--json]
larva opencode [OPENCODE_ARG ...]
larva opencode launches the real OpenCode CLI with a temporary dynamic config
built from the larva registry. Arguments after opencode are forwarded to
OpenCode; a leading -- is optional and is stripped before forwarding.
Repo-local CI gate
Source basis:
design/opifex-frozen-authority-packet.jsonopifex/design/final-canonical-contract.mdopifex/design/cross-repo-followup-packet.mdopifex/contracts/persona_spec.schema.jsonopifex/conformance/shared_surfaces.yamlopifex/conformance/case_matrix/larva/*
Trusted repo-local commands:
uv run pytest -q tests/shell/test_repo_local_ci_gate.py
uv run python scripts/ci/larva_repo_local_gate.py expected-red --opifex-root ../opifex
uv run python scripts/ci/larva_repo_local_gate.py verify --opifex-root ../opifex
These checks are intentionally opifex-authoritative. They fail closed on:
- floating or mismatched frozen
opifexauthority refs - canonical PersonaSpec schema mirror drift
- capabilities-only admission drift as derived from
opifexshared_surfaces+case_matrixauthority (capabilitiesrequired;toolsandside_effect_policyforbidden) - authority-derived shared MCP surface drift, including missing shared tool registration
- dotted or non-
snake_caseMCP tool naming - repo-facing docs drift away from shared naming and invalid-field wording
Python API
from larva.shell.python_api import (
assemble,
clear,
clone,
component_list,
component_show,
delete,
export_all,
export_ids,
list,
register,
resolve,
update,
validate,
)
The Python API mirrors the main CLI and MCP operations and returns the same canonical PersonaSpec shapes.
The package root is not the authoritative Python API surface. Keep imports on
larva.shell.python_api; larva.__init__ remains metadata-only (__version__)
unless guard policy and architecture docs are updated together.
Other surfaces
Web UI
The authoritative packaged startup path is:
larva serve
larva serve binds 127.0.0.1:7400 by default, accepts --port and
--no-open, and serves the packaged single-file UI plus the normative REST
surface documented in INTERFACES.md.
The repository also includes a supported contributor convenience entrypoint for local review work:
pip install fastapi uvicorn
python contrib/web/server.py
Scope note:
larva serveis the canonical packaged web runtime users should targetpython contrib/web/server.pyis supported for contributor/local-review use, not the canonical packaged entrypoint- documented REST endpoints are the verified contract surface
- the prompt copy button is documented only as browser convenience UI behavior
- batch update is documented only for the contrib runtime, not for
larva serve - component query semantics are shared across transports and should be centralized outside adapter-local envelopes
- CLI, MCP, Web, and Python API keep their own rendering, error envelopes, and runtime hooks
- preserved runnable liveness proof for both entrypoints lives in
tests/shell/artifacts/web_runtime_liveness.md
OpenCode plugin
larva ships an OpenCode plugin plus a thin wrapper that exposes registered larva personas as OpenCode agents.
# TUI with every registry persona available as --agent <id>
larva opencode
# TUI pinned to a persona
larva opencode --agent python-senior
# Non-interactive OpenCode run
larva opencode run "check this bug" --agent python-senior
# Optional explicit separator; useful when a future larva flag could conflict
larva opencode -- run "check this bug" --agent python-senior
The wrapper injects OPENCODE_CONFIG_CONTENT for the child OpenCode process, so
personas are visible early enough for OpenCode's --agent <persona-id>
validation. It does not write .opencode/opencode.json, and it does not run
agents itself; after config assembly it execs the real opencode binary.
Plugin path resolution:
LARVA_OPENCODE_PLUGIN=/absolute/path/to/larva.ts- bundled wheel resource at
larva/shell/opencode_plugin/larva.ts - source-tree lookup for
contrib/opencode-plugin/larva.ts
See contrib/opencode-plugin/README.md for plugin internals and tool-policy
mapping.
Architecture
larva uses a strict layered structure enforced by Invar.
| Layer | Path | Role |
|---|---|---|
| Core | src/larva/core/ |
Pure logic, contracts, no I/O |
| App | src/larva/app/ |
Use-case orchestration |
| Shell | src/larva/shell/ |
CLI, MCP, filesystem, web adapters |
Structural guardrails frozen for the remediation campaign:
src/larva/shell/web.pyis the authoritative packaged REST surfacecontrib/web/server.pyis an extension consumer, not the contract ownersrc/larva/core/patch.pydotted-path patch semantics stay separate fromsrc/larva/app/facade.pydotted lookup semantics unless later evidence says otherwise
Read next
If you are just getting started, read README.md then USER_GUIDE.md.
USER_GUIDE.md- detailed human-oriented usage guideUSAGE.md- agent-oriented operational guideINTERFACES.md- public interface specificationARCHITECTURE.md- module boundaries and dependency designADR-001-spec-version-boundary.md-spec_versiondesign decisionADR-002-capability-intent-without-runtime-policy.md- capability intent modelADR-004-empty-capabilities-and-unrestricted-semantics.md- empty capability semantics and unrestricted boundary
License
AGPL-3.0-or-later
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file larva-0.4.7.tar.gz.
File metadata
- Download URL: larva-0.4.7.tar.gz
- Upload date:
- Size: 921.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
898f0dbd28a468c328db9e8d26f31c09fa42f8e57c98eb6d923b3c6896a28503
|
|
| MD5 |
dd66ec021bc5c77da26670f4f8320772
|
|
| BLAKE2b-256 |
ade807fa1b47c3f5419c9c44b4a114ccfd70fa1d1fe4703e7ebbaad54a6c174c
|
Provenance
The following attestation bundles were made for larva-0.4.7.tar.gz:
Publisher:
publish.yml on Tefx/larva
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
larva-0.4.7.tar.gz -
Subject digest:
898f0dbd28a468c328db9e8d26f31c09fa42f8e57c98eb6d923b3c6896a28503 - Sigstore transparency entry: 1429476265
- Sigstore integration time:
-
Permalink:
Tefx/larva@e5a38f3400ae1d672dcc6c43d3eb7ce10c31e257 -
Branch / Tag:
refs/tags/v0.4.7 - Owner: https://github.com/Tefx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e5a38f3400ae1d672dcc6c43d3eb7ce10c31e257 -
Trigger Event:
release
-
Statement type:
File details
Details for the file larva-0.4.7-py3-none-any.whl.
File metadata
- Download URL: larva-0.4.7-py3-none-any.whl
- Upload date:
- Size: 126.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? Yes
- Uploaded via: twine/6.1.0 CPython/3.13.12
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
2d5f8b4b6a29b523a58a4316918a88e6b21018a9f78b9ab7dbcfe8132eeade74
|
|
| MD5 |
fa0322e1277097b99af91f816d3cd5b7
|
|
| BLAKE2b-256 |
7ac0ad91825000a9fdcccfbe9f00fe8ac96c61d8ad503728524a1df4cb10fef4
|
Provenance
The following attestation bundles were made for larva-0.4.7-py3-none-any.whl:
Publisher:
publish.yml on Tefx/larva
-
Statement:
-
Statement type:
https://in-toto.io/Statement/v1 -
Predicate type:
https://docs.pypi.org/attestations/publish/v1 -
Subject name:
larva-0.4.7-py3-none-any.whl -
Subject digest:
2d5f8b4b6a29b523a58a4316918a88e6b21018a9f78b9ab7dbcfe8132eeade74 - Sigstore transparency entry: 1429476282
- Sigstore integration time:
-
Permalink:
Tefx/larva@e5a38f3400ae1d672dcc6c43d3eb7ce10c31e257 -
Branch / Tag:
refs/tags/v0.4.7 - Owner: https://github.com/Tefx
-
Access:
public
-
Token Issuer:
https://token.actions.githubusercontent.com -
Runner Environment:
github-hosted -
Publication workflow:
publish.yml@e5a38f3400ae1d672dcc6c43d3eb7ce10c31e257 -
Trigger Event:
release
-
Statement type: