Weaveflow architecture
An LLM is a brain. An agent is the body. The better the body, with its sensors, memory, actuators, and nervous system, the better the output of the brain. Weaveflow defines the standard anatomy of that body so any LLM can inhabit any agent, and any agent can plug into any other. USB for AI agents.
Typed input & output
Every agent exposes schema-defined ports as its public interface. Internals stay private.
Any LLM backend
Pick a brain with a "provider:model" string. No vendor API leaks into the core.
Protocol + transforms
Compatible-but-different types are bridged automatically between agents.
01 Agent anatomy
Each layer of an agent maps to a part of a body. The skin (ports) is what the outside world touches; the brain is the swappable LLM; the nervous system validates everything around it.
02 Module map
Each anatomical layer is a Python package. Files stay small (≤300 LOC) and single-purpose.
types/
The 8 primitive DataTypes, the compatibility graph, and the immutable Payload envelope.
schema/
PortSchema contracts, the fail-fast validate(), and a reference registry.
llm/
LLMAdapter ABC, a provider factory, and 6 adapters with lazy SDK imports.
memory/
Memory ABC, a bounded short-term buffer, and a long-term vector store.
guardrails/
The pre / post / on_error hook bundle (the nervous system).
agent/
BaseAgent lifecycle, the injected AgentContext, and the @agent decorator.
connection/
The protocol engine, the Router/matcher, and the transform registry.
interop/
Bridges that wrap a LangChain/CrewAI/any callable agent as a BaseAgent: duck-typed, no rewrite.
runtime/
Pipeline (series) + Parallel (fan-out/in) composition and the in-process LocalRunner with tracing.
cli/
scaffold / validate / package, dispatched via a lookup map.
errors.py · logger.py
Centralized typed errors (code + message + docs link) and an env-aware structured logger.
03 Dependency direction
Outer layers depend inward on abstractions, never outward on concretions (Dependency Inversion). No vendor SDK API crosses an adapter boundary.
cli ─┐
├─> runtime ─> connection ─> agent ─> guardrails
│ │ ├─> llm (LLMAdapter ABC) ─> adapters
│ │ └─> memory (Memory ABC)
└──────────────────────────────────> schema ─> types ─> errors
└─> logger
LLMAdapter and Memory
interfaces. Concrete providers and stores are injected, so they swap without code changes.04 Agent execution lifecycle
BaseAgent.run(payload) runs the nervous system around your handler. It is
fail-fast and never swallows exceptions.
05 Connection protocol
When agent A's output feeds agent B's input, a four-step handshake runs. Incompatible links are rejected before any LLM call.
Deterministic transforms
code↔text, structured_json→text, document→text, stream→text, all without an LLM.
Semantic transforms
text→structured_json uses the brain (extraction prompt). Fails fast if no brain is supplied.
06 Pipelines & the local runner
A Pipeline chains agents and validates every link at construction. The
LocalRunner runs a chain in-process and records a per-hop trace.
trace = await LocalRunner().simulate([cleaner, extractor], "raw input")
for hop in trace.hops: # Hop(agent, output, elapsed_ms)
print(hop.agent, hop.output.value, hop.elapsed_ms)
07 Standard data types
Interoperability depends on every port speaking these 8 primitives.
| Type | Python value | Common use |
|---|---|---|
text | str | prompts, summaries, reports |
structured_json | dict | extraction, structured output |
image | str | bytes | vision, document parsing |
code | str | code gen / review / execution |
audio | str | bytes | voice input, transcription |
document | str | bytes | document analysis, drafting |
embedding | list[float] | semantic search, RAG |
stream | iterator | live, long-form output |
08 Type compatibility graph
A source type feeds a target directly (identical) or via a transform. Anything not on an edge is incompatible and rejected at connect time.
09 Design principles
No if/elif dispatch
Providers, transforms, type checks, and CLI commands all resolve through lookup maps, so adding a case never edits existing code (Open/Closed).
Immutability by default
Payload and PortSchema are frozen. Agents and transforms return new objects instead of mutating state.
Dependency injection
Brain, memory, and logger are injected into the context: no globals, fully testable, swappable per environment.
Fail fast, never swallow
Inputs are validated at the boundary; failures raise typed errors with a code, plain-language message, and docs link.
Zero-dependency core
Provider SDKs are optional extras, imported lazily. The base install carries no runtime dependencies.
Small & SOLID
Single-responsibility modules ≤300 LOC, guard clauses over nesting, abstractions over concretions.