avatar.__all__ — the
stable surface to build against. Deep imports of internal modules may break
without notice; the generated API reference covers internals page by page.
The SDK map
The__all__ list is grouped by role, and the grouping is the map:
The Harness facade
Harness assembles a run’s collaborators; every one is overridable via a
constructor kwarg (model, tools, verifier, policy, context builder, emitter) —
swap a seam, keep the rest:
Harness.from_env() constructs without an API key — credentials are needed
only when the model is first called, so a fully wired harness (e.g. with a fake
model, in tests) never touches the network.
The two-plane Session
The interactive contract, and the load-bearing boundary of the whole SDK
(design §13): observation flows out, control flows in, and the two never mix.
session.events(). An async stream of typed HarnessEvents.
It subscribes eagerly (at call time, not first iteration), so a consumer
created before run() misses nothing. Each call yields a fresh, independent
stream — any number of observers can watch one run, and a slow or broken
observer can never block the loop or its peers. The stream ends after
agent_end.
Control — two methods, nothing else.
await session.resolve_approval(approval_id, *, allow, remember=False)— answer a pendingApprovalRequested. Withallow=True, remember=True(the “always” choice) the session stores anApprovalGrantscoped to the call’s program (argv[0]), so later calls sharing that program auto-allow — observable asApprovalResolved(via="grant"), never silent. Grants are session-scoped, never global, and never cover tier-4 (destructive/external) actions.await session.cancel(reason)— trip the cancellation token. The loop observes it at the next checkpoint, records the interruption as feedback, and settles to a terminal state; any in-flight approval is denied so a gated run can’t hang.
Approval prompts fire for
ask-gated calls: tier-3 tools (run_command) and
sensitive-path denylist hits. The edit tools (str_replace/write_file/delete_file)
are tier 1 — they auto-allow once their target paths validate inside the workspace,
and the verifier judges the resulting diff.journal=JsonlEventJournal(path) to harness.session(...)
and every event is written write-ahead — committed to disk before any
subscriber sees it — so even a crashed consumer leaves a complete, replayable
record. load_events(path) reloads the file as typed events.
The event catalog
Every event extendsEventBase (schema_version, bus-assigned monotonic
event_id, session_id, task_id, turn, ts) and is exhaustively matchable
on its type discriminator:
Two further events ride the stream and the journal but are not yet exported in
__all__ (deep-import from avatar.event_types for now): ModelUsage
(prompt_tokens/completion_tokens per turn) and DecisionError (a malformed
model reply, with a capped raw excerpt).
The union is closed and versioned: parse_event rejects unknown types, and
the journal round-trips every event verbatim.
Multi-turn conversations — ReplSession
ReplSession is the scope above one task: conversation history, the sequence
of per-goal TaskStates, session-scoped grants, and the current mode. Each goal
runs as a fresh task through the same single-task Session — batch is just the
degenerate one-submit case.
- History seeding — prior turns become explicit evidence on the next task (structured seeding, not transcript bleed).
- Grant carry-over — an “always allow” granted in one goal persists to later
goals (shared by reference with each per-goal
Session). - Mode routing — each goal’s
task_kindresolves as explicit/modeoverride → LLM classifier (whenAVATAR_CLASSIFIER_MODELis set) → word heuristic. The verdict is visible (repl.last_mode_source) and always correctable — never silent control. @pathgrounding —@src/foo.pyin a goal seeds that file as initial evidence, read through the workspace so the sensitive-path denylist applies.- Meta commands —
repl.is_meta(text)/repl.run_meta(text)handle/help,/quit,/state,/mode,/plan,/diff,/permissionslocally; they never reach the model. - Plan mode —
repl.submit_plan(prompt, decide)drives a no-net-change plan → approve/revise → build, with the approved plan seeding the edit task as a constraint. - Verification authority — the REPL default is conversational: the
verifier always runs and steers (a failing check drives repair, or a
gated contract amendment), and at repair exhaustion the turn defers to the
human (
blockedwith a question) instead of pronouncing failure.ReplSession(harness, auto=True)makes exhaustion a hardfailed. A failed verdict is never delivered assuccess(§23.5, ADR-0046).
jo-cli package, the jo command — a
consumer of the core, never part of it) is exactly this surface rendered
full-screen — nothing it does is unavailable to your own UI.
Configuration
All fields ofHarnessConfig, env-overridable with the AVATAR_ prefix (or a
local .env):
Testing without a network
ModelClient is a one-method protocol, so a scripted fake makes any flow
deterministic and offline: