Skip to content

Tooling Concepts

Jesse Vincent edited this page Aug 21, 2026 · 1 revision

Tooling: Concepts

The vocabulary the evener toolchain shares — sessions, turns, delegates, shell jobs, watches, and compaction. These terms show up identically in the CLI's saved state, the hub UI, the TUI, and evener-doctor's reports.

Sessions

A session is a durable evener conversation with transcript state. State auto-saves after each assistant turn under ${XDG_STATE_HOME:-~/.local/state}/evener/projects/<project-id>/sessions/, which is what powers --resume, transparent resume in the hub, and doctor's forensic reads. Session IDs are 22-character UUIDv7 base62 payloads; domain IDs like job_... keep their prefix outside the payload.

A turn of user input is driven by Session.ProcessInput: it runs model/tool rounds until the model delivers a result through the communicate tool, posts an ask_user question (interactive sessions only), or exhausts the round budget.

(Sources: docs/job-control.md, README.md, docs/architecture.md)

Turns

The persisted transcript is a sequence of typed turns (agent/schema/turn.go). Kinds include:

  • USER_INPUT, STEERING, ASSISTANT — the conversation itself.
  • TOOL_RESULTS — aggregated tool results from one round.
  • SYSTEM, ENVIRONMENT — harness-injected context (cwd, date, sandbox, git branch).
  • CHECKPOINT / SUMMARY — compaction artifacts (see below).
  • MODEL_SWITCH, TURN_FAILURE, HOOK_COMPLETED, ATTENTION_RESOLUTION — presentational/durable markers; most are excluded from what gets sent back to the model.

(Source: agent/schema/turn.go)

Shell jobs

A shell job is one asynchronous process unit owned by a session, identified by a durable job_... id. The shell tool has three modes:

  • foreground (default) — waits inline up to the session command timeout (120s in stock provider profiles); a still-running command is promoted to a durable background job and returns a job_id.
  • background — launch-and-return with a job_id immediately.
  • detached — disowns the process, returns only a PID; no job visibility, retention, notification, or control.

Completion is notification-driven: evener injects typed <job-notification> attention when a job terminates — do not poll. max_runtime_ms is an optional process-killing deadline, distinct from the foreground wait.

Shell lifecycle statuses: running, completed, failed, cancelled (intentional, confirmed stop), stopped (unattributed: runtime lost, timeout, unconfirmed cancel). After a process restart, believed-running shells reconcile to stopped/runtime_lost — provider-free, from shell evidence.

(Source: docs/job-control.md)

Delegates

A delegate is a durable child conversation — a stable subagent resource identified by dlg_..., owned by the root delegate-tree controller. delegate(...) starts a fresh delegate conversation and returns its stable id; delegate_send(to=dlg_...) steers a running delegate or starts an idle one's next private run. From inside a delegate, delegate_send(to="caller") sends a non-terminal update upward; final results go through communicate(end_turn=true).

Delegate status is just running or idle; the prior generation's outcome (completed / failed / exhausted / cancelled / stopped) is summarized separately as last_outcome. Nested delegation is allowance-gated: delegation_allowance defaults to 0 (a leaf that cannot itself delegate), and recursion requires both raising MaxSubagentDepth in config and granting a non-zero allowance per create. Subagents can always start shell jobs; those jobs are visible to the parent (single-hop forwarding), and job_stop on a dlg_... cascade-stops its whole subtree.

(Sources: docs/job-control.md, docs/subagent-runtime-contracts.md)

Watches

A watch (job_watch, identified by watch_id) delivers a bounded notification/frame to the watcher when a condition on a source is met — output matches, progress ticks, or event filters. Sources are typed: self, a granted parent, a job_..., or a dlg_.... Watches are for condition-triggered signals, not as a completion subscription — terminal completion already notifies automatically.

Watches compose into observer sidecars: delegate(watch_parent:true) + job_watch(source="parent") + communicate(end_turn=true) as the callback.

(Source: docs/job-control.md)

Job-control and transcript tools

The model-facing control surface: shell (job-capable), delegate, delegate_send, job_watch, job_status, job_list, job_stop. Handles are purpose-specific — job_... for shell work, dlg_... for delegates, watch_id for watches — and transcript refs name transcripts, not control targets. Reading evidence is separate: read_transcript(transcript_ref="job:<job_id>") reads retained shell output; a delegate's session transcript_ref reads its conversation; find_session_transcripts searches archived sessions. There is deliberately no model-facing wait, ack, kill, or close_agent.

(Source: docs/job-control.md)

Compaction

Long sessions manage context pressure through compaction (agent/internal/contextmgr, wired into the turn loop as ManageContext). Compaction folds older conversation history into a compact summary checkpoint so work can continue within the context window; the persisted artifacts are the CHECKPOINT turn (a deterministic checkpoint, "Layer 3") and the SUMMARY turn (an LLM-generated summary, "Layer 4"). The hub and TUI expose a manual compact action through the hub API.

(Sources: docs/architecture.md, agent/schema/turn.go, README.md)

Clone this wiki locally