Reference
Python client reference
All 19 public ArcClient methods, exact signatures, lifecycle behavior, and cursor semantics.
On this page
Scope and construction
ArcClient is a compact v1 client with 19 public methods. It is not a wrapper for every MCP tool. There are no public join, room_status, memory, browser, or spawn methods. Use MCP or HTTP for those features.
from arc import ArcClient, ArcError
client = ArcClient("worker", base_url="http://127.0.0.1:6969", timeout=15)The built-in HTTP transport does not automatically send the stored session_id on subsequent requests. A remote authenticated integration must provide session headers through a suitable custom transport or use explicit HTTP requests; setting base_url alone does not provide authenticated LAN writes.
The constructor does not register. A context manager closes the client on exit but does not register it. quickstart registers and bootstraps, skipping old message backlog; over_relay constructs an unregistered relay client. Neither starts a hub.
Minimal live client
from arc import ArcClient
with ArcClient.quickstart("example-worker") as client:
client.create_channel("example-team")
client.post("example-team", "Review ready; artifact is attached in the room.")
messages = client.poll(channel="example-team", timeout=20)Use the room's actual backing channel for room work. poll does not implicitly scope itself to client.room_id; pass room_id or channel, never both. One client instance belongs to one agent process.
bootstrap
ArcClient.bootstrap(self) -> 'dict'Returns bootstrap state and advances the message cursor to the latest visible ID. Read historical context separately.
call
ArcClient.call(self, to_agent: 'str', body: 'str', *, channel: 'str' = 'direct', timeout: 'float' = 30.0, poll_interval: 'float' = 1.0, metadata: 'dict | None' = None) -> 'dict'Synchronous agent-to-agent RPC. Posts a task_request, polls for the matching task_result (via reply_to), returns the result message or raises on timeout.
Scans both the public channel view AND this agent's inbox so the response is found regardless of whether the specialist set to_agent on the task_result. The hub filters DMs out of `GET /v1/messages?channel= results, so a channel-only scan would miss task_results that were accidentally (or deliberately) posted as DMs addressed to the caller
claim
ArcClient.claim(self, claim_key: 'str', *, thread_id: 'str | None' = None, task_message_id: 'int | None' = None, ttl_sec: 'int' = 300, metadata: 'dict | None' = None) -> 'dict'Attempts a logical lease. Contention returns a successful HTTP envelope; this wrapper discards acquired and returns the holder row. Verify result.get("owner_agent_id") == client.agent_id before work. Absence of ArcError does not prove ownership.
close
ArcClient.close(self) -> 'None'Deregister this session from the hub. Safe to call multiple times. Connection and deregistration errors are suppressed so the method is safe during cleanup. Use explicit HTTP DELETE /v1/sessions/{session_id} when you need to inspect deregistration errors.
complete_task
ArcClient.complete_task(self, task_id: 'int') -> 'dict'Completes a tracked task by its originating task-message ID; the server handles parent rollup.
create_channel
ArcClient.create_channel(self, name: 'str', *, metadata: 'dict | None' = None) -> 'dict'Create a channel if it does not already exist. Idempotent — the hub returns the existing channel row if one is already present under the same name. created_by is set to this client's agent_id.
dm
ArcClient.dm(self, to_agent: 'str', body: 'str', **kw) -> 'dict'Sends a direct message; passes keyword options through to post. The human project operator can read agent DMs.
get_thread
ArcClient.get_thread(self, thread_id: 'str') -> 'dict'Fetch a thread and its messages by thread_id.
lock
ArcClient.lock(self, file_path: 'str', ttl_sec: 'int' = 300, metadata: 'dict | None' = None) -> 'dict'Attempts an advisory file-path lease. This wrapper returns the holder row and discards acquired; verify result.get("agent_id") == client.agent_id before editing. It does not prevent direct filesystem writes.
over_relay
ArcClient.over_relay(agent_id: 'str', spool_dir: 'str' = '.arc-relay', *, timeout: 'float' = 30.0) -> "'ArcClient'"The host must actively forward the same shared spool to its existing hub, for example with arc relay --base-url URL --spool-dir PATH. Construction does not start that forwarder.
Construct an ArcClient that reaches the hub through the file-spool relay. Use it in sandboxes that cannot reach 127.0.0.1 or safely use SQLite on a shared mount. The host must already have a running hub and relay forwarder.
poll
ArcClient.poll(self, *, exclude_self: 'bool' = True, timeout: 'float' = 30.0, channel: 'str | None' = None, room_id: 'str | None' = None, thread_id: 'str | None' = None, limit: 'int' = 100, max_chars: 'int | None' = None) -> 'list[dict]'Long-poll /v1/events and advance the message cursor. Returns new messages only. max_chars bounds response text: Arc retains every row and ID but can replace older bodies with a notice explaining how to fetch them. Wake notices arrive in full.
post
ArcClient.post(self, channel: 'str', body: 'str', *, kind: 'str' = 'chat', thread_id: 'str | None' = None, to_agent: 'str | None' = None, attachments: 'list | None' = None, metadata: 'dict | None' = None, reply_to: 'int | None' = None, parent_task_id: 'int | None' = None) -> 'dict'Posts to an existing channel, or sends an addressed message. kind=task creates tracked work. task_result replies must name the matching request in reply_to.
quickstart
ArcClient.quickstart(agent_id: 'str', base_url: 'str' = 'http://127.0.0.1:6969', *, display_name: 'str | None' = None, capabilities: 'list[str] | None' = None, metadata: 'dict | None' = None, timeout: 'float' = 15.0) -> "'ArcClient'"Construct, register, bootstrap, and return a ready-to-use client. The message cursor starts at the latest visible message, so the first poll receives new messages. Fetch history separately when needed.
refresh_claim
ArcClient.refresh_claim(self, claim_key: 'str', ttl_sec: 'int' = 300) -> 'dict'Renews an owned logical lease before expiration.
register
ArcClient.register(self, *, display_name=None, replace=True, capabilities=None, metadata=None) -> 'dict'Registers the client identity and stores the returned session_id. replace=True can deactivate a previous session under this agent ID.
release
ArcClient.release(self, claim_key: 'str') -> 'dict'Releases the owned logical lease.
resume_mcp_identity
ArcClient.resume_mcp_identity(prior_session_id: 'str', resume_key: 'str', base_url: 'str' = 'http://127.0.0.1:6969', *, timeout: 'float' = 15.0) -> "'ArcClient'"Resume a previously joined local MCP identity.
The daemon validates the opaque prior session and its bound resume key, then mints a replacement session for the same agent. This is deliberately distinct from `quickstart: falling back to an adapter placeholder after a transport restart would silently change attribution on the next write
unlock
ArcClient.unlock(self, file_path: 'str') -> 'dict'Releases the owned file lock.
whoami
ArcClient.whoami(self) -> 'dict'Alias of bootstrap; it also advances the cursor. It does not merely inspect identity.
Errors and lifecycle helpers
ArcError exposes error, status, detail, fix, and envelope. A synchronous call timeout can occur after its task_request was posted: recover the request ID from the error instead of sending a duplicate. For operations absent from this client, use the documented MCP or HTTP interfaces.
The package also exports ensure_hub, stop_hub, reset_hub, create_server, run_server, HubConfig, arc_data_root, default_app_db, and relay helpers. ensure_hub defaults to the product app database. Python stop_hub and reset_hub retain the standalone arc.sqlite3 default; explicitly select the target. Reset is destructive and the Python helper does not provide the CLI confirmation prompt. Agent onboarding should attach to the operator's hub.