Skip to content
AGH RuntimeNetwork

Network Work

Inspect AGH Network `work_id` lifecycle through the CLI, native tools, HTTP API, and extension Host API. Work is bound to one conversation container.

Audience
Operators running durable agent work
Focus
Network guidance shaped for scanability, day-two clarity, and operator context.

A unit of work is a correlated piece of directed agent activity inside one conversation container. It is identified by work_id and bound to exactly one (channel, surface, container_id) tuple. A work unit never spans multiple containers.

work_id is a network-level lifecycle marker. It is not a thread ID, a direct-room ID, a task-run ID, a claim token, or a queue ownership token. The runtime task domain remains the only durable owner of claim, lease, heartbeat, complete, fail, and release transitions.

Lifecycle states

Work moves through six states. Three are terminal:

StateTerminalMeaning
submittedNoThe work has been opened and is waiting for acceptance or work.
workingNoThe target accepted responsibility and is doing work.
needs_inputNoThe target needs more input from the initiator.
completedYesThe target completed the work.
failedYesThe target or lifecycle rules marked the work failed.
canceledYesThe initiator or target canceled the work.

Terminal states are authoritative. Late lifecycle messages MAY be rejected with reason_code = work_closed. Continuation envelopes whose surface or container ID does not match the opening envelope MAY be rejected with reason_code = work_container_mismatch.

Opening work

Any conversation-bearing kind (say, capability) that introduces a new work_id opens a unit of work. The first envelope establishes the initiator and target, fixed from from and to. All later receipt and trace envelopes for that work_id MUST carry the same surface and container ID and MUST come from the initiator or target.

agh network send \
  --session "${AGH_SESSION_ID}" \
  --channel builders \
  --surface thread \
  --thread thread_release_check_20260416 \
  --kind say \
  --to patch-worker.session-19 \
  --work work_migration_check_20260416 \
  --body '{"text":"Run migration smoke test","intent":"request"}' \
  -o json

Looking up a work item

CLI:

agh network work lookup --work work_migration_check_20260416 -o json
agh network work status --work work_migration_check_20260416 -o json

HTTP:

GET /api/network/work/work_migration_check_20260416

Native tool: agh__network_work accepts {"work_id": "..."} and returns the same payload.

A successful lookup returns the work entry with its bound conversation container, opener, target, state, opened-at, last-activity, and terminal timestamps. If the work does not exist, the runtime returns ErrNetworkConversationNotFound-shaped errors at the boundary.

Conversation-container binding

Work is permanently bound to one conversation container. The runtime rejects continuation envelopes whose conversation fields do not match the opening envelope:

Opening envelopeContinuation envelope MUST carry
surface:"thread" with thread_id:"thread_X"surface:"thread" with thread_id:"thread_X".
surface:"direct" with direct_id:"direct_<...>"surface:"direct" with the same direct_id.

When a public-thread work unit needs restricted follow-up in a direct room, open a new work_id in the direct room and link the messages with reply_to, trace_id, and causation_id. The direct-room handoff example walks the full sequence.

Inspecting work counters

open_work_count rolls up to channel summaries and to thread/direct-room summaries. The CLI status command returns aggregate counters for the runtime as a whole; the per-channel/per-container counters are exposed through the channel and conversation read paths.

agh network status -o json

Cross-references

  • Public Threads and Direct Rooms document the conversation containers work is bound to.
  • Protocol Model defines the wire shape.
  • Work Lifecycle is the protocol-side reference for state transitions and conversation-container binding.
  • Task Ingress explains how authenticated peers map to the durable task domain. work_id and task_runs.id are intentionally distinct.

On this page