The eight steps below build a working Axon + Dendrite round-trip entirely by hand, so you see every wire before anything writes code for you. If you'd rather place components on a canvas and let Genesis generate the same files, switch to the .

Python 3.11+

The cosmo CLI ships inside the cosmonapse package - one install gets you both.

An HF token

Free at huggingface.co/settings/tokens. Swap the source= for openai, anthropic or ollama if you'd rather use those.

Three terminals

One for the Synapse, one for the worker Dendrite, one for the HTTP server. Nothing needs Docker.

01 · Install

Python 3.11+. The cosmo CLI ships with the Python package - run it from your virtualenv.

# Python 3.11+
pip install cosmonapse httpx
02 · Scaffold, then code

Init, scaffold, then code. cosmo init writes the standard package skeleton every example follows - config.py, neurons/, effector/, brain.py, demo.py - with a working Axon + Dendrite round-trip and one tool call. The steps below build the same thing by hand so you can see every wire; when you code your own project, new Neuron modules go under neurons/, tool families under effector/, and the wiring stays in brain.py.

$ cosmo init my-app -n quickstart

  Scaffolded my-app in ./my-app
    + config.py   + neurons/hello.py   + effector/tools.py
    + brain.py    + demo.py            + README.md

$ cd my-app
$ python demo.py   # one process, in-process bus - no setup
03 · Start a Synapse

cosmo synapse start memory boots a local TCP+NDJSON broker - no Docker, no NATS, no Postgres. Swap the URL for nats:// or kafka:// when you move to production - the rest of your code stays the same.

$ cosmo synapse start memory --namespace=quickstart

  URL:        cosmo://127.0.0.1:7070
  Namespace:  quickstart
  Transport:  TCP + NDJSON  (single-host dev only)
  ────────────────────────────────────────────────
04 · Build an Axon

Two steps, the lower-level way: Neuron(source="huggingface", ...) returns a pure async callable, and Axon(neuron_id=..., neuron_fn=...) gives it an identity on the bus. The Axon validates the Neuron's raw output into a Signal; the Neuron itself never sees the protocol. The one-call factory Axon.huggingface() - and .openai(), .anthropic(), .ollama(), .mcp() - is shorthand for exactly this. Set HF_TOKEN to your Hugging Face access token before running.

import os
from cosmonapse import Axon, Neuron

# Lower level, two steps. Neuron(source=...) is a pure async callable;
# the Axon gives it an identity and validates its output into a Signal.
neuron = Neuron(source="huggingface",
    endpoint="https://router.huggingface.co",
    model="meta-llama/Llama-3.1-8B-Instruct",
    api_key=os.environ["HF_TOKEN"], use_chat_api=True)

axon = Axon(neuron_id="llama", neuron_fn=neuron,
    capabilities=["chat"])
05 · Wire a Dendrite

The Dendrite is the only component that touches the Synapse - it hosts the Axon, emits REGISTER / HEARTBEAT / DEREGISTER, and routes inbound TASKs. Run this in a second terminal; it registers and waits for tasks.

worker.py
import asyncio, os
from cosmonapse import Axon, Dendrite, Neuron, connect_synapse

# Build the Neuron, then wire it into an Axon (the two-step, lower-level form).
# role="worker": hosts Axons, replies to TASKs, cannot dispatch TASKs.
neuron = Neuron(source="huggingface",
    endpoint="https://router.huggingface.co",
    model="meta-llama/Llama-3.1-8B-Instruct",
    api_key=os.environ["HF_TOKEN"], use_chat_api=True)
axon = Axon(neuron_id="llama", neuron_fn=neuron, capabilities=["chat"])

async def main():
    synapse = await connect_synapse("cosmo://127.0.0.1:7070")
    worker  = Dendrite(synapse=synapse, namespace="quickstart", role="worker")
    worker.attach_axon(axon)
    async with worker:
        await asyncio.sleep(float("inf"))  # serve until Ctrl-C

asyncio.run(main())
06 · Connect an HTTP interface

A role="orchestrator" Dendrite has no Axon - its job is to dispatch tasks and collect results. Keep your web framework at the edge and dispatch TASK Signals from route handlers via the orchestrator Dendrite. Install Flask with pip install flask.

app.py
import asyncio, threading
from flask import Flask, jsonify, request
from cosmonapse import Dendrite, connect_synapse

# asyncio loop in a background thread  -  Flask stays synchronous.
loop = asyncio.new_event_loop()
threading.Thread(target=loop.run_forever, daemon=True).start()
orch: Dendrite = None

async def setup():
    global orch
    synapse = await connect_synapse("cosmo://127.0.0.1:7070")
    orch = Dendrite(synapse=synapse, namespace="quickstart", role="orchestrator")
    await orch.start()

asyncio.run_coroutine_threadsafe(setup(), loop).result(timeout=10)
app = Flask(__name__)

@app.post("/task")
def submit():
    # dispatch_and_wait: emit a TASK, await the first terminal Signal,
    # close the Pathway, return the Signal. No manual future plumbing.
    fut = asyncio.run_coroutine_threadsafe(
        orch.dispatch_and_wait(neuron="llama",
                               input=request.get_json(), timeout_s=30.0),
        loop,
    )
    reply = fut.result(timeout=32)
    return jsonify(reply.payload["output"])

app.run(port=5000)
07 · Watch the Signals flow

Attach a Doppler to see every Signal as it crosses the Synapse. It is a passive read-only subscriber - it never competes with Dendrites for messages.

$ cosmo prism --tail --url=cosmo://127.0.0.1:7070 -n quickstart

  REGISTER      neuron=llama  capabilities=['chat']
  TASK          trace=trc_01...  neuron=llama
  AGENT_OUTPUT  trace=trc_01...  neuron=llama

# filter to specific signal types
$ cosmo prism --tail -n quickstart --type TASK --type AGENT_OUTPUT

# or open Prism  -  the live browser visualization (http://127.0.0.1:7071)
$ cosmo prism --url=cosmo://127.0.0.1:7070 -n quickstart
08 · Test it

With the synapse, worker, and server all running, send a task:

$ curl -s -X POST http://localhost:5000/task \
       -H "Content-Type: application/json" \
       -d '{"prompt": "Say hello to Cosmonapse."}'

{"response": "Hello! Great to meet you, Cosmonapse..."}

Watch the Doppler terminal - you'll see the full REGISTER → TASK → AGENT_OUTPUT trace as it happens.