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.
Explainable metadata search
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.