Skip to article

OpalSpan Agent CLI reference

The assistant operates opalspan. The compatible forge executable accepts the same commands; new capability examples and next actions use opalspan. This source does not republish an existing public generation. Use current help/ capabilities and release applicability, not project defaults.

Agent harness support skills

opalspan skills status --harness copilot|codex|claude|opencode
opalspan skills status --path <skill-directory> --include-it-support
opalspan skills status --harness <chosen-harness> --include-it-support --check-online
# Obtain the user's approval for this destination and selected content first.
opalspan skills install --harness <chosen-harness> --approve
opalspan skills update --path <skill-directory> --include-it-support --approve

Choose exactly one harness or custom path; none are selected automatically. OpalSpan guidance comes from canonical resources embedded at build time in the signed CLI, works independently and requires no private GitHub access. Install uses each client's supported skill directory. Select Copilot with --harness copilot; Codex uses ~/.agents/skills, Claude ~/.claude/skills, and OpenCode uses ~/.config/opencode/skills. Codex's native user directory is also discovered by Copilot; this platform convention is disclosed, not a request to install into every client. A custom export does not register a client; configure its discovery separately.

status is read-only/offline by default, showing available and observed versions, missing/current/outdated/modified/unknown state and duplicates across known user and plugin-cache locations. Native plugin versions are observed metadata: current-version-unverified and newer-version-unverified report exact known versions without claiming unmodified files or enabled state; unknown is not missing. Discovery is bounded to the selected user's known roots, not every repository or custom client configuration. Existing native plugins update through skills update --harness after human approval: Copilot/Claude delegate the selected plugin update; Codex upgrades only its selected marketplace then adds that selected plugin. No loose duplicate is created. Failed updates preserve authentication and return a failure, not an automatic retry. Automatic installs, per-command network checks and repeated work-session prompts are not used. guide/doctor suggest an optional status review once per available product/public version and detected harness set. A zero-byte local notice under ~/.config/opalspan/skill-notices prevents repeated nags; it is not an installation receipt.

--include-it-support explicitly selects the public MIT library. Installation and updates fetch the pinned public 0.4.0 release, verifying its full SHA-256 before reading the canonical export, preserving its license per skill. Offline status compares its packaged version baseline, not latest upstream; --check-online explicitly verifies/downloads that pinned release; no arbitrary main drift is installed. No generic library content is maintained inside the CLI source.

--approve attests prior human approval; an agent cannot approve itself. Each exported skill has an exact version/file-hash receipt. Updates stage locally and rename directories, refusing untracked, modified, duplicate or newer content; unrelated folders and credentials remain untouched. Symlink/reparse paths are rejected. A failed/interrupted update may leave an owned .opalspan-backup-* directory; retain and inspect it instead of deleting it or replaying blindly. Restart the selected harness if its skill list does not refresh automatically.

Product usage evidence and bug reports

opalspan platform usage --days 7 --tenant <operator-profile>
opalspan platform usage --days 30 --tenant <operator-profile>

The versioned JSON contains UTC daily buckets, normalized screen/action/outcome counts, comparable retained prior-window counts and explicit coverage limits. Exclude synthetic: true from product-use rankings. Counts are visits/actions, not unique people; absent ingestion is not measured zero. The current UTC day and best-effort client collection are incomplete. A 30-day prior window exceeds the 30-day retention period. Workspace Admin membership is not platform-operator permission; the server checks the configured authenticated issuer/subject. No scheduled analysis or new agent identity is created.

Any signed-in human can report a bug without choosing a workspace:

opalspan bug-reports preview --report-file <existing-private-report.json> --tenant <profile>
# Show the report to the user and obtain permission before sending.
opalspan bug-reports submit --report-file <same-private-report.json> --confirm <reviewed-file-sha256> --tenant <profile>
opalspan bug-reports show --id <original-report-uuid> --tenant <profile>

The agent prepares one protected UTF-8 JSON file before dispatch, for example:

{ "reportId": "00000000-0000-4000-8000-000000000001", "message": "Describe the bug without credentials or private customer content.", "screen": "work" }

Report files deserialize to typed requests and serialize for HTTP; do not promise byte-identical HTTP JSON. Keep original private file/UUID for recovery. Current deliveryState issue-created confirms a private issue; historical mailState/mailCode retain prior meaning. Confirmed/nonadmitted report rows retain 30 days, pending/ uncertain originals survive outages. Private S3 downloads have independent fixed 90-day bearer expiry from publication; anyone holding a link can download without login until expiry. This is not GitHub issue deletion or automatic resend.

opalspan search --kind devices|cases|companies|contacts|members|team|automations|sessions|history|mistakes|temporary|enrollment|invitations|releases|workspaces --query <text> [--cursor <opaque>] [--limit <1-100>] [--profile relevance|chronology] --out <new-private.json>

The response contains original matching fields and UTF-16 ranges, not only entity labels. Follow its opaque cursor with unchanged query/scope; partial coverage is not proof of absence. Search is a read and may be retried after availability returns. Exact record authorization is rechecked before subsequent action. Automation names/targets are searched, not encrypted prompts/results. Private messages, files, access codes and credentials are outside this metadata index.

Fleet, views and reviewed bulk work

opalspan fleet query|group-context --input <private-query.json|->
opalspan fleet catalog list --kind site|department|tag [--company-id <uuid>] [--search <text>] [--archive active|archived|all] [--offset <0-50000>] [--limit <1-100>]
opalspan fleet catalog show --id <uuid>
opalspan fleet catalog create --input <private-classification.json|->
opalspan fleet catalog rename --id <uuid> --input <private-versioned-name.json|->
opalspan fleet catalog archive|restore --id <uuid> --version <original-version>
opalspan fleet enrollment-defaults list [--archive active|archived|all] [--offset <0-50000>] [--limit <1-100>]
opalspan fleet enrollment-defaults show --id <uuid> [--offset <0-50000>] [--limit <1-100>]
opalspan fleet enrollment-defaults create --input <private-default.json|->
opalspan fleet enrollment-defaults update --id <uuid> --input <private-versioned-default.json|->
opalspan fleet enrollment-defaults archive|restore --id <uuid> --version <original-version>
opalspan fleet views list [--search <text>] [--archive active|archived|all] [--offset <0-50000>] [--limit <1-100>]
opalspan fleet views show --id <uuid>
opalspan fleet views create --input <private-view.json|->
opalspan fleet views update|rename --id <uuid> --input <private-versioned-view.json|->
opalspan fleet views archive|restore --id <uuid> --version <original-version>
opalspan fleet organization prepare --input <private-original-request.json|->
opalspan fleet organization execute --id <review-id> --request-id <original-request-id>
opalspan fleet organization status --id <review-id> [--offset <0-50000>] [--limit <1-100>]
opalspan fleet organization reconcile --id <review-id>
opalspan fleet automation targets|prepare --input <private-selection.json|->
opalspan fleet automation show --preparation <uuid>
opalspan fleet automation confirmation|create --preparation <uuid> --input <private-original-request.json|->
opalspan automation bulk list|manifest|selection-query|prepare --input <private-query-or-request.json|-> --out <new-private.json>
opalspan cases bulk list|members|manifest|selection-query|prepare --input <private-query-or-request.json|-> --out <new-private.json>
opalspan automation bulk preparation --request-id <original-id> --out <new-private.json>
opalspan cases bulk preparation --request-id <original-id> --out <new-private.json>
opalspan automation bulk execute --review <id> --input <private-original-request.json|-> --out <new-private.json>
opalspan cases bulk execute --review <id> --input <private-original-request.json|-> --out <new-private.json>
opalspan automation bulk result --review <id> [--offset <returned-offset>] --out <new-private.json>
opalspan cases bulk result --review <id> [--offset <returned-offset>] --out <new-private.json>

