Contracts and delivery
Calls use named arguments. Delivery settings can be declared on an action and overridden at the call. Timeout bounds an attempt after a worker accepts it; queue availability has separate server settings.
worker awl 4 Names a typed task-queue contract in a workflow, or opens a worker document implementing that queue.
-
formdeclaration -
positionstop-level
//! The worker block is a typed requirement on the `greeter` task queue.
workflow greet_politely
input name: String
outcome done: type Greeting, route success
type Greeting { text: String }
worker greeter
action greet(name: String) -> Greeting
step greet
greet(name: name) -> reply
route done(reply) action awl 4 Declares one wire contract on a worker: named parameters, one return type, and at most one config line.
-
formheader-clause -
positionsworker-block, role-block
//! Each action line is one wire contract: named parameters, one return.
workflow inspect_repo
input repo: String
outcome done: type Report, route success
type Report { summary: String }
worker inspectors
action inspect(repo: String) -> Report
step inspect
inspect(repo: repo) -> report
route done(report) timeout awl 4 Bounds the workflow run in the header, one activity on an action or call, or one `wait` — three distinct places.
-
formstatement -
positionsworkflow-header, worker-block, role-block, step-body, signal-reference
//! The header timeout bounds the whole run.
workflow nightly_sweep
timeout 2h
input target: String
outcome done: type String, route success
step sweep
route done("swept " + target) retry awl 4 Sets an action's retry policy, as `retry N every DURATION` or `retry N backoff MIN..MAX`.
-
formheader-clause -
positionsworker-block, role-block
//! Retry the flaky pull three times before the step faults.
workflow sync_mirror
input remote: String
outcome done: type Synced, route success
type Synced { revision: String }
worker mirrors
action pull(remote: String) -> Synced
retry 3 every 30s
step pull
pull(remote: remote) -> synced
route done(synced) fallback awl 4 Declares the ordered task-queue chain consulted after a provider policy refusal.
-
formheader-clause -
positionsworker-block, role-block
//! Route policy refusals through the declared queue chain.
workflow route_provider
input prompt: String
outcome done: type String, route success
worker agents
action run(prompt: String) -> String
fallback norn, claude
step run
run(prompt: prompt) -> answer
route done(answer) advisory awl 4 Marks an action whose failure never faults its calling step; it can bind no result and be no pipe stage.
-
formheader-clause -
positionsworker-block, role-block
//! An advisory announcement can fail without faulting the run.
workflow ship_build
input version: String
outcome done: type String, route success
worker notifier
action announce(version: String) -> Nil
advisory, timeout 30s
step ship
announce(version: version)
route done(version) agent awl 4 Marks an action as an agent seam. The prompt is a String; an explicitly bound working-directory parameter can accompany it. The result has text, final_message, stop_reason and session_id fields.
-
formheader-clause -
positionsworker-block, role-block
//! An agent action hands its prompt to a harness and binds the outcome
//! record: accumulated `text`, the last answer as `final_message`, the canonical
//! `stop_reason`, and the `session_id` handle of the conversation that produced it.
workflow ask_reviewer
input question: String
outcome done: type String, route success
type Reply { text: String, final_message: String, stop_reason: String, session_id: String }
worker assistants
action ask(prompt: String) -> Reply
agent, timeout 10m
step ask
ask(prompt: question) -> reply
route done(reply.text) every awl 4 Sets a fixed retry interval, or the cadence that arms a workloop.
-
formheader-clause -
positionsworkloop-header, worker-block, role-block
//! `every` fixes the interval between retries: ten seconds, each time.
workflow ping_service
input url: String
outcome done: type Pong, route success
type Pong { latency_ms: Int }
worker probes
action ping(url: String) -> Pong
retry 5 every 10s
step ping
ping(url: url) -> pong
route done(pong) backoff awl 4 Sets the growing retry interval in `retry N backoff MIN..MAX`.
-
formheader-clause -
positionsworker-block, role-block
//! `backoff` grows the retry interval from ten seconds toward two minutes.
workflow fetch_upstream
input source: String
outcome done: type Fetched, route success
type Fetched { bytes: Int }
worker fetchers
action fetch(source: String) -> Fetched
retry 4 backoff 10s..2m
step fetch
fetch(source: source) -> fetched
route done(fetched) node awl 4 Constrains relative placement with `node same as STEP`, `node different from STEP`, or `node group LABEL`; `node from PATH` reads a String in the run and an empty value gives no call-site pin.
-
formheader-clause -
positionsworker-block, role-block
//! Pin an action's dispatch to the named worker node.
workflow build_release
input tag: String
outcome done: type Build, route success
type Build { artifact: String }
worker builders
action build(tag: String) -> Build
node group linux_large
step build
build(tag: tag) -> built
route done(built) affinity awl 4 Keeps unpinned actions from this worker block on the node of its first unpinned lease. An explicit selector wins for that action.
-
formheader-clause -
positionsworker-block
//! Keep this run's build actions on the node that serves its first lease.
workflow affinity_build
input tag: String
outcome done: type Build, route success
type Build { artifact: String }
worker builders
affinity run
action build(tag: String) -> Build
action sign(artifact: String) -> Build
node group signing_hsm
step build_and_sign
build(tag: tag) -> built
sign(artifact: built.artifact) -> signed
route done(signed) run awl 4 Gives an action a command-line body, which the server runs itself with no sandbox of any kind; `runs command <name>` is the typed alternative.
-
formheader-clause -
positionsworker-block
//! The document is the implementation: the server runs the command itself.
workflow greet_by_hand
input name: String
outcome done: type Stdout, route success
type Stdout { stdout: String }
worker shell
action greet(name: String) -> Stdout
run "echo hello {{name}}"
step greet
greet(name: name) -> out
route done(out) Retry counts additional attempts. A retryable failure consumes that policy; worker loss can redispatch the same attempt. A fallback names another declared worker queue, not an arbitrary program.
Relative placement
An authored node selector relates work inside a run. A bare physical node name is refused. The referenced step must exist and cannot be the enclosing step itself.
same awl 21 Selects the node recorded for another step in `node same as STEP`.
-
formstatement -
positionsworker-block, role-block, step-body
//! Keep a build and its signature together, with review elsewhere.
workflow relative_build
outcome done: type Nil, route success
worker builders
action build() -> Nil
action sign() -> Nil
action review() -> Nil
step build
build()
node group release
step sign
sign()
node same as build
step review
review() -> done
node different from build
route done as awl 21 Joins `same` to its step name in `node same as STEP`.
-
formstatement -
positionsworker-block, role-block, step-body
//! Keep a build and its signature together, with review elsewhere.
workflow relative_build
outcome done: type Nil, route success
worker builders
action build() -> Nil
action sign() -> Nil
action review() -> Nil
step build
build()
node group release
step sign
sign()
node same as build
step review
review() -> done
node different from build
route done different awl 21 Excludes the node recorded for another step in `node different from STEP`.
-
formstatement -
positionsworker-block, role-block, step-body
//! Keep a build and its signature together, with review elsewhere.
workflow relative_build
outcome done: type Nil, route success
worker builders
action build() -> Nil
action sign() -> Nil
action review() -> Nil
step build
build()
node group release
step sign
sign()
node same as build
step review
review() -> done
node different from build
route done from awl 21 Names the reference step in `node different from STEP`, or opens a runtime binding path after `node`.
-
formstatement -
positionsworker-block, role-block, step-body
//! Keep a build and its signature together, with review elsewhere.
workflow relative_build
outcome done: type Nil, route success
worker builders
action build() -> Nil
action sign() -> Nil
action review() -> Nil
step build
build()
node group release
step sign
sign()
node same as build
step review
review() -> done
node different from build
route done group awl 21 Keeps actions with the same run-scoped label on their group's recorded node.
-
formstatement -
positionsworker-block, role-block, step-body
//! Keep a build and its signature together, with review elsewhere.
workflow relative_build
outcome done: type Nil, route success
worker builders
action build() -> Nil
action sign() -> Nil
action review() -> Nil
step build
build()
node group release
step sign
sign()
node same as build
step review
review() -> done
node different from build
route done A call site can override node and timeout. Retry policy and declaration markers cannot be overridden there. A call-site selector wins over its declaration. Run affinity keeps unpinned actions from one worker block on the first unpinned lease’s node. It is a workflow delivery policy and is refused in a worker document.
Worker documents
A worker document opens with one queue and owns its actions’ implementations. It declares no workflow inputs, outcomes or steps. Capture can return the command outcome, trimmed text or decoded JSON of the declared result type.
The worker advertisement is derived from that document. It must agree with the workflow’s independently derived contract. Use worker check mode before connecting.
Agent harnesses
A harness section declares the adapter, concurrency, reconnect policy and environment variable names. ACP also requires a command, explicit permission and an exit grace. Both kinds require a working directory. Paths can be absolute or begin with the literal workspace-root marker; a working directory can instead be bound to an action parameter. The checker names missing fields for the declared kind.
No undeclared environment is inherited by the agent. A missing declared variable is reported at launch. Read worker operations for serving and supervision.
Harness fields
-
kind - Required: acp or norn. Kind-specific fields from the other adapter are refused.
-
concurrency - Required positive maximum activities served at once.
-
reconnect_initial_backoff - Required positive first reconnect duration.
-
reconnect_max_backoff - Required duration at least the initial delay.
-
reconnect_max_attempts - Required positive reconnect budget.
-
connect_timeout - Optional positive overall connect duration; requires registration_timeout. The total outer bound adds twice the registration window.
-
registration_timeout - Optional positive setup read window. Without it the transport's own setup deadline applies.
-
env_pass - Required list of quoted variable names. The whole child environment; values are resolved on the host.
-
command - ACP only, required executable path. Absolute or beginning with the literal {workspace_root}.
-
args - Optional quoted argument strings in order.
-
cwd - Required for both kinds: a literal absolute or {workspace_root}-leading directory, or cwd from PARAMETER. The bound form requires a String parameter on every action served and validates the supplied directory at dispatch.
-
permission - ACP only, required: deny or allow-once.
-
exit_grace - ACP only, required shutdown duration. Zero seconds closes stdin and kills immediately.
-
binary - Norn only, optional executable path. Without it the adapter resolves norn on PATH.
//! The second accepted `cwd` form: the directory arrives WITH the work.
//!
//! A worker that serves many jobs cannot name one tree in advance — which tree a
//! job concerns is a property of the job, not of the box the worker runs on. So
//! the harness binds its working directory to an action parameter, and the
//! checker proves that every action this harness actually serves declares that
//! parameter as a `String`.
//!
//! Nothing is softened by this. The document still has to SAY where the agent
//! stands; it just says it by naming the field the answer arrives in rather than
//! by writing a path only one machine could satisfy.
workflow review_a_tree
input tree: String
input question: String
outcome answered: type Answer, route success
type Answer { reply: String }
/// The canonical agent-outcome record: the checker demands the STRUCTURE, not
/// a blessed name.
type Reply { text: String, final_message: String, stop_reason: String, session_id: String }
worker reviewers
harness
kind norn
concurrency 2
reconnect_initial_backoff 5s
reconnect_max_backoff 1m
reconnect_max_attempts 50
env_pass "PATH", "HOME"
args "--account", "default"
cwd from repo
binary "/usr/local/bin/norn"
action review(repo: String, prompt: String) -> Reply
agent
step review
review(repo: tree, prompt: question) -> reply
route answered(reply: reply.text)