Skip to main content

agentwright

agentwright. A small set of typed, composable primitives for building, validating, and running AI agents — and a zero-daemon runtime that executes them. You describe an agent's intent; the system selects the right primitives, configures them, validates the composition against hard invariants, and gives you a runnable, auditable agent.

No framework lock-in, no training, no always-on services. Pure Python, in-process, runs offline with no API key — real LLM and database backends drop in behind the same interfaces when you want them.

pip install agentwright            # or: uv add agentwright

Quickstart — the one path that always works

from agentwright import DomainBrief, compose
from agentwright.runtime import AgentRuntime, ReasoningEngine
import asyncio

# 1. Describe intent (what, not how).
brief = DomainBrief(name="My Agent", goal="Summarize inbound leads daily.",
                    domain="sales", long_lived=True)

# 2. Compose -> a validated AgentDefinition (the OS picks + configures primitives).
definition = compose(brief, owner_id="usr_1", created_by="usr_1")
assert not definition.validation_errors      # non-empty => you described something illegal

# 3. Boot the runtime and provision exactly this agent's stores.
rt = AgentRuntime()                           # zero-daemon, all in-process, no API key
rt.instantiate(definition)

# 4. Run it.
engine = ReasoningEngine(rt)
result = asyncio.run(engine.run(definition, task="Summarize today's leads."))
print(result.output, result.stop_reason, result.cost_usd)
rt.close()

If you do nothing else, do that. Everything below is detail and variation. The full agent-facing contract is AGENTS.md.


Mental model: three layers, one direction

   YOU (an app / agent / agent system)
        │  express intent as a DomainBrief
        ▼
   Layer 2 — Domain Orchestration
        DomainBrief ─▶ select ─▶ configure ─▶ validate ─▶ register   ─▶ AgentDefinition
        │
        │  an AgentDefinition references…
        ▼
   Layer 1 — Primitives (the vocabulary)
        9 typed building blocks + a discovery/registry API
        │
        │  …which the runtime provisions + executes
        ▼
   Layer 0 — Runtime Infrastructure
        AgentRuntime (stores, vault, bus, scheduler) + ReasoningEngine (the agentic loop)

Direction of control: the AgentDefinition drives the infrastructure. Layer 0 provisions only the stores a definition's primitives declare — it never assumes. You describe needs in the brief; the layers resolve them.

The boundary object is AgentDefinition. It round-trips losslessly, so you can compose in one place and run in another:

blob = definition.model_dump_json()                      # persist / send anywhere
from agentwright import AgentDefinition
definition = AgentDefinition.model_validate_json(blob)   # load and run elsewhere

Two kinds of material: execution code vs. agent guidance

Everything above — the three layers, the primitives, the runtime — is execution code: typed, deterministic machinery that runs an agent. It is the how.

Alongside it, guide/ holds agent guidance: prose an agent reads to design itself before it builds. It is the judgment — open-ended best practice, not code:

Guide The agent uses it to decide…
agent_design_patterns.md which design pattern to run (planner-orchestrator, sequential pipeline, supervisor-worker, blackboard, critique-revision)
agent_task_decomposition_guidelines.md how to break a goal into validated, right-sized tasks
context_engineering_strategies.md what to keep in context and how to manage it over a run's lifetime

The split: agentwright/ is the vocabulary an agent executes through; guide/ is how it decides what to build. The primitives stay fixed and typed; the guidance lets the agent self-organize within them. A consuming agent is expected to pick this guidance up automatically — AGENTS.md makes it part of the contract.


The 9 primitives (Layer 1 vocabulary)

Four are always present; the rest are selected only when the brief implies them.

Primitive Always? Provides Depends on
identity ✅ Name, instructions/persona, model defaults —
reasoning_loop ✅ The agentic loop: model, iteration & cost controls identity
permission ✅ Action policy (allow / deny / require_approval) —
observability ✅ Logs / metrics / traces / export (OpenTelemetry) —
memory ⬜ document + vector + graph + universal + KV state identity
tool_connection ⬜ External tools/APIs the agent may call permission
compute ⬜ Shell / browser execution permission
trigger ⬜ schedule / webhook / email / slack / event / manual identity
generated_ui ⬜ Agent-produced UI surfaces identity

Discover them at runtime — every primitive exposes its JSON config schema:

from agentwright import catalogue, describe_primitive
catalogue()                       # [{name, version, dependencies, config_schema}, …]
describe_primitive("permission")  # one primitive, full schema

Custom primitives are first-class

The OS is extensible by design: register your own primitive and it flows through the same pipeline as the built-ins — selected, configured from its own schema, version-pinned, dependency-checked, and persisted. No fork, no per-type glue.

from agentwright import PrimitiveTemplate, register_primitive, DomainBrief, compose
from pydantic import BaseModel

