Skip to content

Module II — live operation & sessions

Module II is the live operation view of the estate: what every agent session is doing right now, its live token and cost totals, a derived liveness state, and a reconstructable timeline. Where module I (inventory) materializes the durable estate, module II keeps a live operational overlay per session over the same observation stream — and shows only what that stream honestly carries.

Olivares 0.4 also launches official provider CLIs as owned children under a provider profile. That managed path is the same module. It does not replace the overlay, and it does not merge two homes that announce the same provider session id (CHANGELOG.md [26.9.0] B1/B2).

Module II is a bus-driven Core-layer module, sibling to inventory. It maintains a live record keyed by each session’s external reference, built from the cooperative observation stream — never polled, never fabricated. Per session it tracks:

  • the current action (the last tool used) and the resource/mode it touched;
  • the live token and cost totals, read from cost samples (the canonical cost ledger and FinOps are module XI, not here — this is the live figure only);
  • a derived liveness state (cc_state, still named for the original Claude Code derivation); and
  • a timeline to which every observed event is appended in ingest order.

The module registers two tenant-scoped entities. sessions.live holds the live record per session — current action/resource/mode, model reference, live input/output tokens, live cost, event and tool-call counts, and first/last event timestamps. sessions.timeline holds one replayable row per event, ordered by ingest. There is no stored lifecycle column: the cooperative stream carries no end-or-fail signal, so the only honest liveness signal is the derived cc_state.

cc_state is derived at read time from event recency — active / idle / ended — and flips to a silent-evasion state when the connector raises that finding (it is never written by the module itself). Reads are served under module routes (live list, single session, per-session timeline) plus a live SSE stream; every read requires the session read permission, and opening the stream is auto-audited. The SSE channel is strictly tenant-isolated (a client receives only snapshots for its authorized tenant) and best-effort (a slow client drops the intermediate frame and gets the next — ingest never blocks).

A provider profile is the durable identity of one configured provider instance on one execution environment: driver, environment, and the canonical config_home / user_home. It is not an authenticated provider account. Register, rename, disable/enable and retire live under /v1/m/sessions/provider-profiles. Paths appear only on the admin configuration read. A launch names provider_profile_ref; the server resolves the homes and persists a non-secret snapshot on the run before spawn (CHANGELOG.md [26.9.0] B1; web/src/features/agentops/types.ts).

An observation folds into the live row of its channel, computed by the server from the host-stamped source registration (CHANGELOG.md [26.9.0] B2):

Channel Meaning
legacy no registration
observed a source dedicated to a profile by a binding approved at host admission for the exact applied revision
source a known registration with no verifiable profile
managed a run the plane launched; the only row carrying canonical_sid and run_ref

Every live row exposes live_ref and attribution. Two homes that announce the same provider session id are two rows with two timelines. Read one row with GET /v1/m/sessions/live/by-id/{live_ref} (and its timeline / stream / runs query). Bare external-id routes stay and are legacy: they answer for the legacy row only.

Drivers are registered on each node at boot. At launch, the engine uses the newest verified managed install, then the CLI on the engine’s PATH. OLIVARES_SESSION_RUNTIME_CLAUDE_BIN, _CODEX_BIN, _GROK_BIN and _OPENCODE_BIN explicitly override this resolution (see Configuration). If no executable resolves, launch is refused. Other readiness checks, including profile authentication and launch policy, still apply. Operator steps: Operate a provider session.

Managed-run lifecycle and restart boundaries

Section titled “Managed-run lifecycle and restart boundaries”

Sessions is a kernel module: it keeps running even when it is not in the saved module selection. Turning off an optional module does not reset session data.

The managed-run API under /v1/m/sessions/runs and olivares session use the same runtime. Run reads require sessions:run:read; launch, input, stop and resume require sessions:run:write. A viewer can read a run without being allowed to stop it. Tenant and workspace authority still apply to each run.

