Unreleased These pages document the current main build and are not a stable-release promise. View the latest release
Skip to content

Remote sessions ​

External adapters connect to CireilClaw over TLS WebSockets, open conversations they own, and register tools available only in those conversations. An adapter is responsible for authenticating its own users and enforcing external-world permissions. Pairing an adapter does not make its users harness operators.

Listener configuration ​

The listener and discovery are disabled by default. Create config/remote.toml below the runtime root:

toml
enabled = true
listenAddresses = ["127.0.0.1"]
port = 7443
certificate = "remote.pfx"
# certificatePasswordFile = "remote-password.txt"
discoveryEnabled = false
# discoveryInterfaces = ["enp1s0"]
# discoveryInstance = "cireilclaw"

Certificate and password paths are relative to the runtime root unless absolute. The certificate is PKCS#12 with a private key. On Unix, private files must not be accessible to group or other users; use mode 0600. Restart the runtime after changing listener configuration. Bind explicit IP addresses; the adapter-facing endpoint is wss://HOST:7443/remote/v2. Only cireilclaw.remote.v2 WebSocket upgrades are accepted. Compression and binary messages are unsupported.

For LAN discovery, explicitly enable it and select existing, up, multicast-capable network interfaces. The listener must bind an address on those interfaces, or a corresponding wildcard address. Discovery advertises _cireilclaw._tcp with only protocol version and endpoint path in TXT. It provides an address, not trust: never obtain a certificate pin or credentials from discovery. Choose a distinct lowercase DNS label of 1–40 characters for discoveryInstance; an initial name conflict fails startup.

Bootstrapping and validating TLS ​

Use an existing CA-issued PKCS#12 server identity, or create a self-signed identity whose certificate pin you transfer through the trusted pairing channel. This example uses a LAN address; replace the runtime root, address, and DNS name with your deployment's values:

sh
ROOT=/path/to/runtime
LAN_IP=192.168.1.50
DNS_NAME=cireilclaw.local
umask 077
openssl req -x509 -newkey rsa:3072 -nodes -days 365 \
  -subj "/CN=$DNS_NAME" \
  -addext "subjectAltName=DNS:$DNS_NAME,IP:$LAN_IP" \
  -addext "extendedKeyUsage=serverAuth" \
  -keyout "$ROOT/remote-key.pem" -out "$ROOT/remote-cert.pem"
openssl pkcs12 -export -passout pass: \
  -inkey "$ROOT/remote-key.pem" -in "$ROOT/remote-cert.pem" \
  -out "$ROOT/remote.pfx"
chmod 600 "$ROOT/remote.pfx"
cireilclaw dry-run --root "$ROOT"

The empty export password relies on owner-only filesystem protection. If you use a PKCS#12 password, put it in a separate mode-0600 file and configure certificatePasswordFile; do not put the password in command arguments or the listener TOML. Protect a backup of the identity and remove the temporary PEM files after checking the bundle. For LAN access, replace listenAddresses with the chosen explicit address and use it in the WSS endpoint. Discovery does not configure the listener or establish trust.

dry-run uses the same identity loader as startup and invitation issuance. An enabled listener fails validation if its certificate or password file is missing or shared, the PKCS#12 bundle cannot be loaded, or the identity has no private key. It imports keys ephemerally, starts no listener, and writes no runtime state. A successful dry-run does not prove that the requested port is free or that another machine can reach the endpoint.

Pairing and grants ​

Configure an agent and its enabled tools first. Save a separate operator grant file, for example adapter-grants.toml:

toml
agents = ["helper"]
create = true
resume = true
maxSessions = 1
remoteTools = [{ exact = "minecraft.view_inventory" }]
harnessTools = ["respond", "no-response"]

All six fields are required. Remote tool grants use either an exact identifier or a literal dot-terminated namespace, such as { namespace = "minecraft." }. Matching is case-sensitive. A namespace does not match a similarly spelled prefix without the dot. Harness tools must also be enabled on the agent; an empty allowlist grants no ambient capabilities. Granting filesystem, shell, plugin, scheduling, or cross-session tools deliberately expands the adapter's authority. Existing sandbox and conditional-access checks still apply.

Create a ten-minute, single-use invitation:

sh
cireilclaw remote invite --grants adapter-grants.toml --output pairing.toml --endpoint wss://HOST:7443/remote/v2

Use --root PATH consistently when the runtime is not at its default location. The command creates a new owner-only TOML file containing the endpoint, certificate DER SHA-256 pin, and invitation. It refuses to overwrite an existing file and does not print the secret. Transfer this file through a trusted channel. The adapter must verify the pin before sending any invitation or credential, then persist its issued adapter ID and credential privately. Invitations cannot be redeemed twice, including if the first credential response was lost.

When the host is running, administration uses its owner-only local Unix socket. With the host stopped, the same command operates under the runtime mutation and remote authority locks without starting agents. Do not edit the remote database directly.

