Skip to content

Signing in

Sign this machine in once, check the credential against Cloud, hand the session to a browser, and ask whether a person is there to answer.

Four of these five run without a network or with only Cloud: login, auth, whoami and clarify. They are the same implementation on every machine. open is an ordinary hosted command.

Terminal window
mr-data login [--device-name NAME] [--force] [--credential-store secure-file] [--json]

mr-data login signs this machine in to the Mostly Right cloud. It prints a short code and an approval address on stderr and opens a browser. On approval it stores a durable device credential at ~/.mostlyright/credentials, mode 0600. It prints the mr_cli_ prefix and the last four characters, never the raw credential. Run it once per machine. Every other command resolves the stored credential for itself.

Flag Argument Required Meaning Default
--device-name NAME no What to call this device in the cloud. this machine’s hostname
--force none no Compatibility alias for a safe auth rotate. It never truncates credentials in place. off
--credential-store secure-file no Use the secure-file credential store. the platform’s native store, falling back to secure-file
--json none no One JSON object, and no device code on stderr. off

With --json the command prints neither the device code nor the approval address.

mr-data login --json
{
"schema_version": "mr-data-login.v1",
"status": "device_authenticated",
"cloud_url": "https://mostlyright.md",
"key_id": "zn0aFEzQjXzOH16F01VcWO4a5rg3NQTZ",
"prefix": "mr_cli_",
"last_four": "wunu",
"device_name": "laptop",
"created_at": "2026-09-12T09:00:00Z",
"credentials_path": "/Users/you/.mostlyright/credentials"
}

Values are illustrative. status is device_authenticated on a first sign-in, rotated when --force replaced a key, and recovery_required when the old key could not be proved revoked. Run mr-data auth recover after that last one.

Errors: LOGIN_* and CLOUD_AUTH_* codes from the device flow, carried as error_code on the payload or as an error.

MOSTLYRIGHT_CLOUD_URL signs in against a different cloud. It must be an absolute https:// URL with no user information, no fragment and no trailing slash. login refuses LOGIN_CONFIG_INVALID for anything else, not THIN_CONFIG_INVALID, which the hosted commands raise. It accepts a path or a query.

sign in and check it took
mr-data login --device-name ci-runner-1
mr-data whoami --json
Terminal window
mr-data auth {status,devices,tokens,login,rotate,logout,recover} [...] [--json]

auth inspects the effective Mostly Right device authority through Cloud. auth status validates the effective credential and reports stored metadata separately, so a stored file and a credential Cloud accepts stay two facts. Device inventory carries metadata only. Studio access tokens are ephemeral transport credentials rather than local ones, and auth tokens says so.

Run it after a command returns THIN_AUTHENTICATION_FAILED or THIN_AUTHORIZATION_DENIED to see whether the credential, organization role or workspace is missing.

Subcommand Argument Meaning
auth status none Validate the effective device credential with Cloud.
auth devices list none List Cloud device-key metadata in Cloud order.
auth devices revoke KEY_ID Revoke one Cloud device key, remote first, then clean up locally.
auth tokens list none Explain why ephemeral tokens cannot be listed. Always exits 2.
auth tokens revoke none Explain why ephemeral tokens cannot be revoked. Always exits 2.
auth login none Sign in with a device code.
auth rotate none Replace a device key safely.
auth logout none Revoke remotely, then remove stored authority.
auth recover none Resume or clear interrupted credential state.
Flag Argument Required Meaning Default
--json none no One JSON object instead of human lines. Accepted on auth and on every subcommand. off
--device-name NAME no login and rotate: what to call this device (or the replacement) in Cloud. this machine’s hostname
--credential-store secure-file no status, login, rotate, logout, recover: use the secure-file fallback. native store
--local-only none no logout: remove local state without claiming remote revocation. recover: clear only a stale login lease, leaving it uncertain whether the remote credential was minted. off
mr-data auth status --json
{
"schema_version": "mr-data-auth-status.v1",
"status": "authenticated",
"effective_source": "stored_device",
"remote_validation": "validated",
"device": {
"id": "zn0aFEzQjXzOH16F01VcWO4a5rg3NQTZ",
"name": "laptop",
"prefix": "mr_cli_",
"last_four": "wunu",
"created_at": "2026-08-19T20:25:49.647Z",
"last_used_at": "2026-09-12T08:09:14.384Z"
},
"identity": {
"cloud": { "organization_id": "WQUz…", "user_id": "VQGT…", "role": "owner" },
"studio": { "workspace_id": "39ffafde-86ed-5d7b-b337-1c205ea79390", "principal_id": "8801ad48-…" }
},
"stored_state": {
"status": "available",
"device": {
"cloud_url": "https://mostlyright.md",
"key_id": "zn0aFEzQjXzOH16F01VcWO4a5rg3NQTZ",
"prefix": "mr_cli_",
"last_four": "wunu",
"device_name": "laptop",
"created_at": "2026-08-19T20:25:49Z"
}
}
}

