This guide describes how to set up and use agents in dist_agent_lang: project setup, CLI commands, the agent HTTP server, DAL APIs, molds, and evolve context. It reflects what users and developers can do today.
Agents in dist_agent_lang are in-process entities with:
ai, system,
worker, or custom:<name>dal agent serveYou can:
dal init agent (adds agent.dal,
agent.toml, evolve.md, etc.).dal run agent.dal
or run the HTTP server with
dal agent serve.dal agent create <type> <name>) or from DAL
(agent::spawn(config)).[agent.sh] in
agent.toml.mkdir my-agent && cd my-agent
dal init agentThis creates (only if missing):
dal.toml — minimal package configagent.toml — agent config: [agent.sh]
trust, [agent] context_pathagent.dal — entry script that spawns an agent and sets
it as the serve agentevolve.md — evolve context (conversation + action
log)playground.dal — small language sandbox
(dal run playground.dal)README.md — short project summary.env.example and .env — env vars
(.env in .gitignore)dal run agent.dalThis runs agent.dal: it spawns one agent and calls
agent::set_serve_agent(agent_id). The process then exits;
the “serve” designation is used when you start the HTTP server with a
behavior script.
dal agent serveIf agent.dal exists in the current directory, it is run
first; the script must spawn an agent and call
agent::set_serve_agent(agent_id). That agent is then served
at http://localhost:4040 (default port). See Agent HTTP server.
Copy .env.example to .env, set any keys
(e.g. OPENAI_API_KEY, ANTHROPIC_API_KEY for
AI), and load them (e.g. export $(cat .env | xargs) or use
a .env loader). See Shell
trust and evolve context.
For DAL apps, prefer the typed request shape:
let ai_result = ai::agent_run({"message": "Run pwd once and summarize", "policy": "tool_loop"});
ai::respond_with_tools_result(...) remains available for
compatibility, but new first-party examples and templates use
ai::agent_run(...).
For dal init agent, the generated .env
includes a minimal host-protocol profile intended for task completion
with safety guardrails:
DAL_AGENT_SHELL_TRUST=sandboxed
DAL_AGENT_CONTEXT_PATH=./evolve.md
DAL_AGENT_POLICY_DEFAULT=auto
DAL_AGENT_NATIVE_TOOL_CALLS_ENABLED=1
DAL_AGENT_ENABLE_LEGACY_TEXT_JSON=0
DAL_AGENT_GUARDS_STRICT_MODE=1DAL_AGENT_POLICY_DEFAULT=auto favors execution for
actionable requests and direct replies for purely conversational
prompts.DAL_AGENT_GUARDS_STRICT_MODE=1 keeps conservative loop
safeguards enabled for fresh projects.DAL_AGENT_POLICY_DEFAULT=reply_only.dal init agent| File | Purpose |
|---|---|
agent.dal |
Agent behavior: spawn agent, call
agent::set_serve_agent(agent_id). Used by
dal run agent.dal and by dal agent serve when
no --behavior is given. |
agent.toml |
Agent config: [agent.sh] (shell trust),
[agent] (e.g. context_path for evolve). |
evolve.md |
Evolve context file: conversation history and action log. Path set
by [agent] context_path or
DAL_AGENT_CONTEXT_PATH. |
playground.dal |
Minimal DAL language sandbox for quick experimentation
(dal run playground.dal). |
dal.toml |
Minimal DAL package (created only if missing). |
.env.example |
Documented env vars (safe to commit). |
.env |
Local overrides (do not commit; in .gitignore). |
# Agent project config
[agent.sh]
trust = "sandboxed"
# forbidden_patterns = ["rm -rf", "sudo"]
# allowed_prefixes = ["npm", "cargo", "git"]
[agent]
context_path = "./evolve.md"[agent.sh] — Used by
sh::run(cmd) in DAL: trust = off
| sandboxed | confirmed |
trusted; optional forbidden_patterns /
allowed_prefixes.[agent] — context_path:
path to the evolve context file (default ./evolve.md).Context path can be overridden with
DAL_AGENT_CONTEXT_PATH.
Evolve wired at init: When you run
dal init agent, evolve is wired by default:
agent.toml gets context_path = "./evolve.md"
and evolve.md is created. The serve path loads evolve into
the prompt each turn; lifecycle hooks (e.g. in molds) can use
evolve::append_log, evolve::append_summary,
evolve::append_conversation. To disable
evolve, comment out or remove the context_path line in
agent.toml (and optionally remove evolve.md).
To opt in again, uncomment context_path
and ensure the evolve file exists.
All agent subcommands:
dal agent <subcommand> [args...].
Run the agent HTTP server (one agent per process).
dal agent serve [name] [--port PORT] [--mold path] [--behavior path] [--prompt-only]serve_agent).ipfs://<cid> to spawn from mold instead of default
config.agent::set_serve_agent(agent_id). If omitted
and agent.dal exists in cwd, agent.dal is
used.DAL_AGENT_PROMPT_ONLY=1 for the same
effect.Examples:
dal agent serve
dal agent serve my-bot --port 5000
dal agent serve --behavior ./scripts/agent.dal
dal agent serve --prompt-onlyCreate an agent in the current process (in-memory; process exit clears it).
By type and name:
dal agent create <type> <name> [--role "role"]Types: ai, system, worker,
custom:<name>.
From a mold:
dal agent create --mold <path|ipfs://cid> <name>With web3: --mold <numeric_mold_id> uses on-chain
registry (pay fee, then load from IPFS).
Send a message between two agent IDs (same process).
dal agent send <sender_id> <receiver_id> "<message>"Print messages received by an agent (consumes the queue).
dal agent messages <agent_id>Assign a task or list pending tasks:
dal agent task assign <agent_id> "<description>" [--priority low|medium|high|critical]
dal agent task list <agent_id>Interactive chat with an AI agent (same process): messages go to the
agent; replies come from the LLM (OpenAI/Anthropic/local). Requires API
keys or DAL_AI_ENDPOINT.
dal agent chat [name]Prints how to run chat, serve, and multi-agent DAL patterns (agent state is process-local).
Off-chain fleet: named set of agents, optionally created from a mold. See FLEET_DEPLOYMENT.md for full deployment flow.
--from-mold <path> [--count N] [--param k=v ...] to
create a fleet of N agents from a mold (default count 1).-v also shows last_deployed_task and last_deployed_at.last_create_params if set).Fleet state is stored in base/.dal/fleets.json when
using the CLI (current working directory as base).
.,
mold/, mold/samples; *.mold.dal,
*.mold.json).When you run dal agent serve, the server listens
(default port 4040) and exposes one agent.
| Method | Path | Description |
|---|---|---|
| GET | /status |
Agent id, name, type, status |
| POST | /message |
Send message (body: sender_id, content;
optional message_type,
wait) |
| GET | /messages |
Receive (and consume) messages for this agent |
| POST | /task |
Assign task (body: description; optional
task_id, priority, requester_id,
wait) |
| GET | /tasks |
Receive (and consume) pending tasks |
| GET | /health |
Liveness |
curl -X POST http://localhost:4040/message \
-H "Content-Type: application/json" \
-d '{"sender_id": "user1", "content": "Hello"}'
curl http://localhost:4040/messages
curl http://localhost:4040/statusWith --prompt-only (or
DAL_AGENT_PROMPT_ONLY=1), no behavior script is run. The
server spawns a default worker agent and, for each incoming message,
calls the LLM and posts the reply back to the sender. Use when you want
a simple chat-style API without custom DAL logic.
wait and Idempotency-Key
(prompt-only)For POST /message and
POST /task, set
"wait": true in the JSON body to
block until the multi-step tool loop finishes. The HTTP
response includes a result object:
final_text — assistant reply or error
text from the loopsteps_used,
max_steps_reached,
is_ask_user — same meaning as in
ai:: diagnosticsWithout wait, the handler returns
{ "ok": true } immediately and delivers
the assistant output via GET /messages
(unchanged).
Send HTTP header
Idempotency-Key: <opaque> on
wait: true requests to
cache the JSON response for about 10
minutes. Retries with the same key return the cached body
without re-invoking the model (useful for safe cron retries). See CONFIG.md.
Outbound HTTP tools (search,
fetch_url, and other code paths that use
reqwest) require the Cargo feature
http-interface. The default
dal binary enables it. If you build with
cargo build --no-default-features,
re-enable http-interface for production
agent servers that need web access. See root Cargo.toml
[features] and CONFIG.md.
Web search defaults to DuckDuckGo Instant Answer (no
API key). For fuller results, set
DAL_WEB_SEARCH_PROVIDER=brave or
serpapi and supply the matching API key
env vars listed in CONFIG.md.
URL fetch limits and SSRF-related toggles:
DAL_HTTP_FETCH_* in CONFIG.md.
Overlapping long requests: handlers that run an LLM plus a tool loop can hold a blocking worker for a long time. Many concurrent cron-triggered HTTP calls may queue or time out. Mitigate by staggering schedules, limiting parallelism, or using a dedicated worker process. See AUTONOMOUS_JOBS_LANGUAGE_GAPS.md §2.3.
From DAL you call the agent module as follows.
Spawn an agent
agent::spawn(config) — config is a map
with:
name (string)type (string): ai, system,
worker, custom:<name>role, capabilities (list of
strings), trust_level, metadataExample:
use agent;
let agent_id = agent::spawn({
"name": "my-agent",
"type": "worker",
"role": "Agent serve"
});
agent::set_serve_agent(agent_id);
Set the serve agent (required when using
dal agent serve with a behavior script):
agent::set_serve_agent(agent_id) — Registers this agent
as the one to serve over HTTP.Coordination
agent::coordinate(agent_id, task_description, coordination_type)
— Assigns a task to the agent. Coordination type e.g.
"task_distribution". Task is created with default
priority.Communication
agent::communicate(sender_id, receiver_id, message) —
Sends a message. You build the message with
agent::create_message(sender_id, receiver_id, message_type, content)
(or the runtime creates one with a generated id and type when you use
the three-arg communicate).Other
agent::create_config(name, type_str, role) — Build a
config (returns a value used internally).agent::create_task(description, priority?) — Create a
task (task_id is generated).agent::create_message(sender_id, receiver_id, message_type, content)
— Create a message (message_id generated).agent::evolve(agent_id, evolution_data) — Record
evolution data; molds can hook on_evolve (e.g. call
evolve::append_summary).agent::validate_capabilities(agent_type, required_capabilities)
— Validate that an agent type has the required capabilities.agent::terminate(agent_id) — Mark agent terminated
(in-memory).agent::get_status(agent_id) — Get status string.Note: Messages and tasks are consumed when received (e.g.
receive_messages / receive_pending_tasks); the
HTTP server uses the same in-memory bus and queues.
Evolve uses a single markdown file (path from
[agent] context_path or
DAL_AGENT_CONTEXT_PATH; default
./evolve.md).
evolve::load(agent_name?) — Load full context. Creates
file with header if missing.evolve::load_recent(agent_name?, max_lines) — Last N
lines of the file (or full if
max_lines <= 0). Line-based cuts can split tables;
prefer below for prompts.evolve::load_recent_for_prompt(agent_name?, max_turns, max_chars)
— Prompt-oriented load: last max_turns
conversation turns (blocks under
## Conversation), plus optional
## Working memory and the latest ## Summary
block. Omits the action-log table from the returned
string (still on disk). Env defaults in COO:
DAL_EVOLVE_PROMPT_MAX_TURNS,
DAL_EVOLVE_PROMPT_MAX_CHARS.evolve::append_conversation(user_message, agent_response, agent_name?)
— Append a conversation turn.evolve::append_log(action, detail, result) — Append an
action log row (e.g. after sh::run).evolve::append_working_memory(line) — Append one
high-signal bullet under ## Working memory (decisions,
paths, open threads). Creates the section before
## Conversation if needed.evolve::append_summary(summary_text, title?) — Append a
summary section.evolve::get_path() — Resolved context file path.evolve::trim_retention(keep_tail_lines) — Keep only the
last N lines of content after the header.Use these from DAL to keep the context file in sync with agent
behavior (e.g. after answering a user or running a command). For
evolution that actually helps the next turn, prefer
append_working_memory for durable facts
and load_recent_for_prompt (or COO’s
built-in prompt path) instead of stuffing only raw action-log noise into
context.
sh::run(cmd) — Run a shell command. Trust is determined
by DAL_AGENT_SHELL_TRUST or [agent.sh] in
agent.toml / dal.toml. Returns a map:
stdout, stderr, exit_code.Use evolve::append_log after sh::run to
record the action in the evolve file.
Molds are reusable agent configs (type, role, capabilities, trust, memory, lifecycle hooks). They can be local files or IPFS/on-chain.
*.mold.dal. DAL-native block syntax; not plain JSON. See
docs/MOLD_FORMAT.md.mold/,
mold/samples. Legacy *.mold.json still loads
but prefer .mold.dal.dal agent mold list — List local mold paths.dal agent mold show <path-or-name> — Show mold
details.dal agent create --mold <path|ipfs://cid> <name> [--param k=v ...]
— Create agent from mold; optional params merged into metadata and
substituted in role/capabilities ({{key}}). If the CLI
reports "unexpected argument '--mold'", use:
dal agent create -- --mold <source> <name> [--param k=v ...].dal agent serve --mold <path> [name] — Serve an
agent spawned from that mold.When you create or serve an agent from a mold, trust (shell execution) and evolve path (context file) always come from the process (agent.toml, dal.toml, or env), not from the mold. The mold can set role, capabilities, lifecycle, etc., but the operator controls trust and where evolution is stored. See COMPREHENSIVE_AGENT_AND_MOLD_PLANS.md §3–4.
mold::spawn_from(source, name_override?, params?) —
Load mold from path/name or ipfs://<cid>, spawn
agent, return agent_id. Optional name override; optional params map
(string keys/values) merged into metadata and substituted in
role/capabilities ({{key}}).sh::run(cmd) respects:
DAL_AGENT_SHELL_TRUST — off |
sandboxed | confirmed |
trusted[agent.sh] in agent.toml or
dal.toml: trust, optional
forbidden_patterns, allowed_prefixesIf key-based gating is used and the check denies, config falls back
to [agent.sh].
DAL_AGENT_CONTEXT_PATH — explicit path[agent] context_path in agent.toml or
dal.toml./evolve.mdDAL_AGENT_MAX_TOOL_STEPS — max tool
steps (run/search) per message or task before the agent is asked to
summarize. Default 20, clamped 1–50. Used when
dal agent serve runs in prompt_only mode with the
multi-step loop.Agent runtime state persists across restarts by default. No
configuration is required — when you run dal agent serve,
the runtime automatically saves and restores agent memory, tasks,
messages, evolution data, and registered skills.
| Backend | Default? | Config | Notes |
|---|---|---|---|
| File (JSON) | Yes | DAL_AGENT_RUNTIME_PATH=./agent_runtime.json |
Atomic writes, human-readable |
| SQLite | No | DAL_AGENT_RUNTIME_BACKEND=sqlite |
WAL mode, higher throughput, requires sqlite-storage
feature |
| Disabled | No | DAL_AGENT_RUNTIME_PERSIST=0 |
In-memory only, state lost on exit |
Set via environment variables or agent.toml /
dal.toml:
# Environment variables
DAL_AGENT_RUNTIME_PERSIST=1 # 1 (default) or 0
DAL_AGENT_RUNTIME_BACKEND=file # file (default) or sqlite
DAL_AGENT_RUNTIME_PATH=./my_state.json # Custom path# agent.toml
[agent.persistence]
enabled = true
backend = "file"
path = "./agent_runtime.json"dal agent serve), the runtime
checks for a saved snapshot and restores state.version field) enables
forward-compatible migrations.For full details, see Persistent Agent Memory.
Skills define what an agent can do. Each skill is a named bundle of tools and a description that gets included in the agent prompt at serve time.
Four categories ship with every DAL install:
| Category | Skill name | Tools |
|---|---|---|
| Development | development |
read, write, search, run, lint, test, debug |
| Creative | creative |
read, write, search, generate, transform |
| Office | office |
read, write, search, run, schedule, email |
| Home | home |
read, search, run, control, monitor |
Create .skill.dal files in your project's
.dal/ directory (or set DAL_SKILLS_PATH):
// .dal/calendar.skill.dal
skill "my_calendar" {
category "office"
description "Manage my custom calendar app via CLI and API calls."
tools "run" "search" "read" "write"
}
Skills are loaded at startup and included in the agent prompt when the agent's config references them by name.
From DAL or Rust, register skills programmatically:
let skills = [{
"name": "data_pipeline",
"category": "development",
"description": "Run ETL pipelines and data transformations.",
"tools": ["run", "read", "write", "search"]
}];
agent::register_runtime_skills(skills);
Runtime-registered skills persist across restarts (stored in the agent runtime snapshot).
The skills system includes built-in guidance that helps agents discover and use tools effectively:
For full details, see Skills and Registry.
Agent types: ai, system,
worker, custom:<name>.
Capabilities are per-type (built-in or registry) and
per-agent (config/mold). Use
agent::validate_capabilities(agent_type, required_capabilities)
to check a type; at runtime, an agent context’s capabilities are set at
spawn (from type initializer or from config/mold).
For how capabilities are defined, set, and validated, see AGENT_CAPABILITIES.md.
RAG (retrieval-augmented generation) in dist_agent_lang is a lexical MVP: chunks from your indexed corpus are attached to the agent prompt as context blocks when enabled.
DAL_RAG=1
so retrieval applies when the client omits include_rag or
leaves it null (same rules for dal agent serve, HTTP
handlers that support include_rag, and
workflow::run_steps with an optional
include_rag argument). Per-request JSON can override with
include_rag: true|false.cargo run --bin rag-index (output defaults
under .dal/rag/, e.g.
chunks.jsonl). Override with
DAL_RAG_INDEX_DIR.
DAL_RAG_TOP_K controls how many chunks
(1–50, default 5).rag::prompt_block(query, include_rag) to
assemble a block for your own prompts.Full behavior, corpus layout, and context_blocks with
source: rag are documented in RAG_MVP_SPEC.md. Env
reference: CONFIG.md.
MCP (Model Context Protocol) is not
a DAL keyword or builtin. It is a host protocol: a
small stdio process (often Node) forwards tool calls
from an MCP-capable editor (e.g. Cursor) to your agent’s HTTP
API — the same behavior as calling POST /message
or /task with curl.
dal mcp-bridge runs the bundled bridge
script and sets DAL_AGENT_HTTP_BASE (see
dal mcp-bridge --help). Point the base URL at wherever
dal agent serve or your
dal serve app listens.DAL_AGENT_HTTP_BASE /
DAL_MCP_HTTP_BASE (optional
DAL_MCP_BRIDGE_SCRIPT to override the
script path). Prefer DAL_COO_BASE_URL /
DAL_COO_MCP_SCRIPT.COO/mcp/ (repo root) or
../COO/mcp/ (from
dist_agent_lang) — run
npm install in that folder, then configure
your IDE’s MCP server entry to run
node …/COO/mcp/src/server.js (or
node …/../COO/mcp/src/server.js) with
cwd set to that same mcp
folder.Language-wide mental model (HTTP first, MCP optional, LSP separate): IDE_AND_AGENT_INTEGRATION.md. Env index: CONFIG.md.
rag::prompt_block,
include_rag.dal mcp-bridge..skill.dal format, programmatic encouragement,
runtime registration..mold.dal syntax and lifecycle hooks.