First Five Minutes.
Two ways to get an Axon backed by Hugging Face wired to a Dendrite and talking across a local Synapse. Core builds it by hand, one file at a time, so you see every wire. Genesis builds the same thing on a canvas. No Docker. No running broker. Just pip install and a few minutes.
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.
Python 3.11+. The cosmo CLI ships with the Python package - run it from your virtualenv.
# Python 3.11+
pip install cosmonapse httpxInit, 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
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) ────────────────────────────────────────────────
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"])
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.
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())
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.
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)
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
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.