cogsynth
v0.14.0A Python SDK for composing many agents into one deterministic workflow — agent graphs, typed tool-calling, a shared context ledger, and an evaluation harness you run before you ship.
$ pip install cogsynth
# quickstart.py
from cogsynth import Agent, Graph
graph = Graph("research").add(
Agent("planner"), Agent("writer")
).edge("planner", "writer")
result = graph.run("Summarize the v0.14 changelog.")
print(result.output)
##Quickstart
Build a report pipeline that plans, researches, and writes. Everything below runs with a stock Python 3.11+ interpreter and your own model endpoint.
Install the package and pin a model. CogSynth is provider-agnostic: point it at whatever endpoint you already pay for.
$ pip install cogsynth
$ export COGSYNTH_MODEL="anthropic/claude-sonnet-4"
$ export ANTHROPIC_API_KEY="sk-..."
Tools are ordinary functions. The decorator derives a JSON schema from your type hints, so the model sees a strict contract instead of a prose description.
from cogsynth import Tool
@Tool
def web_search(query: str, n: int = 5) -> list[dict]:
"""Search the web and return result snippets."""
return client.search(query, limit=n) # your HTTP client here
Wire the graph. Each agent declares its role, its tools, and which node it hands off to next.
from cogsynth import Agent, Graph
from cogsynth.ledger import ContextLedger
from tools import web_search
ledger = ContextLedger(name="report-builder")
graph = (
Graph("report-builder", ledger=ledger)
.add(Agent("planner", instruction="Decompose the task into queries.", tools=[web_search]))
.add(Agent("researcher", instruction="Run the queries and record findings.", tools=[web_search]))
.add(Agent("writer", instruction="Turn findings into a tight brief."))
.edge("planner", "researcher")
.edge("researcher", "writer")
)
Run it and read the result. RunResult exposes the terminal output, the full context ledger, and per-node timings.
$ python workflow.py
# planner → 2 queries 1.2s
# researcher → 4 tool calls 2.9s
# writer → 1 draft 1.0s
result.output # → "The v0.14 release adds checkpoint/resume..."
##Concepts
CogSynth gives you six primitives. Compose them; the runtime handles scheduling, retries, and state.
Agents are nodes in a graph. Edges define control flow and data flow, so a workflow reads like a wiring diagram instead of a chat transcript.
Graph("review").add(...).edge("a", "b")
Give an agent typed tools with JSON schemas. Arguments are validated at the boundary, not pasted into a prompt and hoped for.
@Tool def search(query: str) -> list[dict]
One append-only store for shared state across agents. No hidden prompt stuffing, no recomputing what a sibling already produced.
ledger.append(kind="fact", body={...})
Run a graph against fixtures and judges. A change that moves a score fails CI before it reaches a user.
harness.evaluate(graph, fixtures)
Execution is a directed acyclic graph. Fan-out and join points are explicit, so concurrency is a property of the graph, not of your luck.
graph.edge("router", ["a", "b"])
Every node write lands in the ledger. Interrupt a run and resume it without replaying side effects.
ledger.checkpoint() → graph.resume(...)
##API reference
Five public classes cover the whole SDK. Signatures are stable across 0.x; breaking changes are announced in the changelog.
Agent
node Agent(name, instruction, *, tools=None, model=None, temperature=0.0)A single unit of work in a graph. An agent runs its instruction against the context ledger, may call its tools, and returns a message that downstream nodes read.
| param | type | description |
|---|---|---|
name | str | Unique node identifier within the graph. |
instruction | str | The system prompt for this node. Written once, evaluated on every run. |
tools | list[Tool] | Tools this agent may invoke. Defaults to none. |
model | str | None | Override the graph-level model for this node only. |
temperature | float | Sampling temperature. Defaults to 0.0 for deterministic runs. |
Graph
orchestrator Graph(name, *, ledger=None, max_parallel=8, model=None)The orchestration DAG. Methods chain so you can build the topology in one expression, or mutate it incrementally.
| method | signature | description |
|---|---|---|
add | add(agent: Agent) → Graph | Register a node. Returns self for chaining. |
edge | edge(src: str, dst: str | list[str]) → Graph | Add a directed edge. A list of destinations creates a fan-out. |
run | run(input: str, *, stream=False) → RunResult | Topologically execute the graph and return the terminal result. |
resume | resume(run_id: str) → RunResult | Continue an interrupted run from its last checkpoint. |
Tool
function Tool(fn) · @ToolWraps a plain function into a model-callable tool. The JSON schema is derived from annotations and the docstring; arguments are validated before the function runs, and failures are returned to the agent as structured errors rather than thrown into the transcript.
ContextLedger
state ContextLedger(name, *, storage=None)An append-only, queryable store of everything a run has produced. Agents read from and write to it through the SDK; you never assemble the shared context by hand.
| method | signature | description |
|---|---|---|
append | append(kind: str, body: dict, *, node: str) → Entry | Write a typed entry (fact, finding, draft, …). |
query | query(kind: str | None = None, node: str | None = None) → list[Entry] | Read entries back, filtered by type or producer. |
checkpoint | checkpoint() → str | Persist the ledger and return a run id usable by Graph.resume. |
EvaluationHarness
testing EvaluationHarness(judges: list[Judge] | None = None)Replays a graph against fixture inputs and scores each output with deterministic judges. Use it in CI; a regression in a scored behavior fails the run before the change ships.
| method | signature | description |
|---|---|---|
evaluate | evaluate(graph: Graph, fixtures: list[Fixture]) → Report | Run every fixture through the graph and score the outputs. |
##SDK
Each pattern below is a topology, not a prompt. Swap the model, keep the edges.
Research pipelines
Plan → search → synthesize. The planner emits queries, the researcher records findings in the ledger, the writer composes the brief. Deterministic handoff at every edge.
planner → researcher ⇒ writer
Support triage
Route the ticket, call a policy tool, draft the reply. A fan-out edge lets the router split to lookup and policy in parallel, then rejoin at the drafter.
router ⇒ [lookup, policy] → draft
Code review & docs
One node reviews the diff against repo rules; another regenerates the docstring contract. Both read the same ledger, so the doc change always matches the reviewed code.
review → docs
Structured extraction
Extract typed records from messy inputs with strict tool schemas. The harness scores field accuracy against fixtures, so you tune the prompt without regressing the parser.
extract → validate → emit
###Example: fan-out
A single edge may target multiple nodes. Downstream branches run in parallel and rejoin at the drafter.
from cogsynth import Agent, Graph
graph = (
Graph("support-triage")
.add(Agent("router"), Agent("lookup"), Agent("policy"), Agent("draft"))
.edge("router", ["lookup", "policy"])
.edge("lookup", "draft")
.edge("policy", "draft")
)
##Changelog
Follows Keep a Changelog. Breaking changes land in minor releases during 0.x and are called out explicitly.
| version | date | changes |
|---|---|---|
| v0.14.0 minor | 2026-08-20 |
|
| v0.13.1 patch | 2026-07-30 |
|
| v0.13.0 minor | 2026-07-14 |
|
| v0.12.0 minor | 2026-06-25 |
|
| v0.11.0 minor | 2026-06-02 |
|
| v0.10.0 initial | 2026-05-11 |
|
##Guides
Design decisions and gotchas from developing an orchestration runtime.
-
Deterministic orchestration, not chat loops
Why we model agent coordination as a graph with explicit edges instead of letting a loop talk to itself until a token budget runs out.
-
Your agent graph is a DAG (and when it isn’t)
Cycles are where state leaks. Enforcing a DAG at build time is the cheapest concurrency bug you will ever prevent.
-
The context ledger: one place for state, zero hidden prompt stuffing
How a typed, append-only store keeps shared context observable instead of silently embedded in a growing system message.
-
Testing agents with fixtures and judges
Prompt changes need CI too. A harness that replays fixtures and scores outputs turns “it feels better” into a pass/fail.
-
Tool-calling schemas that survive a model swap
Derive the schema from your type hints, not from the model’s native format. Your tools should outlive the model you happen to be using.
##Maintainers
A small team building a deterministic runtime for multi-agent Python. Six of us, one graph at a time.
Previously led orchestration infrastructure at a large cloud provider. Sets the roadmap and keeps the SDK honest about what “deterministic” means.
Distributed systems and LLM tooling. Designed the graph runtime and the append-only context ledger that every run writes through.
Owns scheduling, retries, and checkpoint/resume. Obsessed with making fan-out and joins behave the same on a laptop and in CI.
Runs the docs, the quickstart, and the API surface. If a workflow takes more than five minutes to explain, it gets rewritten.
Builds the typed tool-calling layer and the provider integrations. Makes schemas survive a model swap.
Owns the evaluation harness and the judge library. A regression that moves a score never reaches a user on her watch.
##License
cogsynth is released under the Apache-2.0 license. See the LICENSE file in the repository for the full text.