Fleet query input wraps canonical CoreSearchRequest as search, with grouping, sort and bounded page fields. Exact site/department/tag UUIDs and explicit missing_company, missing_site, missing_department selectors are distinct; requiring both an exact ID and its missing value is refused. Complete query totals are not inventory totals. Structured after-change view counts retain overlap; text-search predictions remain explicitly incomplete, not zero.

Organization can review a complete manifest of up to50,000 devices. Bulk pause or collaborator actions and exact automation target sets have a5,000-record ceiling; narrow oversized work, never split implicitly. Automation preparation does not create a schedule: the existing attributable consent/budget/schedule review and explicit create remain required. Pause affects future starts, not current runs; Case additions preserve existing equal collaborators.

Bulk query/context/reasons/results use guarded private files. Original manifest IDs, source/index revisions, analyzer and exclusions bind selection; changed or partial scope refuses rather than substituting matches. Other fleet commands return authorized JSON, which agents should capture privately when it contains customer context. Enrollment-default show searches one returned owner-only page; absence from that page does not establish absence from the workspace.

Connected work history and explicit diagnostic plans

opalspan history list [--search <text>] [--actor <uuid>] [--device <uuid>] [--case <uuid>] [--company <uuid>] [--contact <uuid>] [--since <UTC>] [--until <UTC>] [--filter all|active|attention|mistakes] [--scope work|access] [--kind <recorded-kind>] [--cursor <opaque>] [--limit <1-100>] --out <new-private.json>
opalspan history run --conversation <uuid> --run <uuid> [--cursor <opaque>] [--limit <1-50>] --out <new-private.json>
opalspan history case --case <uuid> [--kind <recorded-kind>] [--since <UTC>] [--until <UTC>] [--cursor <opaque>] [--limit <1-50>] --out <new-private.json>
opalspan diagnostics capabilities --device <uuid> --out <new-private.json>
opalspan diagnostics plan --input <private-selection.json|-> --out <new-private-plan.json>
opalspan diagnostics start --input <private-start.json|-> --out <new-private-run.json>
opalspan automation run continue-recorded --automation <uuid> --run <uuid> --input <private-action.json|->

History includes authorized exact runs, even when they did not operate a device. Frozen context and observed lifecycle differ from today's conversation or Case state. Access-period notes can describe other work sharing that period; they are not a run result. Unknown old start/end/result remains unknown. Needs attention includes uncertain effects requiring reconciliation. Keep paging filters fixed.

Usage groups deduplicate immutable provider calls. Unknown token counts stay null, and reasoning tokens are included in output. The compatible stdout report suppresses private group labels; private --out retains the exact authorized report. --work-session remains an independent Admin-only financial selector, not per-device AI allocation or a second balance.

Diagnostic selection is DeviceDiagnosticSelection: device_id, purpose, exact sections or profile, and optional case_id. Start is StartDeviceDiagnosticPlan: a stable UUID request_id and the exact private review_token returned by preparation. Preparation performs no collection. Start rechecks actor/workspace, expiry, target/helper and original support consent/accounting; retain its original input before dispatch. After an uncertain result, inspect the returned conversation/run and operations before another collection. There is no automatic mutation replay, model interpretation or Monitoring change. See diagnostics.

Additive read-only startup source contract: opalspan fleet startup-evidence --device <uuid> reads original native duration, source/period/coverage/private-artifact provenance and a comparable prior baseline. It starts no scan and never derives duration from uptime or monitoring. Refresh uses the existing reviewed plan/start with sections: ["startup"]; old signed helpers stay unsupported and existing profiles do not collect this section. Source support is separate from helper/CLI/Bridge publication. See startup evidence for platform semantics and limits; installing a client alone does not activate the server reader.

continue-recorded uses AutomationActionRequest with a new UUID request_id and the selected run's configuration_version as expected_version. It keeps that run's original owner, frozen objective and exact targets under current membership, device, agreement and monetary gates. It neither adopts the current configuration nor takes over its owner's conversation. The existing continue command retains its compatible current-definition meaning.

Automation and telemetry controls

opalspan automation list [--search "<text>"] [--offset <returned-offset>]
opalspan automation show --automation <uuid>
opalspan automation templates|models|limits
opalspan automation quote --input <private-json-file|->
opalspan automation prepare --input <private-json-file|->
opalspan automation confirmation show --confirmation <uuid>
opalspan automation create --input <private-json-file|->
opalspan automation update --automation <uuid> --input <private-json-file|->
opalspan automation resume-prepare|adopt-prepare --automation <uuid> --input <private-json-file|->
opalspan automation pause|resume|adopt|delete --automation <uuid> --input <private-json-file|->
opalspan automation runs --automation <uuid> [--offset <0-10000>]
opalspan automation run show|cancel|answer|continue|notifications --automation <uuid> --run <uuid> [--input <private-json-file|->]
opalspan automation notifications settings|set [--input <private-json-file|->]
opalspan automation critical-email prepare|send --conversation <uuid> --run <uuid> --input <private-json-file|->
opalspan devices telemetry catalogue
opalspan devices telemetry activation
opalspan devices telemetry show --device <uuid>
opalspan devices telemetry history --device <uuid> [--offset <0-2000>]
opalspan devices telemetry prepare|set|consent-prepare|consent --input <private-json-file|->
opalspan devices telemetry monitoring-prepare|monitoring-apply --input <private-json-file|->
opalspan devices telemetry changes --device <uuid> [--offset <0-2000>]
opalspan tenant telemetry-default show
opalspan tenant telemetry-default prepare|set --input <private-json-file|->
opalspan tenant telemetry-instruction show [--profile health-first-slice-v1|health-catalogue-v1|health-resources-v1]
opalspan tenant telemetry-instruction prepare|set --input <private-json-file|->

Private input uses the shared versioned contracts, stable request_id and exact expected_version. prepare for a write takes AutomationPrepareWrite with automation_id (null for creation) and write. The actual person reviews the returned protected human_review_url or existing Mech decision; only then can the originating client apply the identical payload with its confirmation_id. The agent cannot approve with a model boolean. Editing payload/version/targets/ recipients or losing authority invalidates the receipt. Financial overage, adoption and workspace-default/instruction actions retain Admin authority.

devices telemetry catalogue reads the closed software definitions; activation reads exact selected publication binding/versions, never collection permission. The compatible Monitoring proposal uses DeviceTelemetryChange and names every selected target/revision plus added, removed and retained signal scope. Apply the identical request with the server-issued confirmation; changing targets or scope invalidates the review. changes reads exact authorized setting events, not an invented active collection period. Old records retain unknown observation scope.

A run answer targets its decision_id; Continue creates a new identifiable run in the same conversation and does not replay uncertain effects. A queued or waiting_for_human result is not completion. Monetary budget defaults zero, uses DKK minor units and is distinct from AI credits. Telemetry bulk changes supply every selected device's revision in expected_device_versions. Missing lawful consent/necessity stays pending/off; future-enrollment defaults do not change current devices. No real critical email is inferred from preparing or submitting an outbox request.

Team, invitations and settings

opalspan team list
opalspan team role --member <uuid> --role admin|technician --version <current-version>
opalspan team spend-limit --member <uuid> --monthly-credits <decimal|none> --version <current-version>
opalspan team capacity --member <uuid> --active true|false --version <current-version>
opalspan team remove --member <uuid> --version <current-version>
opalspan team access show --member <uuid>
opalspan team access assignments --member <uuid> [--limit <1-100>] [--cursor <opaque>] [--version <assignment-version>]
opalspan team access review --member <uuid> --version <assignment-version> --stored-mode <mode> --effective-mode <mode> --mode <mode> --change-kind delta|complete_set [--add <uuid,uuid>] [--remove <uuid,uuid>] [--devices <uuid,uuid>] [--completeness-token <opaque>]
opalspan team access apply --member <uuid> --request-id <uuid> --review-token <opaque>
opalspan team access set --member <registered-service-uuid> --version <current-version>
opalspan team invite --email <recipient> --request-id <uuid> --out <new-private-url.txt>
opalspan team invitations list
opalspan team invitations replace --invitation <uuid> --email <same-recipient> --version <current-version> --request-id <uuid> --out <new-private-url.txt>
opalspan team invitations revoke --invitation <uuid> --version <current-version>
opalspan settings show
opalspan settings update --name "<name>" --timezone <IANA-zone> --days <1-36500> --version <current-version>
opalspan settings retention set --days <1-36500> --expected-days <observed-days> --version <current-version>