Terminal window
olivares session ls -o json
olivares session show <session> -o json
olivares session send <session> "continue the task"
olivares session stop <session>
olivares session resume <session>

A message can carry images. olivares session send <session> --attach shot.png "what is wrong here?" and the console composer (paste, drop or the paperclip) store each PNG, JPEG, WebP or GIF with the session, up to four per message and 3.75 MB each, then send them with the text; a message needs its text, so an image alone is not sent (the CLI and the composer ask for it). Claude Code receives an image content block and Codex its own image input; a tool with no image input refuses the message by name before anything is sent. The API is POST /v1/m/sessions/runs/{ref}/attachments (the image, base64), GET .../attachments/{id} and attachments on .../input. Images live under the data directory, per tenant and session, and are removed with the session.

Stopped runs, their provider-profile and workspace references, and lifecycle events survive an engine restart. Resume starts a new owned child for the existing run. Live attach output is an in-memory bounded ring; retained run metadata and lifecycle events do not promise a persisted conversation transcript. Recording policy and the tool’s own resume support remain separate requirements.

Managed sessions and local stdio MCP servers require Linux Landlock. If the engine host cannot provide it, the launch is refused before the tool starts; no permission preset opts out. Enable Landlock on the engine host and run olivares doctor there to check availability. A doctor check on another machine only describes that machine, not the remote engine.

Confined children receive access to their session folder, profile homes and a private temporary directory. The engine database, secret-store key and engine configuration stay outside those grants. This filesystem boundary does not provide network isolation or container isolation.

A session’s folder is writable, and the Git metadata inside it would otherwise be too: a hook or a core.hooksPath the session wrote runs the next time you use git there. Landlock cannot deny a path inside a directory it grants, so the session (and a local MCP server started in the folder) runs in a mount namespace of its own in which the repository’s hooks directory and config file, config.worktree, and in a linked worktree the files that name the common directory, are read-only; the Git directory cannot be moved away. Git reads commondir and config.worktree from a Git directory when they exist, so the launch creates them where they are missing (a commondir that names the directory itself, an empty config.worktree; both mean nothing to git) and binds them read-only, so the session cannot create its own. git add, git commit and new files work as before. git config in the folder is refused: a session with no Git identity commits with git -c user.name=... -c user.email=... commit or the GIT_AUTHOR_* and GIT_COMMITTER_* variables. A branch made from a remote-tracking branch is created without its upstream (git reports that it could not write the configuration file).

The protection of a file lasts as long as the file. It is a mount on the file in the session’s namespace, and when something outside the session deletes the file or renames another over it, the mount is gone there and the running session can write the new file. Git replaces config that way for git config, git remote add, git push -u, git branch -u, git checkout -b <branch> <remote>/<branch> and git sparse-checkout, so run them before a session starts, or start a new session after them. An empty hooks directory that is removed is the same case; one with files in it cannot be replaced. This does not cover other ways a repository can run code, such as a core.hooksPath that points into the folder, a sibling worktree’s entry, a submodule’s Git directory, a repository nested in the folder, a folder that has no .git yet, or the same files reachable through a second mount point.

This needs unprivileged user and mount namespaces. Where the host lacks them, the session still starts and its confinement line says that the Git hooks and configuration stay writable. The packaged systemd units and the Compose profiles allow the mount namespace and the mount call this needs. A host that has the namespaces but cannot bind one of the files at launch (a path removed in between, an unusual filesystem) does not start the session: a protection the host should give and does not is a failure, not a limit.

Module II consumes the same minimal-data observation stream as inventory — edge.observed, cost.sampled and finding.reported. Only edges whose origin is a session produce live operation; cost samples tied to a session add to the live token/cost figure (no CostRecord is written here); session-subject findings are annotated, and an anti-evasion finding marks the evasion state. Two fields are derived live from those same signals: agent_ref from a session’s attributed agent, and summary from a context-compaction (forensic) finding whose title is summary-safe by contract — never an LLM-fabricated summary.