🐺 PRIMAL
The reliability and interoperability layer for AI agents.
PRIMAL (primal-ai) wraps any AI agent with the seven things production
agents need but rarely have: policy enforcement, structured recording,
output verification, multi-agent orchestration, smart routing, durable
persistence, and portable user memory. Zero runtime dependencies. A2A
AgentCard precursor shape. MCP bridge surface ready for Phase 2.5.
Install
pip install primal-ai
Requires Python 3.11+. No other runtime dependencies — PRIMAL ships stdlib-only.
60-second example
The example below uses all seven pillars + Storage in a single flow: wrap an agent with Guardian, make it discoverable to Conductor + Atlas + Harness, then record, persist, audit, and remember in one durable loop. It runs end-to-end against fake agents — no API keys, no network.
from primal_ai import (
Atlas, BYOProvider, ProviderInfo, ThompsonBandit,
Conductor, AgentCard, Capability,
Continuity, Guardian, Harness,
JSONSchemaVerifier, ToolInfo, Trajectory, Verifier,
)
from primal_ai.storage import SQLiteStorage
# 1. Any callable becomes an agent — wrap it with Guardian's policies.
def search_agent(query: str) -> dict:
return {"answer": f"results for {query!r}"}
agent = Guardian.wrap(search_agent, policies=["no_external_network", "max_cost:$0.10/req"])
# 2. Make the agent + tools + providers discoverable.
class SearchAgent:
name = "search"
card = AgentCard(name="search", description="search the web",
capabilities=(Capability(name="search", description="..."),))
def invoke(self, q): return search_agent(q)
Conductor.register_agent(SearchAgent())
Harness.register_tool(ToolInfo(name="search", description="search the web", tags=("web",)))
Atlas.register_provider(BYOProvider(
name="echo",
call=lambda task, **kw: f"OK: {task}",
info=ProviderInfo(name="echo", capabilities=("chat",)),
))
Atlas.set_selector(ThompsonBandit(seed=42)) # opt-in: learn from outcomes
# 3. Record, persist, audit, remember.
with SQLiteStorage("primal.db") as store:
with Trajectory.record(agent_id="search") as tr:
tr.record_input({"query": "flights to tokyo"})
tr.record_output(agent("Find flights to Tokyo under $800"))
tr.save(store)
verdict = Verifier.audit(tr, layers=[
JSONSchemaVerifier(schema={"type": "object", "required": ["answer"]}),
])
print("verdict:", verdict["status"]) # PASS
Continuity.update("user-k", "language", "en", source="user", store=store)
The seven pillars (plus Storage)
Guardian — Policy enforcement. Wraps any callable with pre/post checks
that gate dangerous actions, redact PII, cap dollar cost, rate-limit
calls, and validate input/output schemas. Composes via AllOf /
AnyOf and is configurable via a compact string DSL. Violations route
through a pluggable escalation handler.
agent = Guardian.wrap(my_agent, policies=["rate_limit:per_minute=60", "max_cost:$0.10/req"])
Trajectory — Structured "black box recorder" for every agent execution. Captures inputs, outputs, tool calls, LLM calls, errors, retries, and inter-agent handoffs into a JSON-serializable record. Replay, filter by step kind, or persist via the Storage Protocol.
with Trajectory.record(agent_id="search") as tr:
result = agent(query)
Verifier — Three-layer audit framework: rule-based, BYO LLM-judge,
and domain-specific. Returns a Verdict(PASS | FAIL | UNCERTAIN) with
confidence + reasons. JSONSchemaVerifier and RegexMatchVerifier ship
built-in; BYOLLMJudge is the LLM surface (you supply the model call).
verdict = Verifier.audit(tr, layers=[JSONSchemaVerifier(schema=...)])
Conductor — Agent-to-agent orchestration. Capability-based agent registry, single-hop delegation with REFUSED/FAILED/TIMEOUT outcomes, linear pipelines, and a sync pub/sub EventBus. AgentCard field names are chosen so a Phase 2.5 serializer maps 1:1 to A2A v1.0.
Conductor.register_agent(my_agent_instance)
Atlas — Smart routing across providers (your wired-up models, APIs, or local agents). Provider Protocol, BYOProvider, capability/tag-based discovery, health-aware filtering, exponential-backoff cascade. Opt into bandit-driven selection (Thompson sampling or UCB1) when you want learning; deterministic routing stays the default.
name, result = Atlas.invoke("task", context={"capability": "chat"})
Storage — Pluggable persistence behind one Protocol. InMemory for tests; SQLite for production (WAL mode, JSON values, thread-safe per connection, strict at the boundary). Postgres + Redis stubs reserved for Phase 2. The Protocol is what every pillar persists through.
with SQLiteStorage("primal.db") as store: tr.save(store)
Harness — Runtime substrate: health monitoring, tool registry (substring + tag, no embeddings), and an interval-based scheduler. Opt-in startup so importing the package never spawns a background thread.
Harness.register_tool(ToolInfo(name="search", description="...", tags=("web",)))
Continuity — Portable user profile with explicit source + confidence
metadata, three merge strategies (self / other / higher_confidence),
and BYO autolearn for extracting facts from text via your model. Storage-
backed persistence.
profile = Continuity.update("user-k", "language", "en", source="user", store=store)
Architecture
The seven pillars compose through small, named neutral primitives at the package root — no pillar reaches into another's internals:
primal_ai/
├── _events.py # shared EventBus + default_bus singleton (Conductor + Atlas + Harness + Continuity publish here)
├── _trajectory_context.py # ContextVar bridge — Trajectory sets, Conductor + Atlas read
├── _jsonschema.py # shared subset validator (Guardian SchemaValidator + Verifier JSONSchemaVerifier)
├── guardian/ ← policy enforcement
├── trajectory/ ← causal recording
├── verifier/ ← output audit
├── conductor/ ← multi-agent orchestration
├── atlas/ ← provider routing
├── storage/ ← persistence
├── harness/ ← runtime substrate
└── continuity/ ← portable user memory
Three pillars expose a BYO LLM surface — BYOLLMJudge (Verifier),
BYOProvider (Atlas), BYOAutolearn (Continuity) — all using the same
Callable[[str], str] boundary. A first-party LLM caller will ship as
an optional install in Phase 2; the MVP stays dependency-free.
Why PRIMAL?
- Zero runtime dependencies. Stdlib-only. No supply chain risk, no version pin headaches.
- Extracted from a production system. Donor codebase is KARIS — 89 plugins, 700+ tools, live since March 2026. PRIMAL keeps the DNA and drops the vendor coupling.
- A2A-friendly out of the box. AgentCard, Capability, and ProviderInfo shapes are designed so a Phase 2.5 serializer can map them 1:1 to A2A v1.0 wire format without renames.
- Composable, not monolithic. Use one pillar or all eight. They share four small, named bridges at the package root and otherwise stand alone.
- Apache 2.0 licensed. Use it commercially.
Status
This is 0.1.0 — the first public release. All seven pillars shipped
as MVPs across nine focused sessions in two weeks. 268 tests passing,
mypy --strict clean, ruff check clean.
- Phase 2 (M2 — hardening) ships OTel spans, async paths, first-party LLM judges as an optional extra, cron syntax in the scheduler, embeddings-backed tool search, and bandit decay.
- Phase 2.5 ships A2A v1.0 wire format compliance and the MCP↔A2A bridge that no neutral party has built yet.
See docs/PRIMAL_ROADMAP.md for the full
plan and CHANGELOG.md for what shipped in 0.1.0.
Links
- GitHub: https://github.com/primalaiagents/primal-core
- Issues: https://github.com/primalaiagents/primal-core/issues
- Roadmap:
docs/PRIMAL_ROADMAP.md - Per-pillar roadmaps:
docs/(one file per pillar)
License
Apache 2.0 — see LICENSE.
Metadata
Release files for primal-ai 0.2.1
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| primal_ai-0.2.1.tar.gz | 132.2 kB | Without provenance | Details for primal_ai-0.2.1.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| primal_ai-0.2.1-py3-none-any.whl | Python 3 | none | any | Details for primal_ai-0.2.1-py3-none-any.whl |
Total release size: 252.7 kB
Release files / primal_ai-0.2.1.tar.gz
| Download URL | primal_ai-0.2.1.tar.gz |
|---|---|
| Size | 132.2 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
a5c90fe9397d7e1447fac3e52b69c1343833a4927d67282990aca97b4c91be5c
|
|
BLAKE2b-256 checksum How to use checksums |
0aa8085fd97bb512d9d83f3bd35a80d1db949e8caf8340bad71d8f08b9250e13
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Release files / primal_ai-0.2.1-py3-none-any.whl
| Download URL | primal_ai-0.2.1-py3-none-any.whl |
|---|---|
| Size | 120.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
31bfd36cc07b01f2d25abd4516a3d7b7bc4aa04a937b67bdda5a4ad9f2707a23
|
|
BLAKE2b-256 checksum How to use checksums |
00b3b467d38fc3820bfe77573cada929aece41fbca94af48da6cdfd955e6e9d3
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
twine/6.2.0 CPython/3.14.3
|
Security for primal-ai 0.2.1
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.
No provenance found
None of the files in this release were uploaded with provenance metadata.
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.