Read the target first and preserve its opaque version, exact actor/workspace and intended payload. spend-limit changes only the existing member-specific AI limit; it does not purchase credits or change prices. Capacity admission uses the current plan, not a new paid seat purchase. The last active Admin is protected. Human device access under workspace-humans-v2 is policy-managed; stored selected-device assignments remain dormant. Machine assignments still apply.

Invitation creation/replacement uses one stable request UUID. The secret URL goes only to the required new private --out file, never stdout, model output or logs. A replay returns status_only metadata, not a retrievable link or another token. Replacement retains the recipient and cannot expand its selected device scope; it invalidates old links and pending acceptance handoffs. Verified recipient acceptance remains the existing invitation preview/accept flow. No email is sent automatically. Replaced/revoked/accepted or foreign records cannot be used as a new target.

Mech's maintained typed tool constructs the exact proposal. Only the current authenticated Admin controller's Approve/Decline answer is a decision; free text or a model assertion cannot approve. The decision binds actor, workspace, target/version, exact payload, conversation/run/scope and expiry, and is consumed in the actual locked service transaction. Changes or revocation invalidate it. Mech invitation results expose only a human-only private Files download; model file tools and recovery context cannot read the invitation URL.

team_outcome_unknown means a mutation may have completed. Read team/invitation or settings status before any intentional retry; preserve the original request UUID and payload, and never automatically resend a mutation or broaden a role. Reducing audit retention can permanently remove older audit history when cleanup runs; it does not alter indefinite Mistake History.

Agent-operated workspace secrets

Introduced in Agent CLI 0.39.8, Bridge 1.21.261 and Host 0.24.17. Current releases retain these capabilities. Windows/Linux use the capable CLI channel; macOS Intel/ARM remain technical previews with build/static-only qualification. Existing signed-in profiles stay in place. Exact delivery and limits.

Agents generate, capture, organize, resolve, use, rotate, migrate and retire arbitrary values through the existing signed-in workspace. Values stay in private runtime transport, encrypted storage and selected target files; output contains names, versions, references and operation receipts. No secret-entry browser form or separate permission-reset cycle is required. These independent commands make no Mech/model call. Released versions and macOS technical-preview limits are in release records.

opalspan secrets list
opalspan secrets receipt --operation <uuid>
opalspan secrets cleanup --operation <uuid>
opalspan secrets generate --operation <uuid> --name <name> [--bytes 32]
opalspan secrets import --operation <uuid> --name <name> (--file <private-file> | --stdin)
opalspan secrets import --operation <uuid> --device <uuid> --path <source-file> --name <name>
opalspan secrets update --reference <uuid> --version <current-version> --name <name> (--file <private-file> | --stdin | --generate --operation <uuid>)
opalspan secrets rename --reference <uuid> --version <current-version> --name <name>
opalspan secrets delete --reference <uuid> --version <current-version>
opalspan secrets exec --operation <uuid> (--local | --device <uuid>) --command <command> --bindings <opaque-binding-json>
opalspan secrets copy --operation <uuid> (--local | --device <uuid>) --reference <uuid> --version <current-version> --destination <new-file>
opalspan secrets migrate --operation <uuid> (--local | --device <uuid>) --reference <uuid> --version <current-version> --destination <new-file> [--retire-reference]

A binding contains reference, version, environment_name and optional private_file. Runtime resolution supplies a child-only environment value; private_file: true instead supplies the path to a protected temporary file, preserving multiline or opaque bytes. Never paste a value into arguments, command text or chat. Private import uses stdin or files directly. Generate passwords with the runtime generator; create other formats, such as SSH keys, through ordinary secret-aware commands and capture their private output.

For command/API capture, add --capture-path <new-file> --capture-name <name> and have the command write its selected returned value there. The capture file is freshly reserved in a private parent directory before execution; use import for existing sources. Source links and platform temporary-directory aliases are resolved safely; exclusive destinations still refuse existing final files/links. All stdout/stderr is sealed, including failed commands. A captured reference can be reused or explicitly replace --reference <uuid> --version <n> after confirmed successful execution. Captures remain private at the selected source during uncertain delivery; reconcile the receipt/reference, then remove that source after confirmed storage. Use materialisation for long-lived services; ephemeral binding-file paths last only for their owned execution.

To migrate a multiline credential between devices, import its authorised source file, then copy/migrate that reference to the destination device. Destination bytes are privately read back before optional vault-source retirement. Existing destination files are never silently overwritten; an explicit secret-aware command can update existing configuration or perform an API rotation. For a cross-workspace move, use the existing workspace selection and a private local materialisation/import handoff, verifying the destination before retiring the original reference.

Updates use current versions; conflict leaves the previous value intact. Operation UUIDs fence dispatch independently of reusable references: read the original receipt and actual target state after uncertainty, rather than replaying a command. Deleting a vault record clears its live ciphertext, not already materialised copies or private backups. Existing migrated records preserve their prior owner/Admin confidentiality; ordinary new records follow workspace operational access. Secret-aware output suppression prevents normal pipeline leakage, while trusted root or arbitrary authored code can deliberately copy/transform/transmit values. There is no plaintext-output command or claim of malicious-code isolation.

Practical agent sequence

Discover the installed surface with opalspan capabilities, then find metadata with opalspan secrets list --prefix harbor/reporting/. These commands make no Mech/model call. Keep reference/version and original operation UUIDs in the task; keep values out of its context.

For a new service password, generate under a useful non-secret name. Use the returned captured.id and captured.version from the command's safe envelope in bindings. For replacement, secrets update --generate selects the existing reference/current version; the stable ID remains, while the version changes.

opalspan secrets generate --operation <generation-uuid> --name harbor/reporting/service-password
opalspan secrets update --reference <password-ref> --version <current-version> --name harbor/reporting/service-password --generate --operation <replacement-uuid>

A private-file binding is suitable for a multiline signing key. This is the JSON shape; substitute authorized metadata, never credential bytes:

[{"reference":"11111111-1111-4111-8111-111111111111","version":1,"environment_name":"SIGNING_KEY_FILE","private_file":true}]

Use that JSON with secrets exec --local on the agent's workstation or --device <uuid> on the authorized remote target. The command consumes the child file path from SIGNING_KEY_FILE. For an API-generated token, use a fresh private capture path and write only the selected returned bytes there; provider creation/revocation and permission semantics remain the application's contract. A sealed exit-zero receipt needs a separate working-service check.

For a device-to-device move:

opalspan secrets import --operation <import-uuid> --device <source-device> --path <private-source> --name harbor/reporting/signing-key
opalspan secrets copy --operation <copy-uuid> --device <destination-device> --reference <captured-ref> --version <captured-version> --destination <new-private-file>

Inspect destination verification, then test the service that uses the copied credential. Optional migrate --retire-reference retires the vault source only after private byte verification; the imported original file and protected backups remain separately owned. For another workspace, materialise privately with copy --local, select/sign in to the destination workspace through the existing profile workflow, import the local file privately and verify the destination before retiring the original. Preserve those profiles and authentication.

After a missed response, secrets receipt --operation <original-uuid> reads the original outcome. Observe uncertain target effects before choosing new work. secrets cleanup --operation <original-uuid> reconciles owned local runtime resources; it is not remote source-file deletion or provider revocation. Confirm private storage before removing a retained capture source through authorized secret-aware execution. Keep completed cleanup and remaining copies explicit. The Mech guide explains the same lifecycle through Mech's actual device tools.

