-
Notifications
You must be signed in to change notification settings - Fork 8
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.
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)
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)
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 ajob_id. -
background— launch-and-return with ajob_idimmediately. -
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)
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)
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)
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)
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)