Getting Started with DNA
This guide walks through provisioning a new DNA organism, configuring its local infrastructure in the habitat, populating secret slots in the vault, starting the local supervisor (hale dna dev), ratifying the initial Board reviews, and submitting your first task.
hale habitat uphale habitat graft democd demohale dna devPrerequisites
Section titled “Prerequisites”Before creating an organism, verify that your machine has:
haleonPATH: The Hale compiler and DNA CLI.git: Candidate branches and base commits live in your Git repository.hale habitat graftinitializes a repository automatically if none exists.docker composeonPATH: Runs the organism’s private backing services—PostgreSQL (memory), NATS JetStream (nerves), and Prometheus (senses)—inside your machine’s local habitat.- An LLM backend (optional but recommended): Either a hosted API key stored in the vault (
hale dna secret set <NAME>), a localollamaserver onPATH(127.0.0.1:11434), or a coding CLI harness (claudeorcodex) onPATH. Without a model, the organism still runs, but the Leader cannot plan tasks or decide delegated reviews, so every review waits for human Board approval. - A Git remote (optional): Required only when sharing a record across teammates or deploying to remote fleet nodes.
Provisioning an Organism
Section titled “Provisioning an Organism”Every organism on a machine is provisioned as a child of the local habitat (The Habitat), which manages shared Docker Compose infrastructure. Run hale habitat up to initialize and start the habitat, then run hale habitat graft <name> to create a new application and its DNA organization in a fresh directory:
$ hale habitat up$ hale habitat graft demook: 1 file(s) typecheckedcreated demo/hale.tomlcreated demo/main.hlcreated demo/tests/main_test.hlcreated demo/.gitignorewrote vendor/dna (81 file(s) written, 0 unchanged; hale.lock pins toolchain 0.21.0, embedded dna ca4012a0cda7226d)cut …/demo/.hale/dna/baseline.topology (schema 1.21, shape ddd87794e8adeed5, verdict clean)created …/demo/dna/org/purpose.hlcreated …/demo/dna/org/charter.hlcreated …/demo/dna/org/law.hlcreated …/demo/dna/org/models.hlmodels found no model key in the vault (`hale dna secret set <NAME>`), no ollama on PATH, claude on PATHmodels frontier = gpt-4o · fast = gpt-4o-mini (OPENAI_API_KEY, not in the vault: hosted backends are not permitted until it is) · desk = llama3 (ollama at 127.0.0.1:11434, not found)models editor, agent, leader: quick = harness (claude), deep = harness (claude) · private = desk · budget 25.00 USD a day (`hale dna models` probes them)created …/demo/dna/org/work.hlcreated …/demo/dna/org/workflows.hlcreated …/demo/dna/org/own_workflows.hlcreated …/demo/dna/org/main.hlmemory the local habitat's allocations: `hale habitat migrate …/demo` brings this organism's memory, nerves and senses' store up and migrates them (docker compose on PATH), and `hale dna dev` runs on them; `hale dna run` needs HALE_DNA_MEMORY_DSN_SPINE, HALE_DNA_NATS_URL_SPINE and HALE_DNA_NATS_ORGkept …/demo/main.hl (the application is not modified; the organization oversees it from dna/org)edited …/demo/hale.toml ([claims] no_base, [environments.local], [environments.org])pinned …/demo/hale.toml ([dna] record = 4f1c9a07d2be…, the identity of the record born here)memory schema applied; the record's tables, roles and functions are in placeborn record 4f1c9a07d2be (record.genesis; record.key 8a3e51c0b7d4…)seeded the record (6 observed event(s): application.attached, structure.observed, responsibility.proposed; then the purpose proposed and the application's graph)graph 2 node(s), 0 edge(s): 1 purpose, 0 axiom, 0 process, 1 seed, 0 contract, 0 noun, 0 deployment, 0 gate, 0 document, 0 witness, 0 position, 0 work, 0 organization, 0 definition; 6 proposal(s) (graph.node, graph.edge)seated the head's socket knows uid 1000 as … (dna.unix.member); the record declares dna.trust = local, where they hold every positionseeded purpose (proposed for the Board: `hale dna review` lists it under `purpose`)seeded design (11 practice(s) proposed, one Board Review each: `hale dna review` lists them under `design`)seeded operating (7 practice(s) proposed, one Board Review each: `hale dna review` lists them under `operating`)seeded using (7 practice(s) proposed, one Board Review each: `hale dna review` lists them under `using`)memory its allocation's superuser password in the vault, and its file beside the allocation in the local habitat (mode 600)nerves every role's password drawn into the vault, and the nerves allocation's secrets written (mode 600)secret oidc-client-dna-local drawn into the vaultsecret forge-token: a slot in the vault for a person to fill (`hale dna secret set`)secret model-OPENAI_API_KEY: a slot in the vault for a person to fill (`hale dna secret set`)nerves the organization's stream created
next steps: hale check --matrix …/demo # every entrypoint against its law hale dna dev …/demo # the organization and the application under one host, iris attached the first Review (`purpose`) ratifies the declared purpose (dna/org/purpose.hl): `hale dna review purpose approve --as <you>`Key details from the graft output:
- Model probing (
models):graftinspects your machine’s vault andPATHto generatedna/org/models.hl. In the output above,claudewas found onPATHand no API key was present in the vault, soquickanddeeptiers default to theclaudeharness while hosted models remain disabled untilOPENAI_API_KEYis set. - Local identity (
seated): Local Git config (dna.unix.member) maps your OS UID to your username, anddna.trust = localgrants that local user authority over every organizational position. - Remote body profile: Grafting a new application refuses an existing target directory. Pass
--profile remote-body --remote <url> [--body <user@host>]to configure a shared remote record and remote host body instead (see The Heart and the Body).
Attaching to an Existing Application
Section titled “Attaching to an Existing Application”To add DNA governance and runtime supervision to an existing Hale repository, run hale habitat graft with --attach:
hale habitat graft . --attach--attach performs the following steps:
- Initializes a Git repository if one does not exist and writes
vendor/dna. - Runs
hale checkto extract the application’s baseline topology. If the existing application fails typechecking,graftaborts before writing anydna/files. - Leaves your application source files untouched (
kept …), adds thelocalandorgenvironments tohale.toml, and runshale fmtacrossdna/and your application seed. - Inspects the repository graph (via
hale check --apiwhen an application seed is present at the root, or the repository graph otherwise). The application becomes the rootseednode, and every HTTP/RPC API surface or hub stream it serves becomes acontractnode. - Proposes holes (
hale dna reviewgroupholes) for the organizational positions implied by the graph (board, plus the application’sdevandreviewerpositions) along with each position’s mandate (a policy text defining what the position decides, what it is forbidden from deciding, what it must cite, how it writes, and what it escalates). - Computes each position’s standard equipment from contract role annotations (
requires: [editor]in an API surface orspec/<Stem>.description.jsongenerated byhale api describe), assigningreviewerto the seed’s reviewer position and all other required roles to itsdevposition (hale dna filldisplays these roles). Equipment roles describe what tools a position holder is fitted with; they never create positions or grant authority on their own.
Generated Files & Habitat Allocations
Section titled “Generated Files & Habitat Allocations”hale habitat graft creates the following files and database structures:
| Path / Resource | Purpose | User-Editable? |
|---|---|---|
dna/org/purpose.hl |
Single-sentence declaration of the codebase’s purpose, ratified in the first Board Review. | Yes |
dna/org/charter.hl |
The Leader’s architectural brief, read alongside the purpose, law, and ratified design practices during planning and review. | Yes |
dna/org/main.hl |
Entrypoint defining the Board, Leader, AutonomyBoundary grant, and dna::Dna substrate. |
Yes |
dna/org/law.hl |
Compile-time architectural claims enforced by hale check. You may add stricter claims, but do not weaken baseline rules. |
Yes (extend only) |
dna/org/models.hl |
Model catalog, tier routing, and daily spend budget generated from detected local tools. | Yes |
dna/org/work.hl |
Worker performer definitions executed by legs (hale dna work). |
Yes |
dna/org/workflows.hl |
Baseline workflow catalog; overwritten whenever you run hale dna upgrade. |
No |
dna/org/own_workflows.hl |
Custom workflow definitions; preserved across hale dna upgrade. |
Yes |
vendor/dna |
Vendored DNA core library matching the hale binary digest (embedded dna ca4012a0cda7226d). Git-ignored; refreshed by hale dna upgrade. |
No |
.hale/dna/ |
Ephemeral runtime state: baseline topology artifacts, Unix sockets, sandbox worktrees, logs, and .hale/dna/memory.env. Git-ignored; safe to delete. |
No |
record_rows (dna_<identity>) |
Append-only PostgreSQL table storing signed record rows and receipts. | No |
hale.toml is updated with two environments ([environments.local] for the application and [environments.org] for dna/org), [claims] no_base = true so each entrypoint is checked against its own architectural claims, and [dna] record = "<identity>" pinning the record’s genesis digest. See DNA, the Building Block for the full contents of each generated file.
Local Habitat Services
Section titled “Local Habitat Services”No Docker Compose files are added to your repository checkout. Instead, PostgreSQL (memory-<id>), NATS JetStream (nerves-<id>), and Prometheus (senses-<id>) run as allocations inside your machine’s local habitat Compose project (hale-habitat-local-<h>) under ${XDG_DATA_HOME:-~/.local/share}/hale/habitat/local/allocations/<id>/, where <id> is the 12-character prefix of [dna] record.
Because allocations are keyed by record identity:
- Multiple clones or Git worktrees of the same organism share the same PostgreSQL database, NATS stream, and Prometheus server.
- Stopping
hale dna devleaves the backing containers running in the habitat. - The habitat also runs one Forgejo, its forge: the graft made your organism a user there and a repository for its code, and
hale dna forge syncsends the code out through it and brings the reviews on it back (The forge mirror). - After updating the
haletoolchain, runhale habitat migrateto idempotently update schemas and bring up any new habitat services (includingsenses-<id>):
hale habitat migrate .Commit the generated project files (Git automatically ignores vendor/dna and .hale/):
cd demogit add -A && git commit -m "the organism"Verifying the Workspace
Section titled “Verifying the Workspace”Use hale check --matrix to verify both the application entrypoint and dna/org against their respective laws, then run the test suite:
$ hale check --matrix .=== ./. @ local ===ok: 1 file(s) typechecked=== ./dna/org @ org ===ok: 8 file(s) typechecked
ok: 2 (entrypoint, environment) pair(s) checked$ hale test .ok ./tests/main_test.hl
1 passed, 0 failedEvery candidate mutation proposed by the organism will automatically run hale check, hale verify, and hale test before opening a Review.
Managing Secrets in the Vault
Section titled “Managing Secrets in the Vault”hale habitat graft automatically generates random passwords for internal PostgreSQL and NATS roles and creates empty slots for user-supplied API keys. Secrets live in HALE_VAULT_DIR (or ~/.cache/hale/vault by default) as mode 0600 files.
Run hale dna secrets to check which secrets are present or missing (values are never printed):
$ hale dna secretsthe organism's secrets (the local vault, …): present postgres-dna_db39b9dd436962c99cfa90fe5366f10a48f71dc0_spine memory: the spine's role present postgres-dna_db39b9dd436962c99cfa90fe5366f10a48f71dc0_head memory: the head's role present postgres-owner-db39b9dd4369 memory: its allocation's superuser in the local habitat present nats-dna_db39b9dd436962c99cfa90fe5366f10a48f71dc0-owner the nerves: the owner's account present nats-dna_db39b9dd436962c99cfa90fe5366f10a48f71dc0-spine the nerves: the spine's account present nats-dna_db39b9dd436962c99cfa90fe5366f10a48f71dc0-head the nerves: the head's account present nats-dna_db39b9dd436962c99cfa90fe5366f10a48f71dc0-reflexes the nerves: the reflexes's account present nats-dna_db39b9dd436962c99cfa90fe5366f10a48f71dc0-app-demo the nerves: the application `demo`'s account present oidc-client-dna-local the skin: the head's OIDC client secret (the local stub's) MISSING forge-token the forge's token — a person supplies it: `hale dna secret set FORGE_TOKEN` MISSING model-OPENAI_API_KEY the model's key OPENAI_API_KEY — a person supplies it: `hale dna secret set OPENAI_API_KEY`2 missingTo populate a user-supplied slot (FORGE_TOKEN, OIDC_CLIENT_SECRET, or any model key declared in dna/org/models.hl), run hale dna secret set <NAME> and enter the secret on stdin:
$ hale dna secret set OPENAI_API_KEYvalue for OPENAI_API_KEY (this machine), on one line:secret set: OPENAI_API_KEY is in its slot of the vault, …/model-OPENAI_API_KEY (secret.rotated OPENAI_API_KEY; the value is nowhere in the record). A part reads it from the vault where it uses itStarting the Runtime (hale dna dev)
Section titled “Starting the Runtime (hale dna dev)”Start the organization and your application together under the local host supervisor:
hale dna devLeave hale dna dev running in its terminal. On startup, hale dna dev executes five steps in order:
- Resolves spine credentials for the organism’s PostgreSQL (
memory) and NATS (nerves) services in the local habitat.hale dna devdoes not start containers or run schema migrations itself—if the habitat services are down or unmigrated, it exits and instructs you to runhale habitat migrate. - Acquires the body lease in PostgreSQL so this checkout is the single active host supervising the record.
- Compiles and launches
dna/orgwith thespinecredentials and waits up to 20 seconds for it to subscribe to the NATS stream. - Compiles and launches your application, attaching the Iris inspector on port
8787. - Enters the 1-second tick loop: syncs record state, relays unanswered request rows onto NATS JetStream, and rebuilds/restarts the application whenever an approved mutation is applied.
hale dna dev: body lease taken as … (token 1)hale dna dev: memory: the graph, the ledger and protected evidence under the record's spine rolehale dna dev: organization (pid …) from … under LOTUS_OBS=1hale dna dev: the organization reads its facts from the nerves (…)hale dna dev: expression demo (pid …) under LOTUS_OBS=1If no model credential is present in the vault, the host logs a warning (hale dna dev: no credential for the model: …) and displays a notice on hale dna board until the slot is filled.
Useful flags for hale dna dev:
--observe <secs>: Duration of the post-restart health observation window (default:15seconds).--port <N>: Port for the Iris inspector (default:8787).--no-iris: Disables the Iris inspector.- Stop the supervisor at any time with
Ctrl-C; all pending Reviews and tasks remain durable in PostgreSQL.
Inspecting Runtime Status
Section titled “Inspecting Runtime Status”In a second terminal, run hale dna status:
$ hale dna statusembedded dna: ca4012a0cda7226d (hale 0.21.0)organism: not running — reading the Journaljournal: 38 event(s), chain verified at 9ddd807957fcexpression: attached Demo (shape ddd87794e8adeed5) · current shape not cut · build not builtintents: 0 offered, 0 refusedtasks: nonereviews: 32 pending of 32 k:05cecb18af4e [pending] needs board — ratify the design practice `design/software-delivery`: For an appendage or a product: process boundaries first (what runs, fail… …mutations: 0 (none applies before a human's verdict on the exact candidate)profile: local (detected)body: none (no body has run this record; `hale dna run` takes the lease)memory: record + ledger (operations and leases live in memory)genome: no node has recorded the genome it runsRead-only inspection commands (hale dna status, hale dna history, hale dna review, and hale dna board) query PostgreSQL directly using the head DSN stored in .hale/dna/memory.env and work even when hale dna dev is stopped. When hale dna dev is running, the organism: and body: lines display the active holder and lease status.
Ratifying Initial Board Reviews
Section titled “Ratifying Initial Board Reviews”hale habitat graft seeds dna/org/purpose.hl and proposes initial governance items for the Board (you) to ratify:
const PURPOSE: String = "refproj: keep the application correct, reviewable and explainable; every change is staged, reviewed, and never applied by the organism itself.";Run hale dna review to list all pending Reviews grouped by category:
$ hale dna review32 pending review(s) of 32 purpose — the declared purpose, the Board's to ratify first: k:d2564afcfe0d — ratify the declared purpose? decide one with `hale dna review <id> …`, or all pending with `hale dna review purpose approve|reject` design — 11 seeded practice(s), each its own Review: k:05cecb18af4e — ratify the design practice `design/software-delivery`: For an appendage or a product: process boundaries first (what runs, fail… … operating — 7 seeded practice(s), each its own Review: k:33be310ddba8 — ratify the operating practice `operating/one-store-per-step`: a workflow step writes to exactly one store, by that store's one writer,… … using — 7 seeded practice(s), each its own Review: k:8c1f6a4e2d70 — ratify the using practice `using/propose-review-ratify`: nothing is in force until the Board says so. A change to the organi… … holes — 6 hole(s) the repository leaves, each its own Review: k:d51a712f169e — ratify the position `board` under the purpose: it ratifies what this organization becomes … decide one with `hale dna review <id> …`, or all pending with `hale dna review holes approve|reject`render one with `hale dna review <id>`; decide with `hale dna review <id> approve|revise|reject|abstain`With hale dna dev running, ratify the declared purpose and the seeded practice families (design, operating, and using):
hale dna review purpose approve --as alicehale dna review design approve --as alicehale dna review operating approve --as alicehale dna review using approve --as aliceEach command appends a review.verdict row signed by --as <name> and waits for the running spine node to settle the Review (review k:… settled: approve by alice). If no body holds the record lease, hale dna review refuses to write unless you pass --no-wait to queue the verdict for the next run.
To ratify every pending group—including holes—in one command, run hale dna review all approve --as alice. To also assign yourself to every position opened by holes (board, <app>/dev, and <app>/reviewer) during initial setup, apply the founder pack when grafting:
hale habitat graft . --attach --with founder --set founder=alice --as alicehale dna review all approve --as alice # with `hale dna dev` runningSee A Pack at the Graft for details on how packs stage proposals against open position holes.
Submitting Your First Task
Section titled “Submitting Your First Task”With hale dna dev running, request a code change from the terminal:
hale dna task create --as alice "document the Echo locus in main.hl"The CLI writes the request row, waits for the spine to admit the workflow, and prints task t1 born for intent i… […]. Continue to One Task, End to End to trace how this task executes, verifies, reviews, and deploys.