Device administration and enrollment housekeeping (S4)

opalspan devices update --device <uuid> --version <current-version> [--display-name <label>] [--primary-user <label>] [--organization <label>]
opalspan devices capacity --device <uuid> --active true|false --version <current-version>
opalspan devices work-hours --device <uuid> --version <guidance-version|none> --input <private-schedule.json>
opalspan devices revoke --device <uuid> --reason <reason> --version <current-version> --confirm
opalspan device transfer status --transfer <uuid>
opalspan enrollment options|list
opalspan enrollment show --enrollment <uuid>
opalspan enrollment revoke --enrollment <uuid> --version <current-version> --confirm
opalspan enrollment share revoke --share <uuid> --version <current-version>
opalspan enrollment share extend --share <uuid> --version <current-version> --expected-expires-at <exact-offset-timestamp> --additional-minutes <1-10080>
opalspan rescue list --workspace [<current-workspace-uuid>] [--history] [--cursor <cursor>] [--limit <1-100>]

Read devices show, enrollment show or enrollment share status first and preserve the returned version. Metadata update preserves omitted labels; explicit empty labels clear them. Work hours use the separate work_guidance.version (none when unconfigured), with the existing DeviceWorkHours JSON (time_zone, working_hours, protected_periods, instruction); JSON null clears it. The schedule file uses the existing private-file/link/size guard. Hours remain advisory, never a scheduler or permission to disrupt. Device administration versions exclude heartbeats and lease renewal.

Device capacity and extension of an unused shared enrollment remain Admin-only. Metadata/hours use DeviceEditor; enrollment/revoke/transfer use DeviceManager under the current workspace policy. Machine profiles cannot use these human administration adapters or workspace Rescue enumeration; existing explicit run-owned enrollment/Rescue routes remain unchanged. rescue list --workspace reads the selected profile's workspace, not local rescue session list; an optional UUID must match that profile and never changes membership or selection. Read visibility does not grant someone else's owner-only Rescue control.

Mech has read_device, read_enrollment_options, list_enrollments, read_enrollment, read_device_transfer, list_workspace_rescues and read_workspace_rescue. update_device_metadata, set_device_capacity, set_device_work_hours, revoke_device, revoke_enrollment, revoke_enrollment_link and extend_enrollment_link render the exact server-owned change for the current authenticated controller through shared S3. The single-use proof is consumed in the existing locked business transaction; changed actor, scope/run, version, expiry or payload is refused. A model cannot approve. CLI --confirm records already supplied human intent, not Mech approval.

device_admin_outcome_unknown requires same-target read reconciliation, never an automatic mutation retry. Revocation keeps durable history and closes live access; it does not certify remote software/file cleanup. Enrollment revoke affects future consumption, not a completed device. Share extension preserves the same URL/code/pinned release and compares the exact previous expiry; used, revoked and run-owned links never regain authority. Transfer prepared is not completed; status contains no acceptance code or candidate credential. Enrollment receipt, health polling or reconnect does not create an additional charged work session.

Read views and Mech lifecycle

Current work-session summary is v3; v1/v2 remain compatibility. Mech settings include Plan, exact confirmed for subsequent runs and unavailable during active runs; changing mode sends no message and gives no authority.

opalspan overview [--customer <uuid>] [--case <uuid>] [--technician <uuid>] [--activity all|active|idle] [--cursor <opaque>]
opalspan access sessions list [--actor <uuid>] [--device <uuid>] [--state active|ended] [--since <UTC>] [--until <UTC>] [--cursor <opaque>] [--limit <1-100>]
opalspan access sessions show --session <uuid> [--cursor <opaque>] [--limit <1-100>]
opalspan access activity [--device <uuid>] [--cursor <opaque>] [--limit <1-100>]
opalspan usage ai --since <UTC> --until <UTC> [--case <uuid>] [--company <uuid>] [--contact <uuid>] [--conversation <uuid>] [--run <uuid>] [--controller <uuid>] [--group-by run|case|conversation|actor] [--group-cursor <opaque>] [--group-limit <1-50>] [--work-session <uuid>] [--before <uuid>] [--out <new-private.json>]
opalspan usage work-sessions [--since <UTC>] [--until <UTC>] [--technician <uuid>] [--cursor <opaque>] [--limit <1-100>]
opalspan usage work-sessions current
opalspan usage work-sessions events --session <uuid> [--cursor <opaque>] [--limit <1-100>]
opalspan releases list
opalspan devices list --company <exact-workspace-company-uuid>

Work-session financial reporting requires an Admin; a Technician must decline it. AI usage is customer retail usage, never supplier economics. Null or unavailable coverage is not zero. Follow returned cursors with the same filters. Access periods, authenticated device work and AI credits remain different units.

opalspan mech capabilities
opalspan mech conversations list [--archived] [--cursor <opaque>] [--limit <1-100>]
opalspan mech conversations show --conversation <uuid> --out <new-private.json>
opalspan mech conversations create --request-id <uuid> [--title <label>] [--model <permitted>] [--reasoning <permitted>] [--devices <uuid,uuid>] [--case <uuid>] --out <new-private.json>
opalspan mech conversations rename --conversation <uuid> --version <current> --title <label> --out <new-private.json>
opalspan mech conversations archive|claim|release --conversation <uuid> --version <current> --out <new-private.json>
opalspan mech conversations settings --conversation <uuid> --version <current> --model <permitted> --reasoning <permitted> --out <new-private.json>
opalspan mech conversations context --conversation <uuid> --version <current> [--devices <uuid,uuid>] [--case <uuid>] --out <new-private.json>
opalspan mech messages send --conversation <uuid> --version <current> --request-id <uuid> --text-file <private-utf8.txt> [--attachments <uuid,uuid>] --out <new-private.json>
opalspan mech runs list --conversation <uuid> [--cursor <opaque>] [--limit <1-100>]
opalspan mech runs show|results --conversation <uuid> --run <uuid> --out <new-private.json>
opalspan mech runs stop|cancel --conversation <uuid> --run <uuid> --version <current> --out <new-private.json>
opalspan mech runs continue --conversation <uuid> --run <prior-uuid> --version <current> --request-id <uuid> --out <new-private.json>
opalspan mech runs guidance --conversation <uuid> --run <uuid> --request-id <uuid> --text-file <private-utf8.txt> --out <new-private.json>
opalspan mech events list --conversation <uuid> [--after-sequence <n>] [--limit <1-100>] --out <new-private.json>
opalspan mech files list --conversation <uuid> [--offset <n>] [--limit <1-100>]
opalspan mech files download --conversation <uuid> --file <uuid> --out <new-private-file>
opalspan mech attachments add --conversation <uuid> --request-id <uuid> --file <private-evidence> --out <new-private.json>

A conversation has one current human controller. Others may read within their workspace authority, but cannot take another controller or mutate their run. Idle settings and scope changes require the exact optimistic version; scheduling state alone does not advance that content revision. Stop/cancel names the exact run and remains irreversible for it; observer loss never implies cancellation. Continue is explicit recovery after inspecting recorded operation status, not permission to repeat an uncertain effect. Historical unrecorded run status is reported unavailable rather than inferred from a newer run.

Create and input UUIDs bind the original payload; an identical retry reuses the original intent while a changed payload conflicts. Private --out is reserved before mutation and retains the exact prepared intent if the outcome is unknown. Transcripts, run results, evidence and input text never go to ordinary stdout or telemetry. Downloads are bounded, current-user protected and opaque-file scoped; no server paths or provider credentials are returned. Existing human-only team invitation files remain unavailable to model/external file tools.