Administration ​

sh
cireilclaw remote list
cireilclaw remote inspect --adapter ADAPTER_ID
cireilclaw remote inspect --session remote:SESSION_ID
cireilclaw remote update-grants --adapter ADAPTER_ID --grants adapter-grants.toml
cireilclaw remote revoke --adapter ADAPTER_ID
cireilclaw remote revoke-invitations
cireilclaw remote reissue --adapter ADAPTER_ID --output replacement.toml --endpoint wss://HOST:7443/remote/v2
cireilclaw remote transfer --session remote:SESSION_ID --adapter NEW_ADAPTER_ID
cireilclaw remote delete --session remote:SESSION_ID

Revocation and reissue terminate live authenticated connections. Removing an agent grant also terminates that agent's attachments and fences outbound delivery; changing only tool grants preserves an otherwise authorized attachment while denying subsequent unauthorized dispatch. Reissue preserves the adapter identity and its owned sessions while invalidating old credentials. Transfer and deletion require an offline session; an attached session returns already_attached. Deletion removes remote ownership/recovery records and conversation history. Destructive operations prompt for confirmation; --yes is available for intentional automation.

If conversation-history cleanup fails during deletion, remote access has already been withdrawn. Fix the storage failure and retry remote delete with the same session ID, including after a host restart; the host retains the cleanup mapping until deletion succeeds.

list and inspect print metadata-only JSON: current grants, ownership, active credential counts, queued/running/unknown submission counts, unacknowledged output counts, and pending or unknown invocation receipts with caller provenance. They never print credentials, verifiers, message text, history, tool arguments, or results. inspect requires exactly one of --adapter and --session. Pages contain up to 100 entries; pass the returned nextCursor as --after to continue. liveStateAvailable distinguishes authoritative running-host attachment information from offline metadata. Offline reads do not create, migrate, or lock remote authority state.

Transfer never merges sessions. If the destination adapter already owns a different session for the same agent and external reference, ownership_conflict leaves both sessions unchanged. Inspect both sessions, choose another destination adapter, or archive and deliberately delete the conflicting destination before retrying. Revoking or updating a nonexistent adapter fails rather than reporting success.

An unexpected certificate always fails closed. Certificate replacement requires operator-issued pairing material with the new pin. Reissue credentials for the existing identity, or pair a new identity and explicitly transfer offline sessions. Neither endpoint changes nor external references automatically migrate ownership.

Sessions, tools, and recovery ​

One WebSocket attaches one session. Opening the same external reference for the same adapter and agent recovers the existing session, including after a lost first attachment response. A second connection cannot displace a live attachment. Each attachment has a fresh generation and requires a fresh manifest beginning at revision 1; queued work remains paused until registration succeeds, even when the manifest is empty. Tool manifests are session-local, and in-progress turns retain their captured revision until retirement.

Submissions use an adapter-generated messageId and an adapter-attested opaque actorId for the authenticated external user. Retry the same text and actor with the same ID to retrieve durable status, not with a new ID. A reused ID with different text, actor, or attesting adapter is rejected. Queued submissions survive restart. Running submissions interrupted by a crash or disconnect become unknown and are not automatically restarted. Terminal receipts remain for seven days; do not retry an older ambiguous submission without operator review.

Failed or cancelled remote turns retain conversation records of completed tool calls and delivered responses. Their effects are not rolled back, and a later turn can see those records. A terminal failure or unknown outcome is not permission to repeat an external action.

Outputs are persisted with their original caller before delivery and replayed in creation order until acknowledged. Deduplicate durable consumption by outputId, then send ack_output; delivery is at least once, not exactly once. The caller retains the original submission's session, message, adapter, and actor even for deferred cross-session work; the envelope identifies the destination. Acknowledgement receipts remain for seven days. Exhausting the 1,000-record or 8 MiB unacknowledged-output budget pauses output production and blocks new submissions until acknowledgements free capacity. Submission and output production each have a rolling 60-per-minute adapter allowance that survives reconnect and restart.

While initial output replay is backlogged, manifest registration and output acknowledgements remain valid. Their replies wait for room in the bounded transport queue rather than disconnecting the adapter. Continue receiving replay while awaiting those replies.

For a clean shutdown, continue receiving output and acknowledgement replies until session_closed, then complete the WebSocket close handshake rather than immediately aborting the socket. The harness waits at most five seconds for a normal close response and forcibly tears down a stalled peer after that deadline. A peer-initiated close also receives a close response. Disconnect still releases the attachment without deleting history; if a submission's final receipt was lost, recover its status with its original ID rather than repeating the work.