Values are illustrative. effective_source is stored_device or environment. On environment, auth status carries environment_notice, a sentence saying MOSTLYRIGHT_API_KEY is effective for this process and that mr-data cannot unset a parent-process credential. The shorter "environment_authority": "remains_effective" rides on the commands that change authority: logout, recover, devices revoke, rotate and login. stored_state.status is available, not_configured or unavailable. On unavailable it carries error_code.

Other schema versions on this command: mr-data-auth-devices.v1 (devices list), mr-data-auth-device-revoke.v1 (devices revoke), mr-data-auth-token-boundary.v1 (tokens), mr-data-auth-logout.v1 (logout), mr-data-auth-recovery.v1 (recover), mr-data-auth-rotate.v1 (rotate).

status decides the exit code. authenticated, not_authenticated, listed, logged_out, local_recovery_completed, recovered, device_authenticated, rotated and revoked exit 0. unsupported, not_implemented and refused exit 2. Anything else exits 1, including error and recovery_required.

Errors: CLOUD_AUTH_FORBIDDEN and CLOUD_AUTH_NOT_FOUND arrive as status: "refused" with error_code. Storage faults arrive as status: "error" with the LoginError/CredentialStoreError code. retry_after_seconds rides along when Cloud stamped one.

is this machine signed in, and as whom
mr-data auth status --json | jq '{status, effective_source, workspace: .identity.studio.workspace_id}'
Terminal window
mr-data whoami [--credential-store secure-file] [--json]

whoami is the compatibility alias for mr-data auth status. It validates the effective device credential with Cloud, reports stored metadata separately, and never prints a credential. Use it in a script that predates auth.

Flag Argument Required Meaning Default
--credential-store secure-file no Use the secure-file fallback, for a first credential migration. native store
--json none no One JSON object instead of human lines. off

The payload is auth status’s, key for key, plus one member:

mr-data whoami --json (extra member only)
{ "compatibility_alias": "whoami" }

Exit codes and errors are auth’s.

Terminal window
mr-data whoami --json | jq -r '.status'
Terminal window
mr-data open TARGET [--open] [--json]

open prints a one-time address that signs a browser in as you and lands on the page you named. It lasts about a minute and works once. Use it to hand a dataset page to the person watching. It also finishes work only a signed-in browser can do, such as publishing a dataset or a step-up verification. Anyone holding the address within that minute holds the session.

Flag Argument Required Meaning Default
TARGET path yes The dashboard page to land on, as a path beginning with a single /. At most 512 characters. none
--open none no Hand the address to this computer’s browser instead of only printing it. off
--json none no One JSON object instead of human lines. off
mr-data open /datasets/d31017e0 --json
{
"schema_version": "mostlyright-thin-client-v4-handoff.v1",
"status": "handoff_minted",
"lane": "hosted",
"handoff_id": "5a9c0e17-8d46-42b3-b71e-0f2a6c8d4931",
"redeem_url": "https://mostlyright.md/handoff/…",
"expires_at": "2026-09-12T09:01:00Z",
"target_path": "/datasets/d31017e0",
"issuer": "cloud",
"opened": false,
"note": "This address works once and stops working at the moment above. …"
}

Values are illustrative. issuer is cloud or studio. Cloud and Studio mint identical-looking addresses but revoke different things, so issuer says which one issued the address.

Errors: THIN_REQUEST_INVALID for a target that does not begin with / or runs over 512 characters. THIN_RESPONSE_INVALID when the issued address is not an HTTPS URL. THIN_AUTHENTICATION_FAILED, THIN_AUTHORIZATION_DENIED, THIN_NOT_FOUND.