Mech provides direct shared-service read and lifecycle tools, not an HTTP loopback or Bridge shell. Its selected scope cannot inspect or launch a broader conversation. Archive uses the existing server exact-change confirmation; ordinary safe authorized actions need no routine per-command approval. Pending proposals and answers use the shared decision adapter, which rechecks the relevant role before exposing a private proposal and again before mutation. Confirmation never grants an Admin role or a device lease. Native execution keeps its independent controller/run/device lease; Mech cannot adopt an external CLI lease.

Mech decisions

opalspan mech decisions show --conversation <uuid> [--decision <32-hex-id>] --out <new-private-decision.json>
opalspan mech decisions answer --decision-file <private-decision.json> --approve true|false
opalspan mech decisions answer --decision-file <private-decision.json> --answer <text>

The first command reads the server-rendered summary and saves the exact profile, workspace, actor, run, revision and payload digest. Your agent presents that summary and relays only your actual decision. Approval/decline uses a boolean; an ordinary question answer does not approve a mutation. Changes, expiry, permission loss or a different controller invalidate a confirmation. The API rechecks these boundaries when recording the answer and the shared service rechecks before applying it.

Use --decision to read approved, declined or consumed receipt state. An approval is not proof that the target change completed. After decision_outcome_unknown, inspect the same decision and target outcome before any intentional retry; no answer or operation is retried automatically. Keep the snapshot private, do not copy it between identities/workspaces, and do not log its contents. Windows, Linux and macOS share this contract; macOS remains a technical preview, in active development. The release page identifies when the new commands are published.

Original-holder terms, orders and rights

opalspan rights terms --language en --out <new-private-terms.json>
opalspan rights order-review --input <private-order.json> --out <new-private-review.json>
opalspan rights order-decide --review <private-review.json> --decision order-with-obligation-to-pay --out <new-private-journal.json> --url-file <new-private-url>
opalspan rights status --order <uuid> [--out <new-private-status.json>]
opalspan rights review --order <uuid> --input <private-exact-request.json> --out <new-private-review.json>
opalspan rights decide --review <private-review.json> --decision confirm-exact-holder-request --out <new-private-journal.json>
opalspan rights receipt --order <uuid> --request-id <uuid> --out <new-private-receipt.json>
opalspan rights copy --order <uuid> [--request-id <uuid>] --out <new-private-copy>
opalspan rights document --order <uuid> --kind <exact-kind> --out <new-private-document.json>
opalspan rights refund-results --order <uuid> --out <new-private-results.json>
opalspan rights portal --order <uuid> --out <new-private-url>
opalspan rights refund-copy --order <uuid> --refund <uuid> [--correction true] --out <new-private-receipt>
opalspan rights payment-copy --order <uuid> --out <new-private-receipt>

The notice input contains request_id, operation (withdrawal, cancellation, billing-correction or applicable credit redemption), current revision, name, receipt_email and the exact statement. The new-order input contains request_id, plan_id, language, name, receipt_email, capacity, early_start, applicable dpa and processing_use. Neither input is acceptance. Your agent privately presents the entire server-rendered review: dated document versions, binding, recipient, exact statement/price and effect. Only your actual meaningful decision for that current text may be relayed before expiry. An agent assertion, free-text model reply or old unattended authorization is not acceptance.

Auth0 signup/sign-in and Stripe card, payment, SCA and provider consent remain browser flows. Accepted terms are frozen independently of payment; no browser return grants credits or capacity. Cancellation stops renewal at the existing paid boundary without removing the paid coverage or automatically refunding it. Withdrawal and remedies receive durable acknowledgments without deciding a financial refund. Seller financial handling remains in Stripe.

Private copies and journals use new, guarded nofollow/owner-only paths. Do not print the private review capability, payment URL, customer statement or agreement copy in logs. holder_outcome_unknown/billing_outcome_unknown retains the exact request; read current rights and the same receipt/result before any intentional retry. Never automatically retry or switch request IDs after uncertain acceptance, cancellation, withdrawal or refund intake.

Mech's holder_order, holder_rights_status, holder_request, holder_request_result, holder_billing_provider and holder_contract_copy use the same services. Exact confirmation binds the current controller/run/version/digest and expiry, then rechecks original holder identity in the locked business transaction. Copies are human-only private Files downloads, not shared model artifacts. The standalone contract-rights page also offers Mech's same exact decision for original holders with no active workspace membership. This identity-only entry has only holder tools; it creates no membership, starts no paid inference and cannot access a workspace, device, ordinary conversation or Automation. Existing standalone web controls remain available alongside it. Source and actual release applicability remain distinct until the release record proves publication.

Workspace billing

opalspan billing status|allowance|budget
opalspan billing compare --input <private-workload.json>
opalspan billing session-quote --input <private-actual-target-set.json>
opalspan billing budget-quote --input <private-request.json>
opalspan billing confirmation --id <quote-uuid>
opalspan billing subscribe --plan shop|business|fleet --request-id <uuid> --url-file <new-private-file>
opalspan billing subscription-status --id <checkout-uuid>
opalspan billing invoices|manage --url-file <new-private-file>
opalspan billing change-plan [--plan shop|business|fleet] --url-file <new-private-file>
opalspan billing top-up --request-id <uuid> --url-file <new-private-file>
opalspan billing top-up-status --id <request-uuid>
opalspan billing device-slots --blocks <25-slot-blocks> --request-id <uuid> --url-file <new-private-file>
opalspan billing device-slots-status --id <purchase-uuid>

compare accepts enrolled_devices, monthly_work_sessions, human_members, active_automations, executing_hosted_mech_runs and optional recurring_interval_minutes. It orders applicable full-month costs including explicit device-slot blocks and session rates, excluding extra AI and VAT; it is not a mid-month invoice quote or a spending authorization. Automation capacity fields do not establish deployed scheduling or telemetry.

session-quote accepts a stable request_id, exact device_ids and optional run_id. budget-quote accepts request_id, a change containing nullable member_id/run_id and dkk_limit_minor, plus device_ids for a run quote. Only one scope can be selected. Session overage starts with a zero monetary budget; accepted and in-flight aggregate exposure counts against workspace, member and run limits. A quote is not approval. The agent opens its exact human_confirmation_path; the signed-in Admin confirms in the browser, or Mech presents the same retained exact quote to its authenticated controller. A model, old message or bearer flag cannot approve it. Read confirmation state afterwards. Limits cannot be reduced below accepted/in-flight exposure.

Payment, card, SCA and subscription consent remain Stripe browser steps; Auth0 owns signup and sign-in. Provider URLs go only to guarded private files, never ordinary output or logs. billing_outcome_unknown means a mutation might have completed: preserve request/profile/payload and inspect status before retrying. Discovering/enrolling a device never buys slots. Plan changes use only an exact configured target in the retained offer generation, with paid-invoice entitlement; unapproved international tariffs or new agreement acceptance are never inferred.

Conventions and output

opalspan --version
opalspan help
opalspan capabilities
opalspan guide
opalspan doctor

--version prints the installed version. capabilities describes commands and platform selections; doctor checks local readiness and login, not the health of every remote device.

For commands below, angle-bracket text is a placeholder to replace. Square brackets mean optional syntax; | means choose one value. Do not type those notation characters literally. UUIDs identify records; file paths identify local inputs/outputs unless explicitly called remote paths. Neither is a substitute for authorization.

Common options:

Option Meaning
--tenant <profile> Select one isolated local named profile without changing the default.
--format json Stable machine-readable envelope. Use explicitly in automation.
--format text Human-readable output.

Interactive login, whoami and devices list can use readable terminal output. Redirected/JSON commands preserve non-prompting workspace selection. Browser authentication remains explicit.

Normal command envelopes contain:

Field Contract
schema_version "1.0" for the CLI envelope, independent of a nested diagnostic schema.
command Operation name.
ok, status Success flag and operation-specific state.
data Typed command result, or null.
errors Entries with code, message and optional remediation.
next_actions Entries with description and suggested command.
timestamp_utc Result timestamp.

