cowo
codex workflows. orchestrate many codex agents from plain python. each agent is a real codex thread — tools, sandbox, structured output — and N agents run as N threads multiplexed over one codex app-server process. fan out, pipeline, build DAGs.
from cowo import agent, parallel
caps = await parallel([(lambda c=c: agent(f"capital of {c}?")) for c in countries])
install
uv add cowo
cowo drives your codex CLI over its app-server JSON-RPC — it bundles nothing, so it runs anywhere codex runs (no platform-locked wheels). put codex on PATH, auth once:
bun install -g @openai/codex # or any codex install
codex login # or set OPENAI_API_KEY
cowo doctor
quickstart
import asyncio
from pydantic import BaseModel
from cowo import agent, parallel, spent
class Fact(BaseModel):
name: str
year: int
async def main():
pong = await agent("Reply with one word: pong")
fact = await agent("Founding year of Tokyo.", schema=Fact) # Fact(name='Tokyo', year=1457)
caps = await parallel([(lambda c=c: agent(f"Capital of {c}? one word")) for c in ("France", "Japan")])
print(pong, fact, caps, "·", spent.spent(), "tokens")
asyncio.run(main())
pass a pydantic model as schema and codex enforces it (outputSchema) — a schema'd agent cannot return malformed JSON; you get the parsed instance back.
DAGs of agents
declare the graph with airflow-style >>; it runs over a tunable concurrency limiter:
from cowo import dag, task
a = task("Analyze module A.")
b = task("Analyze module B.")
synth = task(lambda ups: f"Synthesize:\n{ups}")
[a, b] >> synth # a, b run concurrently; synth receives both results
result = dag(synth).run(concurrency=8) # drain the graph through 8 live-adjustable slots
the graph is data before it runs — inspectable, scheduled, journalable. d.concurrency = 32 mid-run to drain a big queue faster.
recursion
not a primitive — a recursive function whose leaves are agent() calls:
async def summarize(chunks):
if len(chunks) == 1:
return await agent(f"Summarize:\n{chunks[0]}")
mid = len(chunks) // 2
parts = await parallel([(lambda h=h: summarize(h)) for h in (chunks[:mid], chunks[mid:])])
return await agent("Merge:\n" + "\n".join(parts))
api
agent(prompt, *, schema, model, effort, sandbox, cwd, label) |
one ephemeral thread + one turn. schema = dict or pydantic BaseModel. sandbox=None is yolo; pass "read-only"/"workspace-write" to restrict |
session(*, model, sandbox, cwd) |
.send(prompt, schema=, effort=) — a persistent thread that remembers |
parallel(thunks) / pipeline(items, *stages) |
imperative fan-out / staged flow |
dag(*terminals).run(concurrency=N) + task + >> |
declarative agent DAG |
spent |
budget: .spent() / .remaining() / .total, summed across all agents |
run(coro) |
asyncio.run that also closes the app-server |
COWO_CONCURRENCY |
global concurrency cap (default min(16, cpu-2)) |
how it works
one codex app-server subprocess; agent() = thread/start + turn/start, events demuxed by threadId; budget summed from token-usage notifications. ~120 lines over the protocol — see client.py.
roadmap
codex ships a native actor runtime (multi_agents_v2: spawn/send/wait/close, mailboxes, supervision). v0.2 exposes it as a message-passing actor substrate — see ACTORS.md.
MIT
Metadata
Release files for cowo 0.1.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 | |
|---|---|---|---|
| cowo-0.1.1.tar.gz | 7.8 kB | Details |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Reset |
|---|---|---|---|---|
| cowo-0.1.1-py3-none-any.whl | Python 3 | none | any | Details |
Total release size: 18.0 kB
Release files / cowo-0.1.1.tar.gz
| Download URL | cowo-0.1.1.tar.gz |
|---|---|
| Size | 7.8 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
747edcaaab072f1e875743b978d13f6cb2399a9bdb51ee10161721b092b1f6bd
|
|
BLAKE2b-256 checksum How to use checksums |
b53970d4504595ef31004ab46d14b4a7cd6a560b82324a67ba44f41f7e91dffa
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|
Release files / cowo-0.1.1-py3-none-any.whl
| Download URL | cowo-0.1.1-py3-none-any.whl |
|---|---|
| Size | 10.2 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
a865d63a2ee063bd4c447755bed65fbfcfb23f57b1d2e2ebd688de57a044c5b8
|
|
BLAKE2b-256 checksum How to use checksums |
b214a6a34947f77fff184f8363c98eba3c5dca982a0d87e1ddf1b2428285bf5d
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
No |
| Uploaded via |
uv/0.11.16 {"installer":{"name":"uv","version":"0.11.16","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
|