Your Agents and Distributed Agent Language

Vibes live on in agentic.

A chat session ends and takes the work with it. An agent does not. Same vibe coding — you describe what you want and let a model build it — but the result is a folder on your disk with a name your coordinator can call tomorrow. Distributed Agent Language is what makes that difference structural: its dal toolchain scaffolds a real agent project in two commands, and everything after that is you describing the work.

How you build one — click a step

Make a folder named for the agent

Your agents live in ./my-agents/ on the host, beside your other folders — bind-mounted read-write so the agent can keep its own runtime state. The folder name is the project root COO uses, so name it like the job: my_shopper, prep_lists, lead_digger.

What this gives you

  • A home that survives image upgrades — the bundled reference agents stay inside the image, yours stay on your disk
  • A name you will use again as the capability_id

In your terminal

cd my-agents
mkdir prep_lists
cd prep_lists

Why the vibe survives

It keeps a log, not a transcript

dal init agent wires evolve.md by default — a conversation and action log the agent reads back each turn. Your session becomes its memory instead of dying with the tab.

It lives on your disk

The folder is yours, mounted into the container. Swap the COO image on the next version and your agent is still sitting there, unchanged.

It has a name that can be called

Once it has a capability_id, the coordinator invokes it by name. You never re-explain what it is — to a chat window or to a new model.

Personality can live in copy, tone, and presentation. Authority should live in explicit actions, durable files, and clear contracts.

The vibe is not dead. It is finally getting a contract.

— Vibes Live on in Agentic

Read that as build instructions and you get this page. The separation it argues for is the same one dal init hands you: your taste stays in what the agent is for and how it talks, while its authority is pinned to things you can open — a port, a health check, a route with a named input, a log of what it did. So the rest of this page is the contract, in its smallest honest form.

Making it something COO can call

The three things the scaffold does not write

dal init builds a working DAL project. It does not know about your coordinator, so you add the parts that make it invokable — this is the “and we go from there” of the flow, and it is exactly what to hand the LLM.

  1. capability.json — capability_id, a label, dispatch_kind: external_http, and a default_agent_port
  2. A POST /task route in server.dal — COO posts {"description": "…"} there, and reads GET /health to know you are up
  3. scripts/start.sh — COO lazy-starts this path; copy the shape from my-agents/README.md so the hub environment stays isolated

Pick a port first. The serve scaffold defaults to 4040 — which is COO itself. Bundled agents already hold 8092, 8094, 8095, 8098 and 8099. Choose something else (8101 is a fine start) and set it in the agent's own .env.

Then restart and call it

COO merges each capability.json into the invoke registry when it loads, so a new agent needs a restart before it exists:

docker compose -f docker-compose.dist.yml \
  restart coo

curl -s http://127.0.0.1:4040/api/targets

curl -s -X POST \
  http://127.0.0.1:4040/api/coordinator/invoke \
  -H 'Content-Type: application/json' \
  -d '{"capability_id":"prep_lists",
       "input":{"description":"Draft Friday prep"}}'

Your agent cannot take over a bundled id. Rows from my-agents/ are merged in, never replacements — so nothing you write can quietly shadow a shipped capability.

What to ask the LLM for

Step 4, said out loud

I have a DAL project in my-agents/prep_lists — dal init agent and dal init serve have both run, so there is an agent.dal, an agent.toml with evolve wired, and a server.dal with @route handlers. Build me an agent that takes a service date and turns our standing prep notes into one packet the opening crew can read. Keep its own notes in the project folder. Then make it callable from my coordinator: add a capability.json with capability id prep_lists on port 8101, add a POST /task route that accepts {"description": "…"}, keep GET /health, and add scripts/start.sh following the shape in my-agents/README.md. Do not touch the bundled agents.

Same shape as any good setup prompt: what the work is, where it keeps state, and the limits. The difference is that this one ends with a process that has a name — so the next time you want Friday's packet, you call it instead of re-describing it.