Envelope commands exit 0 when ok is true and 1 when false. Inspect the data as well: a partially created batch may contain successful and failed items. For exec, the actual remote exit code is data.exit_code; it is not the CLI process's exit code.

Identity and profiles

opalspan login [--workspace <workspace-id>] [--non-interactive]
opalspan whoami
opalspan logout [--all]
opalspan tenant list
opalspan tenant show
opalspan tenant use <profile>
opalspan devices list [--all-tenants]
opalspan devices show --device <device-id>

Use opalspan login --tenant <profile> --workspace <workspace-id> for an isolated membership profile. --non-interactive prevents the workspace prompt; it does not perform browser consent or MFA for you. Routine login discovers public configuration from OpalSpan's compatible service; no custom Bridge or identity-provider flags are needed.

Windows profile migration

Fresh Windows profiles use %LOCALAPPDATA%\OpalSpan\Client. An existing populated %LOCALAPPDATA%\Forge\Forge stays authoritative until an offline cutover, so installing an update keeps the current login. Root precedence is an explicit adapter/setup root, OPALSPAN_HOME, then the compatible FORGE_HOME alias. Configured filesystem roots are never moved. Windows native credentials are shared across those roots; every current root adapter uses the same identity owner. OPALSPAN_CREDENTIAL_NAMESPACE takes precedence over FORGE_CREDENTIAL_NAMESPACE and preserves the selected namespace suffix. The installed CLI, services and protected signing stores retain their own locations. The separate canonical secret-runtime directory is unchanged.

opalspan state status
opalspan state migrate --quiesced
opalspan state rollback --quiesced

Stop other Windows CLI and transport processes across all filesystem roots, including older clients, before cutover; --quiesced records that condition. Current commands share a read-concurrent native-vault lease; the offline global identity/default-tree transition takes its exclusive lease. Unset both home variables for default-root migration. The command renames one tree on the same volume, preserving profiles, selection, keys and ACLs. It repairs owned session/connection path fields and managed SSH key references while preserving unrelated SSH configuration. Two populated roots or differing old/new credential identities produce an explicit conflict: neither is merged or overwritten. Select the intended root explicitly for recovery rather than repeating login.

Before explicit cutover, existing legacy vault identities stay authoritative: a fresh default-root read cannot retire a credential used by a custom-root client. Genuinely new credentials use canonical identities, and every current root adapter reads that same single value. The quiesced migration boundary enables canonical adoption globally. Later use verifies the canonical write before retiring the legacy entry; custom-root clients share the adopted value without moving their files. A shared metadata-only intent list supports rollback with the current credential, including rotated values and capsule issuers, even when there is no default profile tree to move. Refresh coordination retains the established identity. Migration keeps values inside protected storage and leaves sign-in/account state intact.

After interruption, including storage exhaustion, state status reports the pending direction. Repeat that same command with --quiesced before restarting clients. Completed cutover and lost-acknowledgement retries reconcile the actual tree without copying state or replaying authentication. Before running an older client after canonical use, finish state rollback --quiesced; simply installing an older binary does not reverse state adoption.

Linux profile migration

Linux uses canonical OpalSpan XDG config/state/cache defaults while retaining a populated legacy generation until state migrate --quiesced. The same status, migrate and rollback commands compose the shared offline tree contract with Linux filesystem, case, permission and native-flock checks. Pinned key/token paths, Secret Service collection and original refresh coordination remain stable; provider identity adoption and current-value rollback are scoped to that pinned storage. Explicit home overrides are never moved. See Linux installation for original XDG scope recovery, conflicts and provider-specific adoption details. Linux requires opalspan credentials configure and opalspan credentials status before login; a provisioned-key provider needs no desktop keyring.

macOS profile and Keychain migration

Fresh macOS defaults use ~/Library/Application Support/OpalSpan and ~/Library/Caches/OpalSpan. Existing populated Forge profiles/cache remain selected until opalspan state migrate --quiesced. Explicit roots and both home overrides retain their files and precedence. The independently owned installed CLI stays under ~/Library/Application Support/Forge/cli; its installation identity is unchanged. The original default Forge/state/keychain-coordination directory also remains in place. Explicit-root clients retain their original state/keychain-coordination refresh lock and pending markers alongside the current-client shared lease; an older same-root reader's barrier remains effective. Workspace rotation invalidates original and shared revision metadata, and cached borrows check both: either an older or current same-root writer invalidates the other reader without opening Keychain during cache checks. The separately owned OpalSpan/secret-runtime subtree retains its original bytes and paths through migration and rollback; it participates in neither profile-generation detection nor profile reference scans.

Stop all CLI and transport readers across every root, including older clients, and unset both home overrides before default cutover. Migration moves profile entries and cache without copying a second active tree, checks actual filesystem device identities, and preserves private ownership/modes. Case matching follows the observed filesystem identity. Linked, non-private, conflicting or cross-volume state stays protected for explicit recovery. Owned session/connection paths and managed SSH references follow the adopted root; unrelated SSH entries remain.

The native adapter retains the existing Keychain search list and new-item default. Its service/account scope is shared by filesystem-root overrides. Metadata-only ownership and rollback records are bound to the ordered search list and default Keychain identity; changing that provider scope does not select another scope's migration record. Existing items retain dk.readyit.forge.cli and their account until explicit cutover. New items use dk.readyit.opalspan.cli with canonical accounts. Cutover enumerates only account metadata in the legacy service and adopts the known authentication, machine, workspace and capsule families. Distinct legacy items sharing the same service/account are fenced before any rename; repeated observations of the same persistent item are deduplicated. Unmapped compatibility accounts retain their original legacy service for ordinary reads, writes and explicit deletion.

Adoption renames the original item's service/account in place, verifies its current value and retains its Keychain object and access controls. Equal-valued but distinct old/new items also require explicit conflict recovery. No duplicate rotating credential is retained. state rollback --quiesced returns current registered values, including rotations and fresh canonical values, to old-reader identities before restoring profile/cache paths. Overlapping search lists can contain the same item: rollback inventories current canonical identities in its selected provider as well as registered accounts, and ordinary commands preserve existing legacy items until another explicit offline cutover. Another context's lazy read therefore cannot undo rollback. Unrelated services/accounts, sign-in state and Keychain security settings remain unchanged. Native item access can require the owner's normal Keychain interaction; the CLI never unlocks it, broadly deletes items or initiates OAuth as migration cleanup.

After interruption, state status reports the original direction without opening Keychain; partially moved state has no selected active root. Resume that direction with the original provider scope and --quiesced before restarting clients. Intel and ARM packages remain signed technical previews; build/static qualification alone establishes neither native Keychain/lifecycle acceptance, physical Apple silicon execution, Apple Developer ID signing nor notarization. Exact published applicability belongs to the supported releases.

Agent-first onboarding

opalspan login --signup [--tenant <profile>] [--authorization-url-file <new-private-path>] [--callback-stdin]
opalspan purchase plans
opalspan purchase start --plan shop|business --currency DKK|EUR|USD --request-id <uuid> --out <new-private-continuation.json> --url-file <new-private-url.txt> [--continuation-file <previous-private-continuation.json>]
opalspan purchase status --continuation-file <private-continuation.json>
opalspan purchase status --purchase <purchase-id>
opalspan purchase claimable
opalspan purchase claim --purchase <purchase-id> [--continuation-file <private-continuation.json>]
opalspan tenant list --memberships
opalspan tenant create --name "<workspace-name>" --request-id <uuid> --out <new-private-request.json>
opalspan invitation preview --link-file <private-invitation-url.txt> --out <new-private-preview.json>
opalspan invitation accept --link-file <private-preview.json>

--signup asks Auth0's normal Universal Login to show signup; it adds no account or workspace authority. With no memberships, login returns authenticated_no_workspace, saves the normal protected sign-in and offers agent onboarding instead of requiring Bridge UI. Existing Credential Manager, Linux Secret Service/protected encrypted store and macOS Keychain lifetime, rotation, revocation and logout rules are unchanged. A saved session is not a promise of unlimited or perpetual login; provider expiry or revocation can require browser sign-in again.

