Documentation Index
Fetch the complete documentation index at: https://docs.blobhub.io/llms.txt
Use this file to discover all available pages before exploring further.
session_agent_harness is one of the job types the worker supports. A section
with this job_type attaches the worker to one BlobHub session, watches that session’s thread
session objects, and — when the user marks a thread as pending — spawns a coding agent
(Claude Code or Codex) inside the configured workspace and bridges items between the agent and
the thread.
The job type uses no new BlobHub backend endpoints — it speaks the existing session-object and
thread-item commands as the user whose API key the worker carries.
What a section does
For eachsession_agent_harness section in config.yaml, the worker:
- Claims a per-session
workerobject — the affinity lock and activity log; see Theworkersession object. - Discovers thread session objects in the session and runs the
handoff state machine for each — when a
user marks a thread
instance.state = "pending", the worker validates the workspace and spawns the configured coding agent. - Bridges items:
- Outbound — for each agent emission (text, tool call, tool result, thinking, status, turn
end, pending prompt), posts a thread item with brief text plus structured
metadata. See Thread items. - Inbound — coalesces other users’ thread items into the next agent turn.
- Outbound — for each agent emission (text, tool call, tool result, thinking, status, turn
end, pending prompt), posts a thread item with brief text plus structured
- Supports interactive prompts — when the agent pauses for input, posts a
pending_promptitem and resolves the user’s plain-text reply back to the agent. See Interactive prompts. - Resumes cleanly after restart — replays missed items, re-attaches the agent session, cancels stale prompts. See Recovery.
Identity
The worker acts on behalf of a single BlobHub user. Atlogin, the worker
validates the API key against GET /v1/users/me and records the returned user_id in
~/.blobhub-worker/identity.yaml. Every API call the worker subsequently makes is attributed to
that user.
Recommendation: run the worker under a dedicated service-account user with its own API key.
If a human is logged in as the same user and posts to the same thread via the web UI, the worker
classifies those posts as its own and ignores them — see
Reference.
The worker also carries an instance_id, generated fresh on every start. The instance_id is
informational (logs, dashboard) and is not an affinity key.
Sections
Asession_agent_harness section targets exactly one BlobHub session via
(org_id, blob_id, revision_id, session_id). One worker process can run any number of sections —
each runs independently. Two sections targeting the same session in the same config are refused
with DUPLICATE_SECTION_TARGET.
Configuration reference (including a full working example):
Configuration.
The worker session object
When a section attaches to a session, the worker creates (or claims) a session object whose alias
is worker. Its value is a thread-typed session object whose metadata carries:
metadata.user.user_id— the affinity key. A different worker (differentuser_id) refuses to attach withSESSION_OWNED_BY_DIFFERENT_USER.metadata.instance.*— the currently running instance (id, version, started_at, last_seen_at, status). Informational only.
attached, thread_active,
thread_failed, detached, etc. They form a visible worker activity log in the session.
There is no blobhub-worker detach command in v1. To free a session, delete the worker session
object via the API: delete_session_object(session_id, alias="worker"). The running worker
observes the deletion and stops that section cleanly.
Full shape and rules: The worker session object.
Threads and the agent state machine
Inside a session, the user creates thread session objects (one per task the agent should drive). The user populates each thread’s metadata with a workspace + anagent block, then sets
instance.state = "pending" to hand it off:
pending threads, validates the workspace, spawns
the coding agent inside work_folder, and drives instance.state through the canonical state
machine:
The worker writes only instance.state, and only the values active and failed. The user
owns workspace.* and agent.* and sets instance.state (pending to hand off, completed to
stop cleanly, reset failed → pending to retry). The agent resume pointer (agent_session_id) and
any error detail are local to the worker — they never appear on the wire envelope; a failure
surfaces server-side as a thread_failed item in the worker activity log.
Full object shape and field ownership:
Job Session Object. State-machine dynamics:
Handoff.
Items in / items out
While a thread isactive, two flows run in parallel:
- Inbound — the worker watches session events for
session_thread_item_posted{alias}. New user items are dropped through a self-filter (the worker’s own posts are ignored), coalesced into the next agent turn, and handed to the agent’s prompt. - Outbound — each agent emission (text segment, tool call, tool result, thinking, status,
turn-end, pending prompt) is translated into a thread item with brief text in
contentand structured detail inmetadata. The full untruncated payload is always written to a local log for recovery if the item is truncated to fit the 350 KB per-item budget.
Process model
session_agent_harness sections run in the same single worker process, on a single asyncio
event loop. The dashboard (Textual) is opt-in via --tui. By default the worker runs headless
with structured JSON logs to stderr, suitable for systemd or a container.
Single-instance enforcement is generic — see Filesystem layout.
See also
- Job Session Object — object shape, ownership, settings tiers.
- Configuration — full working example with one section.
- Filesystem Layout — per-section/per-thread on-disk state.
- Handoff — the lifecycle state-machine dynamics.
- Recovery — what survives restarts and what doesn’t.
- Reference — error codes and limitations.
- Thread session object reference