hand the dataset page to the person watching
mr-data open "/datasets/$DATASET_ID" --open
Terminal window
mr-data clarify --question TEXT [--answer TEXT] [--answered-at MOMENT]
[--dataset DATASET_ID] [--no-activity] [--recipe RECIPE_ID]
[--attended | --unattended] [--json]

clarify asks whether one clarifying question may be put to the user right now, and turns the answer into the block it is recorded as. The gate allows a question only for a fact nobody but the user has. What a word in their request means, how wide they need it, how far back. The gate opens only before a recipe is registered. After that the same answer is a revision.

By default, it does not contact an external service or ask the question itself. Without --answer it reports whether the question may be asked and exits 1 when it may not, so mr-data clarify --question '…' && ask runs the ask only when the gate opens. With --answer it formats an exchange that already happened and returns the record. It stores nothing. Naming --dataset is the exception: the question goes on that page, so somebody watching sees what the work waits on.

Flag Argument Required Meaning Default
--question TEXT yes The one question, written as it would be put to the user. none
--answer TEXT no What the user answered. Giving it composes the record instead of asking the gate. none
--answered-at MOMENT no When they answered, as YYYY-MM-DDTHH:MM:SSZ. this machine’s clock
--dataset DATASET_ID no Put the question on this dataset’s page while the work waits. Best-effort, and it never fails the command. none
--no-activity none no Do not put the question on the page even when --dataset names one. off
--recipe RECIPE_ID no The registered recipe this is about. Naming one closes the gate. none
--attended none no State that a person is here to answer. inferred
--unattended none no State that nobody is here to answer. inferred
--json none no One JSON object instead of human lines. off

Without either flag, clarify reads an agent host that names itself in the environment (CLAUDECODE, CLAUDE_CODE_SESSION, CODEX_SESSION) as a conversation with somebody in it. CI or GITHUB_ACTIONS set beside it makes the session headless. A cron job carries none of these and stays unattended. A schedule cannot pass a flag, so an operator running mr-data on a timer outside CI exports MOSTLYRIGHT_ATTENDED=0. That veto beats an --attended written inside the process.

the gate, --json
{
"status": "clarification_allowed",
"question": "Which cities, and how far back?",
"may_ask": true,
"phase": "research",
"attendance": { "attended": true, "decided_by": "agent_host", "reason": "…" },
"refused_because": null,
"reason": null,
"attendance_variable": "MOSTLYRIGHT_ATTENDED"
}

status is clarification_allowed or clarification_refused. phase is research before registration and contract_agreed once --recipe names one. refused_because is no_one_to_ask or contract_already_agreed. attendance.decided_by is one of flag, environment, agent_host, headless_host, terminal, default, unreadable_environment. When --dataset named a page and the report reached it, the payload also carries activity_reported.

the record, --json
{
"status": "clarification_prepared",
"phase": "research",
"attendance": { "attended": true, "decided_by": "flag", "reason": "…" },
"block": {
"kind": "clarification",
"question": "Which cities, and how far back?",
"answer": "The twenty largest US metros, from 2020.",
"answered_at": "2026-09-12T09:00:00Z"
},
"carry_into": "This is the record of the exchange, not a copy of it that has been stored anywhere. …"
}

The block is the shape mr-data note --blocks-file accepts. Write the answer into the recipe document it settles as well, so it registers with the contract and reads on the dataset page.

Errors: THIN_CLARIFICATION_AFTER_CONTRACT when --answer arrives with --recipe, because that exchange is a revision. THIN_CLARIFICATION_TOO_LARGE when the question (200 characters) or the answer (1024 characters) runs over its ceiling. THIN_CLARIFICATION_CONTROL_CHARACTER for a control character other than tab and newline. The gate checks the question against its own ceiling before anybody is asked.

ask only if there is somebody to ask
mr-data clarify --question "Which cities, and how far back?" --dataset "$DATASET_ID" \
&& echo "ask the user" \
|| echo "assume the default and say so in the recipe description"
  • CLI reference: conventions, exit codes, environment variables
  • Datasets: the page open and clarify --dataset point at