Fractal asynchronous control for distributed agent systems.
Coglet is a framework built on two primitives:
- COG (Create, Observe, Guide) — slow, reflective supervisor
- LET (Listen, Enact, Transmit) — fast, reactive executor
Every Coglet is both: a LET under its parent COG, and a COG over its children. This forms a recursive temporal hierarchy where layers share a uniform interface and differ only in cadence and scope.
src/coglet/ # Framework
coglet.py # Base class + @listen/@enact/transmit decorators
channel.py # Async pub/sub channel bus
handle.py # CogletHandle, CogBase, Command
runtime.py # CogletRuntime — boots and manages Coglet trees
lifelet.py # LifeLet mixin — on_start/on_stop lifecycle
ticklet.py # TickLet mixin — @every periodic scheduling
proglet.py # ProgLet mixin — unified program table with executors
llm_executor.py # LLMExecutor — multi-turn LLM conversations
gitlet.py # GitLet mixin — repo-as-policy with git patches
loglet.py # LogLet mixin — separate log stream
mullet.py # MulLet mixin — fan-out N children behind one handle
suppresslet.py # SuppressLet mixin — COG-controlled output gating
weblet.py # WebLet mixin — register with CogWeb UI for visualization
src/cogweb/ # CogWeb graph visualization UI
ui/
server.py # FastAPI + WebSocket server
static/
index.html # Interactive SVG graph frontend
cogames/ # CvC (Cogs vs Clips) game player
cvc/
cvc_policy.py # PolicyCoglet: LLM brain + Python heuristic
policy/
anthropic_pilot.py # CogletAgentPolicy — optimized per-agent heuristic
semantic_cog.py # Base semantic policy from cogora (~1300 lines)
helpers/ # Geometry, resources, targeting, types
coach.py # Coach: orchestrates games, maintains changelog
player.py # PlayerCoglet: GitLet COG over PolicyCoglets
gamelet.py # GameLet: bridge to cogames CLI
setup_policy.py # Tournament sandbox setup (installs anthropic SDK)
docs/ # Architecture design docs
coglet.md # COG/LET primitives, communication model, mixins
tournament.md # Tournament system hierarchy and pseudocode
# Start the runtime
coglet runtime start
# Create coglets from .cog directories
coglet create examples/counter.cog # -> counter-a3f1
coglet create examples/doubler.cog # -> doubler-b2c4
coglet create examples/printer.cog # -> printer-d5e6
# List a coglet's channels
coglet link counter-a3f1 # shows transmit + listen channels
# Wire channels together (id:channel syntax)
coglet link counter-a3f1:count doubler-b2c4:count
coglet link doubler-b2c4:doubled printer-d5e6:doubled
# Push data directly into a channel
coglet transmit doubler-b2c4:count 42
# Subscribe to channel output
coglet observe printer-d5e6:log --follow
# Send @enact command
coglet enact printer-d5e6 reset
# Inspect
coglet links # list all wires
coglet runtime status # tree + coglets + channels + links
# Tear down
coglet unlink counter-a3f1:count doubler-b2c4:count
coglet stop counter-a3f1
coglet runtime stopThe runtime exposes a FastAPI server (default port 4510):
POST /create?cog_dir=PATH spawn coglet, returns id
POST /stop/{id} stop a coglet
POST /transmit/{id}/{channel}?data=... push data into a channel
POST /enact/{id}?command=...&data=... send @enact command
GET /observe/{id}/{channel} SSE stream of channel events
POST /link?src_id=...&src_channel=... wire channels
&dest_id=...&dest_channel=...
DELETE /link (same params) remove wire
GET /links list all wires
GET /channels/{id} list coglet's channels
GET /status tree + coglets + links
GET /tree ASCII tree
POST /shutdown stop everything
The runtime serves an MCP endpoint at /mcp. Connect any MCP client
(Claude Code, etc.) to http://localhost:4510/mcp to use all API
endpoints as tools.
Run a .cog directory directly without the daemon:
coglet run examples/multi.cog --trace events.jsonlfrom coglet import Coglet, LifeLet, TickLet, CogBase, every, listen, enact
from coglet.runtime import CogletRuntime
class MyCoglet(Coglet, LifeLet, TickLet):
async def on_start(self):
print("started")
@listen("obs")
async def handle_obs(self, data):
await self.transmit("action", self.decide(data))
@enact("reload")
async def reload(self, config):
self.load(config)
@every(10, "s")
async def heartbeat(self):
await self.transmit("status", "alive")
# Boot
runtime = CogletRuntime()
handle = await runtime.run(CogBase(cls=MyCoglet))cogames play -m machina_1 -p class=cvc.cvc_policy.CogletPolicy -c 8 --seed 42cogames upload -p class=cvc.cvc_policy.CogletPolicy -n coglet-v0 \
-f cvc -f mettagrid_sdk -f setup_policy.py \
--setup-script setup_policy.py --season beta-cvcSee docs/coglet.md for the full architecture design.
| Decorator | Plane | Purpose |
|---|---|---|
@listen(channel) |
Data | Handle messages from a named channel |
@enact(command_type) |
Control | Handle commands from supervising COG |
transmit(channel, data) |
Output | Push results outbound |
| Method | Purpose |
|---|---|
create(config) |
Spawn a child Coglet |
observe(handle, channel) |
Subscribe to a child's transmit stream |
guide(handle, command) |
Send a command to a child (fire-and-forget) |
| Mixin | Purpose |
|---|---|
| LifeLet | on_start() / on_stop() lifecycle hooks |
| TickLet | @every(interval, unit) periodic scheduling |
| ProgLet | Unified program table with pluggable executors |
| GitLet | Repo-as-policy — patches applied as git commits |
| LogLet | Separate log stream from transmit stream |
| MulLet | Fan-out N identical children with map/reduce |
| SuppressLet | COG-controlled output gating (subsumption) |
| WebLet | Register with CogWeb UI for graph visualization |
Coach (Claude Code session — NOT a Coglet)
├── Runs games via cogames CLI
├── Reads learnings from PolicyCoglet
├── Maintains changelog (coach_log.jsonl)
└── Commits improvements to repo
PlayerCoglet (GitLet COG)
└── Manages PolicyCoglets across games
└── Reads learnings, accumulates experience
PolicyCoglet (CogletPolicy)
├── Python heuristic (CogletAgentPolicy) — handles every step
├── LLM brain (Claude) — analyzes ~14x per episode
└── Writes learnings to disk on episode end
CogWeb provides a browser-based UI for visualizing live coglet supervision trees.
Add WebLet to any coglet and pass a shared CogWebRegistry:
from coglet import Coglet, CogBase, CogletRuntime, LifeLet
from coglet.weblet import CogWebRegistry, WebLet
from cogweb.ui import CogWebUI
class Supervisor(Coglet, WebLet, LifeLet):
async def on_start(self):
await super().on_start()
await self.create(CogBase(cls=Worker, kwargs={"cogweb": self._cogweb}))
class Worker(Coglet, WebLet, LifeLet):
pass
# Boot
registry = CogWebRegistry()
ui = CogWebUI(registry, port=8787)
rt = CogletRuntime()
await ui.start()
await rt.spawn(CogBase(cls=Supervisor, kwargs={"cogweb": registry}))
# Open http://localhost:8787- Live graph — nodes auto-register on start, deregister on stop
- Hierarchical layout — parent COGs above, child LETs below
- Interactive — pan, zoom, drag nodes, click to inspect
- Inspector panel — shows class, mixins, @listen/@enact handlers, channels, children, restart config
- WebSocket updates — graph refreshes automatically as coglets start/stop
- REST API —
GET /api/graphreturns JSON snapshot
Use CogWebRegistry standalone for programmatic introspection:
registry = CogWebRegistry()
# ... spawn WebLet-enabled coglets ...
snap = registry.snapshot()
print(snap.to_dict()) # {"nodes": {...}, "edges": [...]}CvC runs 10,000 steps per episode with 8 agents per team. Only 5 actions exist: noop + 4 cardinal moves. All interactions happen through movement (walking into extractors, junctions, enemies). Score = aligned junctions held per tick.
The Python heuristic handles fast-path decisions (role assignment, pathfinding, resource gathering, junction alignment). The LLM brain runs every ~500-1000 steps to analyze strategy and log insights. The Coach reads these post-game and commits code improvements.