purchase plans reads the existing public retail catalogue without a bearer token. It lists Free as well as paid plans; use tenant create for a Free workspace. Paid start requires explicit purchase authority and a retained fresh request UUID. Its --out journal is saved before dispatch. The returned provider URL and issuer/subject-bound continuation go only into new private files. Stdout contains non-secret selectors, file paths and next_actions, never the URL, handle, bearer or continuation. The agent opens the URL privately for the human to finish Stripe Checkout; do not copy it into a transcript, telemetry or another URL.

purchase status --continuation-file reads provider-observed OpalSpan state: pending, reconciliation_required, expired, paid or claimed. A browser return is not payment evidence. Once paid, claimable lists only receipt-mailbox matches verified by Auth0 UserInfo with the same authenticated subject. Multiple matches require explicit purchase selection. Claim creates/binds the paid workspace through the existing service and selects it as the caller's first Admin. Another identity, even with the same receipt email after claim, cannot take it over. status --purchase is a mailbox-recovery read for paid purchases, or an exact-owner read for claimed purchases; it cannot discover pending checkouts by UUID.

Retain request identity, payload, profile and private continuation after interruption. An intentional start retry must include the received continuation and the identical request UUID/plan/currency, with new output paths. Without a received continuation, use claimable after the original checkout is paid rather than buying again. There are no automatic mutation retries. onboarding_outcome_unknown means a mutation may have completed; inspect the existing receipt and tenant list --memberships first. The latter reads server-authorized memberships without selecting a workspace; plain tenant list continues to list local profiles. A local selection failure reports completed membership with _selection_required; select it rather than repeating creation/acceptance. Free workspace retries retain the original UUID and name; changing either is not recovery.

Invitation preview reads a private same-origin /join#... link, exchanges it through OpalSpan and writes a short-lived private preview containing the confidential handle. Show its workspace, recipient and proposed effective device access before accepting. accept --link-file consumes that preview file, not an arbitrary raw link. It rechecks access and requires the verified recipient; role remains Technician. It cannot merge accounts, restore removed membership or request Admin. Successful acceptance removes the private preview; successful claim may remove its supplied continuation. Remove stale handoffs and provider URL files after their useful lifetime.

Windows, Linux and macOS use the same API and CLI contracts. Browser opening and private-file/credential adapters differ by OS. macOS remains technical preview, in active development, without new hardware or signing acceptance in S1.

Access and transfers

opalspan device connect --device <device-id>
opalspan device disconnect --device <device-id>
opalspan exec --device <device-id> --command "<target-shell-command>" [--timeout-seconds <seconds>]
opalspan exec --device <device-id> --execution-mode discover
opalspan exec --device <device-id> --execution-mode signed_in_user --user-session <native-session> --command "<target-shell-command>"
opalspan upload --device <device-id> --source <local-file> --destination <remote-file>
opalspan download --device <device-id> --source <remote-file> --destination <local-file>
opalspan device transfer accept [--expires-in-minutes <minutes>]
opalspan device transfer initiate --device <device-id> --acceptance-code <private-one-use-code>
opalspan device transfer cancel --transfer <transfer-id>

CLI 0.39.0 does not impose a total-runtime deadline on execution, file transfers or diagnostics. --timeout-seconds is an explicit caller choice, not a default. exec reports stdout_truncated and stderr_truncated when bounded local capture fills; the process continues. Write high-volume output to a file when a complete log is required. Cancellation and uncertain-result reconciliation remain required.

Execution defaults to the existing machine/service account. On compatible native companions, discover reads current OS-observed account, elevation, privilege limits and existing local signed-in sessions; explicitly select the returned session for signed_in_user. Windows uses the console user's token and desktop, Linux uses logind UID/GID/groups and observed session environment, and the macOS technical preview enters the existing launchd GUI bootstrap under user credentials. This is not remote desktop, account creation or sign-in. A tty session or missing graphical environment supports user-level work without proving desktop attachment.

execution_context is informational. Unknown/missing observations never disable machine execution, diagnostics or repair. A failed user attempt does not disable service work. Existing consent, revocation and OS permissions remain effective; root/SYSTEM/admin labels and exit zero do not prove app visibility, UAC or TCC access. Discovery is demand-driven rather than a mandatory per-command round trip. Retain operation identity and inspect uncertain results instead of replaying side effects.

Transfer acceptance defaults to 30 minutes and is created in the destination workspace. Initiation runs in the source workspace. These move device ownership; they are not file-transfer commands.

See access for elevated execution, exclusive leases, profile selection, host-key protection and interrupted-operation behavior. device relay probe is a migration-specific command, not an ordinary health check. Retired transport commands are not a supported fallback.

Enrollment

Current keyed sharing uses issue/replacement/intake/association with retained identity/version and status-only recovery; never fall back to unkeyed create after uncertainty. Target platforms include osx-arm64/osx-x64 technical previews with optional reviewed support_access_mode/classification.

opalspan enrollment create --display-name "<label>" --out <directory> --access-mode enrolled-attended|enrolled-unattended [--platform win-x64|linux-x64|osx-x64|osx-arm64]
opalspan enrollment batch create --manifest <csv-file> --out <directory> --access-mode enrolled-attended|enrolled-unattended [--platform win-x64|linux-x64|osx-x64|osx-arm64] [--concurrency <count>]
opalspan enrollment batch status --batch <batch-id> [--wait] [--timeout-seconds <seconds>]
opalspan enrollment share create --display-name "<label>" --platform win-x64|linux-x64|osx-x64|osx-arm64 --access-mode enrolled-attended|enrolled-unattended --out <new-directory> [--expires-in-minutes <minutes>]
opalspan enrollment share status --share <share-id>
opalspan enrollment share revoke --share <share-id> --version <current-version>

Creation requires the human-selected --access-mode; the target installer independently confirms that exact mode. A package, role or elevation is not that confirmation. The selected signed platform release must support the mode; an old signed release may lack the explicit-mode protocol; choose a compatible verified release, not version-number inference. Already enrolled Linux devices keep their existing access. Mac native decisions/enrolled lifecycle remain under verification. See release applicability and the access guide.

Single and batch creation accept --expires-at <ISO-8601-timestamp> or --expires-in-minutes <minutes>. Single creation also accepts --primary-user "<label>" and --organization "<label>". Batch concurrency defaults to four, and waiting for batch status defaults to 600 seconds.

A batch CSV requires the headers display_name, primary_user and organization; the latter two may have empty values. Optional folder and platform columns choose an output subfolder and target platform per row:

display_name,primary_user,organization,folder,platform
Example Windows device,,,windows-device,win-x64
Example Linux device,,,linux-device,linux-x64

Use private output folders. Generated Windows filenames, Linux code files and enrollment links contain enrollment capabilities. A share ID and batch ID are non-secret selectors, not those capabilities. See enrollment.

Diagnostics

opalspan diagnostics collect --device <device-id> --sections <comma-separated-sections> --output <local-json-file>
opalspan diagnostics collect --rescue-code <session-code> --profile <profile> --output <local-json-file>

Choose exactly one target and one selection form. Use current CLI help/capabilities and the selected signed helper's supported sections/profiles. The diagnostics guide explains scope, privacy and evidence limitations.

Customer directory

Creation supports capability-gated persisted idempotency_key. Unkeyed creates are non-idempotent; same-key recovery preserves actor/workspace/unchanged payload and current-content equivalence. Directory search covers names/email/phone and authorized related records.

In the following syntax, choose companies or contacts:

