PRIMAL

The reliability and interoperability layer for AI agents.

$pip install primal-ai
Star on GitHub

Apache 2.0 · Python 3.11+ · zero runtime dependencies · 268 tests

Seven composable pillars

Use one or all eight. They share four small, named bridges at the package root and otherwise stand alone.

Guardian

Policy enforcement. Wrap any callable with pre/post checks that gate dangerous actions, redact PII, cap dollar cost, rate-limit calls, and validate schemas.

agent = Guardian.wrap(my_agent, policies=["rate_limit:per_minute=60"])

Trajectory

Structured black-box recorder for every agent execution. Captures inputs, tool calls, LLM calls, errors, and inter-agent handoffs. JSON-serializable, replayable.

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 PASS / FAIL / UNCERTAIN with confidence and reasons.

verdict = Verifier.audit(tr, layers=[JSONSchemaVerifier(schema=...)])

Conductor

Agent-to-agent orchestration. Capability-based registry, single-hop delegation, linear pipelines, EventBus. AgentCard maps 1:1 to A2A v1.0.

Conductor.register_agent(my_agent_instance)

Atlas

Smart routing across providers. Health-aware filtering, exponential-backoff cascade, optional Thompson / UCB1 bandit selection that learns from outcomes.

name, result = Atlas.invoke("task", context={"capability": "chat"})

Storage

Pluggable persistence behind one Protocol. InMemory for tests; SQLite (WAL, JSON, thread-safe) for production. Postgres + Redis reserved for Phase 2.

with SQLiteStorage("primal.db") as store: tr.save(store)

Harness

Runtime substrate: health monitoring, tool registry, interval scheduler. Opt-in startup so importing the package never spawns a background thread.

Harness.register_tool(ToolInfo(name="search", tags=("web",)))

Continuity

Portable user profile with source + confidence metadata, three merge strategies, BYO autolearn for extracting facts from text via your model.

Continuity.update("user-k", "language", "en", store=store)

Drop into your agent stack

One file. Seven pillars composing. Runs end-to-end against fake agents — no API keys, no network.

quickstart.py
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)

Composable, not monolithic

Seven pillars compose through four small, named bridges at the package root. No pillar reaches into another's internals.

PRIMAL architecture: pillars compose via neutral primitivesSeven pillars on top connect through four shared neutral primitives (default_bus, current_trajectory, _jsonschema, StepKind enum) to the pluggable Storage Protocol below.GuardianTrajectoryVerifierConductorAtlasHarnessContinuity_eventsdefault_bus_trajectory_contextcurrent_trajectory_jsonschemavalidateStepKind / EventKindenumsStorage ProtocolInMemory · SQLite · Postgres / Redis (Phase 2)

Cross-pillar communication routes through the four red-dashed primitives only. A pillar can be tested in isolation; new pillars plug into the same surfaces.

268 testsmypy --strictzero depsApache 2.0Python 3.11+A2A AgentCard precursorMCP bridge (Phase 2.5)

Why PRIMAL?

Composable

Seven pillars compose through four small named bridges at the package root. No pillar reaches into another's internals. Use Guardian alone. Use the full stack. Add a pillar later. Nothing forces an all-or-nothing decision.

Observable

Guardian, Trajectory, and Verifier give every agent action a recorded, replayable, audited trail. Failures land as structured outcomes — DelegationResult, RoutingDecision, Verdict — not raised exceptions that break calling code.

No lock-in

BYO LLM across Verifier, Atlas, and Continuity — supply any Callable[[str], str]. Zero runtime dependencies. Apache 2.0. Extracted from a production system, not a clean-slate experiment.

Be there for 0.2.0

PRIMAL is shipping fast. Get the email when Cloud beta opens, the A2A bridge lands, or the marketplace goes live.

No spam. Unsubscribe with one click. Apache 2.0, indie-built, no VC.