Remote tool execution has success, failure, and unknown outcomes. Cancellation, timeout, and a lost result do not prove rollback. Never automatically replay an ambiguous side-effecting invocation. Tools carry immutable caller authority separately from model arguments; the adapter must enforce that user's external permissions before executing them or routing output. Scheduling from a remote session is restricted to main-session execution targeting a session owned by the same adapter; isolated execution and webhooks are not available through this capability. A reminder persists the original caller and message, with its triggering scheduleId. Unstarted one-shots wait while the target is offline, busy, unregistered, or unauthorized. Once execution starts, the one-shot is consumed durably before engine effects and is not automatically repeated after failure, uncertainty, or restart.

Replacing an unstarted remote reminder with the same job ID and caller supersedes the previous revision, including an identical replacement. Only the current revision can execute; changing the caller's in-memory job object after scheduling does not alter queued work.

Remote invocation deadlines include waiting for outbound capacity. A cancelled or expired invocation that never entered the outbound queue is a definite failure; once admitted to that queue, its unresolved outcome remains conservatively unknown. Expired or cancelled queued invocations are skipped before send, and best-effort cancellation cannot wait indefinitely behind output replay.

For a remote main-session schedule, delivery = "none" discards response output without changing the target session, caller authority, or tool execution. The scheduled conversation remains in history, and ordinary delivery resumes after the job.

Back up host-level state/remote.db together with agent session databases while stopped, or using a consistent SQLite backup procedure. Include private adapter pairing records in your protected recovery plan. Live attachments and executable handlers are not persisted.

Direct-address example ​

The repository's examples/RemoteAdapter/ application demonstrates pinned TLS pairing, private credential persistence, resumption, durable submission retries and output receipts, and parameterless minecraft.view_inventory with deterministic inventory data selected by attested caller. It does not require Minecraft:

sh
dotnet run --project examples/RemoteAdapter -- pairing.toml adapter-state.toml helper minecraft-world lys-player-id "Show my inventory"

The example is included in CireilClaw.slnx, so normal solution builds and formatting checks cover it alongside the application.

Use the same state file, agent, external reference, external user ID, and pending message to reconnect. The example saves the original submission ID, text, and actor before sending, then reuses them after a lost acknowledgement. It rejects saved agent/world mismatches or a different pending actor or text before connecting. Existing saved credentials take precedence over the invitation file. For a reissued credential, provide the replacement pairing file and a new state file. The agent's inference provider must support tool calls and have respond enabled.

The example writes owner-only durable output receipts under <state-file>.outputs/ before acknowledgement, and replay does not print the same receipt again. Those files are the canonical consumption record. Console printing is best-effort: a crash after committing a receipt but before printing can omit that output from the console. Back up the receipts together with the state file. The CLI reports bounded protocol error codes and retryability without echoing remote error messages or exception payloads; retry only an operation whose durable status permits it.

The explicit external user ID is an example input, not user authentication. A production adapter must obtain it from its authenticated external user, enforce world and operation permissions, and never trust a model-selected player. The example rejects all inventory arguments, including a player selector, and uses only the out-of-band caller.

Adapter authors should use the source repository's docs/architecture/remote-session-protocol.md for the complete wire contract, supported schema subset, and fixed version 2 limits.

Upgrade from version 1 ​

Version 2 is a clean cutover, not a compatible version 1 endpoint. This changes adapter contracts and requires a major application release.

  1. Stop admission and drain or explicitly resolve accepted version 1 submissions, unacknowledged outputs, ambiguous invocations, and remote reminders before upgrading. Never automatically replay an unknown operation.
  2. Stop the host and back up state/remote.db, the agent databases and job state, and private adapter pairing/state files and output receipts consistently.
  3. Update adapters to /remote/v2, cireilclaw.remote.v2, envelope v: 2, and version 2 hello. Obtain an authenticated external user for every submission and send its actorId. Consume and enforce the caller on tool invocations and output, including the originating IDs and optional scheduleId; do not put identity authority in model arguments.
  4. Upgrade the host. Its remote database migrates to caller-aware schema version 3. Older binaries cannot safely reopen it; downgrade only by restoring the complete pre-upgrade backups.
  5. Use remote list and remote inspect to review retained receipts and ownership. Old queued work, outputs, and reminders without attested caller authority remain held. Do not guess actors or grant them a synthetic system identity. Archive and explicitly resolve obsolete work, deliberately delete an obsolete session when appropriate, and recreate a necessary request or reminder through a freshly attested user only after ruling out prior execution.
  6. The example rejects legacy state missing agent/world binding or pending actor. Resolve any legacy pending submission against its durable receipt before creating new state. Verify the existing adapter identity, owned session, agent, and external reference before deliberately migrating endpoint, pin, credential, and session fields into a version 2 state record with explicit binding, or use a fresh pairing record and explicitly transfer an offline session. Preserve output receipts; do not invent a pending actor.

Are you an agent? Prefer this page's raw Markdown document: follow its text/markdown alternate link, use its .md URL, or add ?md=1 to the page URL.