opalspan companies|contacts list [--search "<name>"] [--archive active|archived|all] [--limit <1-100>] [--cursor <cursor>]
opalspan companies|contacts search --search "<name>" [--archive active|archived|all] [--limit <1-100>]
opalspan companies|contacts show --id <id>
opalspan companies|contacts create --input <json-file|->
opalspan companies|contacts update --id <id> --input <json-file|->
opalspan companies|contacts archive|restore --id <id> --version <current-version>
opalspan device customer-links show --device <device-id>
opalspan device customer-links update --device <device-id> --input <json-file|->

Contact lists/searches additionally accept --company <company-id>. Source intake accepts a supplied durable idempotency_key in create JSON, not in updates. Keyed creates check a fresh authenticated X-Forge-Intake-Version: 1 response before writing. opalspan capabilities describes client syntax, not proof that the selected Bridge supports it. Read customers for complete JSON examples, full replacement semantics and archive handling.

Cases, notes and drafts

Case/draft creation supports persisted keys, with unchanged payload and exact parent/actor/workspace binding. Case discovery supports search/status/company/contact and 1–100 records; note/draft/revision pages retain 1–50.

opalspan cases list [--search <text>] [--status open|in_progress|waiting|closed] [--company <uuid>] [--contact <uuid>] [--archive active|archived|all] [--device <device-id>] [--session <session-id>] [--cursor <cursor>] [--limit <1-100>]
opalspan cases show --case <case-id>
opalspan cases create --input <json-file|->
opalspan cases update --case <case-id> --input <json-file|->
opalspan cases status --case <case-id> --version <version> --status open|in_progress|waiting
opalspan cases close|reopen|archive|restore --case <case-id> --version <version>
opalspan cases collaborators --case <case-id>
opalspan cases assign|unassign --case <case-id> --member <member-id> --version <version>
opalspan cases links --case <case-id>
opalspan cases link --case <case-id> --kind device|session --target <target-id> --version <version>
opalspan cases unlink --case <case-id> --link <link-id> --version <version>
opalspan cases notes list --case <case-id> [--cursor <cursor>] [--limit <1-50>]
opalspan cases notes show --case <case-id> --note <note-id>
opalspan cases notes revisions --case <case-id> --note <note-id> [--cursor <cursor>] [--limit <1-50>]
opalspan cases notes create --case <case-id> --input <json-file|->
opalspan cases notes update --case <case-id> --note <note-id> --input <json-file|->
opalspan cases drafts list --case <case-id> [--cursor <cursor>] [--limit <1-50>]
opalspan cases drafts show --case <case-id> --draft <draft-id>
opalspan cases drafts create --case <case-id> --input <json-file|->
opalspan cases drafts update --case <case-id> --draft <draft-id> --input <json-file|->

Exact draft review and private export

opalspan cases drafts review --case <case-id> --draft <draft-id> --version <exact-version> --recipient <exact-address>
opalspan cases drafts reviewed-text --case <case-id> --draft <draft-id> --version <exact-version> --out <new-private-file>

Case intake supports --search <text>, --status open|in_progress|waiting|closed, --company <id> and --contact <id>. These filters require the version-1 intake marker on the authenticated response; unsupported servers cannot silently return unfiltered results. Case/draft creates also accept optional persisted idempotency_key in their existing V1 JSON. No automatic mutation retry occurs.

intake_outcome_unknown reports an unconfirmed mutation, not safe failure. Preserve the original request and reconcile current records in the same profile. Never replace the key to retry an uncertain create; server rollback needs operator reconciliation. See customer intake for search-before-create semantics, preservation-first triage and the pending access-link integration boundary.

Customer messages

These commands require capable CLI 0.40.0 or later on Windows/Linux and Bridge 1.27.0 or later. The retained Mac CLI 0.39.11 technical preview does not contain this command group. Browser and Mech actions use the same Bridge permission and human-review gates independently of the CLI package.

Work item: opalspan#1019.

opalspan customer-comms settings
opalspan customer-comms configure --input <json-file|->
opalspan customer-comms prepare --case <case-id> --input <json-file|-> [--html-out <new-private-file>]
opalspan customer-comms list --case <case-id>
opalspan customer-comms show --case <case-id> --message <message-id> [--html-out <new-private-file>]
opalspan customer-comms request-approval --case <case-id> --message <message-id> --digest <confirmation-digest>
opalspan customer-comms approval --case <case-id> --message <message-id> --approval <approval-id>
opalspan customer-comms send --case <case-id> --message <message-id> --approval <approval-id>
opalspan customer-comms cancel --case <case-id> --message <message-id> --version <version>
opalspan customer-comms links --case <case-id>
opalspan customer-comms revoke-link --case <case-id> --link <link-id> --version <version>

Output is a model-safe projection: recipient, sender facts, subject, shared text, digests and states, never rendered HTML, capability tokens or customer link URLs. --html-out writes the rendered email, with capabilities redacted, to a new guarded private file. The confirmation digest identifies content; it is not consent. request-approval returns a human_review_url where the same signed-in human approves or declines in OpalSpan; only then can send dispatch once. customer_mail_unavailable means real delivery is gated off and nothing was sent.

Rescue

opalspan rescue guide
opalspan rescue capabilities
opalspan rescue doctor
opalspan rescue session create --label "<target-label>" [--platform win-x64|linux-x64|osx-arm64|osx-x64] [--out <directory>] [--lifetime until_end_or_reboot|bounded]
opalspan rescue session list
opalspan rescue session status --code <session-code>
opalspan rescue session connect --code <session-code>
opalspan rescue session enroll --code <session-code> [--label "<device-label>"]
opalspan rescue session close --code <session-code>

Use Rescue only with matching signed-payload prerequisites and explicit customer authority. History IDs are not session codes. Promotion requests persistent access; closing requests temporary cleanup.

Mistake History

opalspan mistakes record --agent "<agent-name>" --note "<bounded-factual-note>" [--device <device-id>] [--customer "<plain-label>"] [--occurred-at <ISO-8601-timestamp>]
opalspan mistakes list [--since <ISO-8601-timestamp>] [--device <device-id>]

Use this separate append-only record for a material unintended change made by an agent, not routine case progress, rejected operations or harmless command typos. It is retained indefinitely. Keep the note factual and exclude secrets, transcripts and unnecessary customer content.

Installation maintenance

opalspan update installs the latest verified technician release. Platform setup, repair and uninstall differ; follow the Windows or Linux guide.

Machine configuration, acceptance-run administration and platform migration operations are not ordinary customer workflows. Their presence in discovery output does not grant authority to use them.

Device-work identity and accounting

opalspan exec --device <device-id> --command <command> [--operation-id <uuid>]
opalspan upload --device <device-id> --source <local-file> --destination <remote-file> [--operation-id <uuid>]
opalspan download --device <device-id> --source <remote-file> --destination <local-file> [--operation-id <uuid>]
opalspan work show --operation-id <uuid>

Retain the returned operation_id. If no completion is observed, read its status before considering another effect; reuse is not permission to execute it again. The native device fences duplicate identities. work show reports native acceptance, ongoing work, completion or uncertainty, with distinct new_sessions, reused_sessions and platform-covered session references. A failed operation can count as device work; a completed meter record is not proof that a repair succeeded. Mech exposes the same evidence and per-run distinct unit counts. AI credits are separate. Repeated references never charge the same device-work unit again.

For Windows remote file paths use the SFTP absolute form /C:/.... The Daemon runs as LocalSystem, not the logged-in user; private user folders may independently refuse access. Keep native grants and filesystem permissions intact instead of changing them to make a transfer pass.

A work session is commercial grouping, never device authority or local consent. Already-dispatched work crossing a boundary without permission for another charge can continue within its original runtime/scope at OpalSpan's expense; further new unauthorized-charge operations are blocked. Your workspace Billing view identifies platform-covered continuation separately from included/extra sessions.

Browser elsewhere

Ordinary PKCE uses http://127.0.0.1:17874/callback/. Headless sign-in supports guarded new authorization-file handoff or --callback-stdin, without starting the loopback listener. Preserve private code/URL transfer; no credential-cache extraction.