class SentimentConfig(BaseModel):
    threshold: float = 0.5

register_primitive(PrimitiveTemplate(
    name="sentiment", version="1.0.0", config_model=SentimentConfig,
    dependencies=("identity",), runtime_contract=("scores text sentiment",),
))

brief = DomainBrief(name="reviews", goal="triage reviews", domain="support",
                    extra_primitives=["sentiment"],
                    custom_config={"sentiment": {"threshold": 0.8}})
defn = compose(brief, owner_id="u", created_by="u")
defn.primitives.custom["sentiment"]          # SentimentConfig(threshold=0.8)

An unsatisfied dependency is a normal validation error; an unregistered name raises. See orchestration/README.md.


Layer 0 — what's real vs. interfaced

Layer 0 is zero-daemon: everything runs in your process.

  • Real, fully tested offline: SQLite system DB, File Store, Fernet vault, Event Bus, Scheduler (cron), TinyDB document store, LMDB KV, Shell Runner, the ReasoningEngine, and in-memory implementations of every heavy store.

  • Real backends behind protocols (runtime/interfaces.py ↔ runtime/real_backends.py): each heavy service has a real adapter implementing the same protocol as its in-memory default, swappable via AgentRuntime(...). SurrealDB (universal) and Chroma (vector) test for real with no API key. Three LLM gateways — Anthropic, OpenAI, Google Gemini — plus a make_gateway(provider) router. Install only what you need:

    pip install "agentwright[anthropic,chroma,surreal]"   # pick extras
    pip install "agentwright[all]"                        # every backend
    

Bring your own backend by implementing a protocol from runtime/interfaces.py (LLMGateway, VectorStore, GraphStore, Memory, …) and passing it to AgentRuntime. That protocol set is the OS's plugin ABI.


Install (development)

Uses uv:

uv sync                 # core, offline
uv sync --extra all     # + every real backend
uv run pytest           # run the suite

Tests

uv run pytest

164 tests pass offline; 8 live-backend tests skip unless their keys/installs are present. Coverage spans the registry and dependency resolution, the selector matrix, the configurator mapping, custom-primitive composition, every composition invariant and infra gap, the SQLite instance registry, all Layer-0 runtime services, the Layer-2→Layer-1 consumer journey, cross-layer integration, and agent-archetype scenario tests that build realistic agents and run them end to end (L2→L0) — covering all nine primitives and every pattern (each trigger type, each compute backend, generated_ui, sub-agents, the full memory stack, the permission approval flow, multi-tool reasoning, and concurrent agents).


Observability

Orchestration boundaries (orchestrate.select/configure/validate/compose/register) emit OpenTelemetry spans, no-ops until a tracer provider is installed. Call agentwright.telemetry.enable_console_tracing() to print spans while debugging. Layer 0 boundaries (run start/stop, tool calls, cost) are recorded in the system DB and audit ledger.


Docs

Acknowledgments

This project stands on the teaching and generosity of others:

  • Andrew Ng, whose Agentic AI course shaped much of the thinking behind these primitives and the compose-validate-run model.
  • Andrew Lee and the team at Tasklet, for generously sharing the practices behind building an agent OS — a real source of both inspiration and concrete knowledge for this work.
  • Matt Dzaman (Stellic), whose Configurable Workflow Platform project idea helped inspire the configuration-driven, composable approach taken here.

Any mistakes or rough edges here are my own.

License

Apache-2.0.

Release files for agentwright 0.1.0

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

Source distribution (sdist)

Source distribution for agentwright 0.1.0
File Size Uploaded
agentwright-0.1.0.tar.gz 353.9 kB Details

Built distribution (wheel)

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

Total release size: 435.3 kB

Release files / agentwright-0.1.0.tar.gz

Download URL agentwright-0.1.0.tar.gz
Size 353.9 kB
Tags Source
SHA-256 checksum
How to use checksums
44076616eca27484a8d73e8a451ebd94b21a37e05dd3a759f576ae3e904a7328
BLAKE2b-256 checksum
How to use checksums
e53509c507a4593fe8cc67726fe36e22bce385d6fe5280c2a4b929b73a3b4a20
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release files / agentwright-0.1.0-py3-none-any.whl

Download URL agentwright-0.1.0-py3-none-any.whl
Size 81.4 kB
Tags Python 3
SHA-256 checksum
How to use checksums
c2f59591820cad5604cbf02266d622fddcbe160d67031019a19155d868d070aa
BLAKE2b-256 checksum
How to use checksums
115ac8ecf49dbc09c5728dfe80033cddf9e535b6a008fa02ab57547ea005f39a
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.2.0 CPython/3.11.15

Release history Release notifications | RSS feed

This release

0.1.0 This release

2 release files

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