DEVELOPER DOCUMENTATION
CLI Command Reference
Core OpenTrain CLI commands with links to dedicated references for rich Instructions, Project To-dos, LMS, and retraining workflows.
This page covers the core opentrain command surface. Rich workflow families use dedicated references so their safety sequence, capability discovery, and complete flags stay together. Commands support --json (raw API response) and --base-url <url> (override the API origin) unless their dedicated page says otherwise. Scope, feature-flag, and claim requirements are those of the wrapped endpoint.
See the CLI overview for installation, credentials, and conventions.
The instructions command group reads, previews, imports, uploads images, atomically revises, and verifies the canonical pages in a real job’s Instructions tab. CLI 0.23.0 adds hosted visual proof through the real employer and designated test-worker renderers. It has its own page.
The todos command group reads and manages the canonical Project To-dos and native quizzes for a job. Its explicit-audience, preview-first workflow, checksum-bound full retakes, selective coaching lifecycle, and hosted Native Forms visual proof have their own page (CLI 0.23.0+ for hosted quiz screenshots).
The lms group begins with opentrain lms capabilities --json, then provides canonical course authoring, Native Forms, assets, Preview, publishing, active-assignment rollouts, assignment, reporting, grading, and mastery operations. Publishing creates an immutable version but does not silently change existing learner assignments. Use lms rollout preview, confirmed lms rollout, then lms rollout status or receipt to advance them safely while preserving compatible progress. See Update an assigned LMS course. Its lms retraining subgroup creates one worker-specific case, returns a deterministic no-write authoring scaffold, runs worker-equivalent Preview, reviews a no-write assignment plan, assigns exactly one Project To-do, and monitors or closes the outcome. CLI 0.17.0 adds hosted desktop/mobile visual proof, closed typed browser steps, and observe-only employer review links. CLI 0.20.0 adds one canonical local-and-remote authoring analyzer plus a fail-closed publish acknowledgement gate. CLI 0.21.0 adds canonical draft authoring intent and the retraining scaffold. See Individualized LMS retraining.
Validate LMS authoring before publishing
Section titled “Validate LMS authoring before publishing”Run the same analyzer locally and remotely before you publish:
opentrain lms validate --dir ./course --remote --key <idempotency-key> --jsonUse --intent INDIVIDUAL_MASTERY when the course is intended for individualized mastery. The response may return acknowledgeable warnings for quiz-like lessons without an assessment, repeated answer positions, operational metadata in learner copy, or an overly long first check. A manual-review assessment under individualized mastery is a blocking error and cannot be acknowledged.
Publishing fails with AUTHORING_CONTRADICTION while a blocking error remains. It fails with AUTHORING_ACK_REQUIRED while a warning remains unacknowledged. To accept a reviewed warning, pass the exact acknowledgementId returned by the latest validation:
opentrain lms publish \ --dir ./course \ --intent INDIVIDUAL_MASTERY \ --acknowledge '<acknowledgementId>' \ --confirm-publish \ --key <idempotency-key> \ --jsonAcknowledgements apply only to that request. They are not stored on the course, and any content change invalidates the old IDs. lms push may proceed with warnings, but it does not acknowledge them or bypass the publish gate.
The checklists and feedback groups provide adaptive checklist authoring,
exact-revision browser preview, submission review, employer-private reviewer
reports, and reviewer grant management. They default to one JSON envelope and
use --pretty for human output. See Reviewer Feedback and Task
Checklists (CLI 0.14.0+).
The manager group is the context-first live-job control surface. It reads and
reconciles shared state, polls for real-time changes, claims actions, declares
spontaneous-work intents, reviews alternative proposals, separates TEAM,
PERSONAL, and SESSION guidance, records typed policies, sends guarded managed
messages, and leaves checkpoints or handoffs. See CLI: Shared Job
Context (CLI 0.11.0+ for the automatic
cross-command workflow).
Global
Section titled “Global”opentrain --version # print the CLI version (also: opentrain version)opentrain help # print usage (also: opentrain --help, or no arguments)capabilities
Section titled “capabilities”opentrain capabilities [--json]Returns canonical root capability discovery, including every agentSurfaces family status, required and granted scopes, and per-operation authorization. Call it before a multi-step workflow, then call that family’s scoped capability command—for LMS, opentrain lms capabilities --json.
Wraps GET /api/public/v1/capabilities.
Auth and Identity
Section titled “Auth and Identity”whoami
Section titled “whoami”opentrain whoami [--json]Alias of auth status — prints the authenticated user, token label, scopes, and account type.
Wraps GET /api/public/v1/auth/me.
auth register
Section titled “auth register”opentrain auth register [--agent-name <name>] [--org-name <name>] [--force] [--json]Creates an anonymous agent account and saves the pre-claim ot_pat_ token plus the claim token to the credentials file. Fails if credentials already exist unless --force is passed.
| Flag | Description |
|---|---|
--agent-name <name> | Display name for the agent identity (alias --name) |
--org-name <name> | Name for the employer organization created with the account (alias --organization-name) |
--force | Overwrite existing saved credentials |
opentrain auth register --agent-name "Hiring agent" --org-name "Acme Research" --jsonWraps POST /api/agent/identity.
auth claim
Section titled “auth claim”opentrain auth claim --email <human-email> [--claim-token <token>] [--json]Emails the human owner an invitation to claim the agent-registered account. The claim token defaults to the one saved by auth register.
| Flag | Description |
|---|---|
--email <address> | Required. The human owner’s email address |
--claim-token <token> | Claim token to use; defaults to the saved one |
Wraps POST /api/agent/identity/claim.
auth claim-status
Section titled “auth claim-status”opentrain auth claim-status [--wait] [--timeout <seconds>] [--claim-token <token>] [--json]Checks whether the human completed the claim. On success the saved token is upgraded automatically to the claimed account’s scopes. Without --wait it checks once and reports pending; with --wait it polls (respecting slow_down backoff) until claimed or the timeout elapses.
| Flag | Description |
|---|---|
--wait | Poll until the claim completes |
--timeout <seconds> | Give up waiting after this long (default 1800) |
--claim-token <token> | Claim token to check; defaults to the saved one |
opentrain auth claim-status --wait --timeout 600Wraps POST /api/agent/oauth/token.
auth login
Section titled “auth login”opentrain auth login --api-key <token> [--base-url <url>]Verifies an existing ot_pat_ token against the API, then saves it to the credentials file.
| Flag | Description |
|---|---|
--api-key <token> | Required. The personal API token (alias --token) |
Wraps GET /api/public/v1/auth/me for verification.
auth status
Section titled “auth status”opentrain auth status [--json]Same as whoami. Wraps GET /api/public/v1/auth/me.
auth logout
Section titled “auth logout”opentrain auth logoutDeletes the saved credentials file. Purely local — it does not revoke the token; use tokens revoke for that.
jobs draft create
Section titled “jobs draft create”opentrain jobs draft create --description <text> [--title <title>] [--external-id <id>] [--idempotency-key <key>] [--json]Creates an unpublished draft from a plain-text job description (the primary workflow) or a structured payload. The response includes the validation state: each missing field carries an ask: question, type, allowed enum values, and the field name to set with jobs draft update. Alias: jobs create.
| Flag | Description |
|---|---|
--description <text> | Plain-text job description or project brief |
--description-file <path> | Read the description from a file instead |
--canonical-file <path> | JSON file with an OpenTrain canonical job object |
--payload-file <path> | JSON file with a supported import payload (e.g. schema.org JSON-LD) |
--title <title> | Title to prepend to plain-text descriptions |
--external-id <id> | Source-system id for audit |
--idempotency-key <key> | Reuse to avoid duplicate drafts on retry |
opentrain jobs draft create \ --description "Label 5,000 street-scene images with bounding boxes. Native Spanish speakers, \$14/hr." \ --jsonWraps POST /api/public/v1/job-drafts.
jobs draft update
Section titled “jobs draft update”opentrain jobs draft update --job-id <id> --set <field=value> [--set <field=value> ...] [--json]Fills in or corrects fields on an unpublished draft. --set values are auto-coerced (numbers, booleans, JSON arrays; everything else stays a string); repeat the loop until the draft is publish-ready. Alias: jobs update.
| Flag | Description |
|---|---|
--job-id <id> | Required. The draft job id |
--set <field=value> | Set one field (repeatable) — use the set: field names from the validation output |
--patch-file <path> | JSON file with a field patch object (alternative to --set) |
--patch-json <json> | Inline JSON patch object (alternative to --set) |
opentrain jobs draft update --job-id <JOB_ID> \ --set paymentType=PAY_PER_HOUR --set pricePerHour=14 --jsonWraps PATCH /api/public/v1/job-drafts/{jobId}.
jobs list
Section titled “jobs list”opentrain jobs list [--status <status>] [--limit <n>] [--cursor <cursor>] [--json]Lists your own jobs with publish state, proposal counts, and live URLs.
| Flag | Description |
|---|---|
--status <status> | Filter: DRAFT, OPEN, ONGOING, COMPLETED, ARCHIVED, PENDING_APPROVAL |
--limit <n> | Page size (max 100, default 25) |
--cursor <cursor> | Pagination cursor from the previous page |
Wraps GET /api/public/v1/jobs/mine.
jobs search
Section titled “jobs search”opentrain jobs search [--q <text>] [--category <slug>] [--language <lang>] [--country <iso>] [--pay-type <type>] [--limit <n>] [--cursor <cursor>] [--json]Searches the public marketplace (all live jobs, not just yours). No token required.
| Flag | Description |
|---|---|
--q <text> | Free-text query |
--category <slug> | Category filter |
--language <lang> | Language filter |
--country <iso> | ISO country code |
--pay-type <type> | PAY_PER_HOUR, FIXED_PRICE, or PAY_PER_LABEL |
--limit <n> / --cursor <c> | Pagination |
Wraps GET /api/public/v1/jobs.
jobs publish
Section titled “jobs publish”opentrain jobs publish --job-id <id> [--json]Publishes a publish-ready draft live on the marketplace, running the same validation and moderation pipeline as the in-app flow. Subject to daily publish limits.
Wraps POST /api/public/v1/jobs/{id}/publish.
jobs invite
Section titled “jobs invite”opentrain jobs invite --job-id <id> --freelancer-id <id> [--json]Invites an AI trainer to a published job, creating a proposal. Idempotent — re-inviting returns the existing proposal.
Wraps POST /api/public/v1/jobs/{id}/invites.
jobs close
Section titled “jobs close”opentrain jobs close --job-id <id> [--json]Archives a published job: it stops accepting proposals and leaves public listings. Existing contracts are unaffected. Idempotent.
Wraps POST /api/public/v1/jobs/{id}/close.
jobs update-published
Section titled “jobs update-published”opentrain jobs update-published --job-id <id> --set <field=value> [--set <field=value> ...] [--json]Patches a live (OPEN) job using the same field names and --set/--patch-file/--patch-json flags as jobs draft update. The revised listing is re-moderated; a blocked result unpublishes the job back to draft.
Wraps PATCH /api/public/v1/jobs/{id}.
Proposals and Candidates
Section titled “Proposals and Candidates”proposals list
Section titled “proposals list”opentrain proposals list --job-id <id> [--status <status>] [--limit <n>] [--cursor <cursor>] [--json]Lists proposals for a job with statuses, bids, and AI-interview scores — the ranking view for deciding who to interview or hire.
| Flag | Description |
|---|---|
--job-id <id> | Required. The job to list proposals for |
--status <status> | Filter, e.g. UNREVIEWED, SHORTLISTED, HIRED, DECLINED |
--limit <n> / --cursor <c> | Pagination (max 100, default 25) |
Wraps GET /api/public/v1/jobs/{id}/proposals.
proposals get
Section titled “proposals get”opentrain proposals get --proposal-id <id> [--interview] [--json]Reads the full candidate evaluation: bid, AI-interview score and summary, verification, assessment results, and contract state. --interview also fetches the sanitized AI-interview transcript. Alias: proposal get.
Wraps GET /api/public/v1/proposals/{proposalId} and, with --interview, GET /proposals/{proposalId}/interview.
proposals hire
Section titled “proposals hire”opentrain proposals hire --proposal-id <id> --amount <usd> [--milestone-name <name>] [--milestone-description <text>] [--due-date <iso>] [--confirm-not-fit-override] [--json]Requests a hire — never hires anyone or moves money. Records a pending approval and returns 202 with an approvalUrl a signed-in human must confirm in the OpenTrain app; on confirm, the contract is created and the first escrow milestone funded. A 409 payment_method_required includes a billingUrl a human must visit. Alias: proposal hire.
| Flag | Description |
|---|---|
--proposal-id <id> | Required. The proposal to hire from |
--amount <usd> | Required. First milestone amount in USD |
--milestone-name <name> | Short milestone name |
--milestone-description <text> | What the first milestone delivers |
--due-date <iso> | Milestone due date (ISO 8601) |
--confirm-not-fit-override | Confirm hiring a candidate previously marked “Not a fit” after a 409 not_fit_confirmation_required |
opentrain proposals hire --proposal-id <PROPOSAL_ID> --amount 500 \ --milestone-name "First batch" --milestone-description "First 1,000 labeled images" --jsonWraps POST /api/public/v1/proposals/{proposalId}/hire.
freelancers get
Section titled “freelancers get”opentrain freelancers get --id <user-id-or-slug> [--json]Reads a masked AI trainer profile (skills, stats, work and labeling experience, education, reviews) by user id or public profile slug. Names stay masked to first name + last initial; personal contact details are never returned. Alias: freelancer get.
Wraps GET /api/public/v1/freelancers/{idOrSlug}.
Messages
Section titled “Messages”messages list
Section titled “messages list”opentrain messages list [--filter all|job|proposal] [--unread-only] [--limit <n>] [--cursor <cursor>] [--json]Lists conversation summaries you participate in, with unread counts and the latest message.
Wraps GET /api/public/v1/messages.
messages unread
Section titled “messages unread”opentrain messages unread [--filter all|job|proposal] [--limit <n>] [--cursor <cursor>] [--json]Shorthand for messages list --unread-only — only conversations with unread messages.
messages read
Section titled “messages read”opentrain messages read --conversation-id <id> [--limit <n>] [--direction older|newer] [--cursor <cursor>] [--json]Reads messages inside one conversation, paginated in either direction.
Wraps GET /api/public/v1/messages?conversationId=....
messages send
Section titled “messages send”opentrain messages send --conversation-id <id> --content <text> [--json]Sends a plain-text message (max 10,000 chars) into an existing conversation. Use --content-file <path> to read the message body from a file.
Wraps POST /api/public/v1/messages.
messages start-proposal-thread
Section titled “messages start-proposal-thread”opentrain messages start-proposal-thread --proposal-id <id> [--json]Opens (or fetches) the pre-hire direct-message thread for a proposal — idempotent get-or-create, employer side only. Returns the conversationId to use with messages send.
Wraps POST /api/public/v1/proposals/{proposalId}/conversation.
Contracts and Milestones
Section titled “Contracts and Milestones”contracts list
Section titled “contracts list”opentrain contracts list [--job-id <id>] [--status active|ended] [--json]Lists contracts (hired AI trainers) with milestones, the masked freelancer identity (first name + last initial), and the post-hire job DM conversationId.
Wraps GET /api/public/v1/contracts.
contracts get
Section titled “contracts get”opentrain contracts get --contract-id <id> [--json]Reads one contract in detail. Alias: contract get.
Wraps GET /api/public/v1/contracts/{contractId}.
contracts end
Section titled “contracts end”opentrain contracts end --contract-id <id> [--json]Ends a contract. With no funded milestones it ends immediately; with funded escrow at stake it returns a pending approval with an approvalUrl a human must confirm.
Wraps POST /api/public/v1/contracts/{contractId}/end.
admin-balance-milestones create
Section titled “admin-balance-milestones create”opentrain admin-balance-milestones create \ --contract-id <id> \ --idempotency-key <key> \ --description <text> \ --amount <usd> \ [--volume <hours-or-labels>] \ [--name <name>] \ [--due-date <iso>] \ --jsonCreates and internally funds a later milestone for an eligible OpenTrain platform-admin workflow. For hourly and per-label contracts, provide a positive --volume or omit it to let OpenTrain derive the volume from --amount and the canonical contract rate. A supplied amount, rate, and volume must agree.
This command is not an ordinary employer funding option. The server independently requires the restricted scope, platform-admin status, canonical admin-organization membership, Admin Pay eligibility, matching token organization, and the default-off rollout. The funding step moves $0 and creates no Stripe charge or PaymentIntent. Releasing payment later remains a separate human-authorized action.
Wraps POST /api/public/v1/contracts/{contractId}/admin-balance-milestones.
admin-balance-milestones fund
Section titled “admin-balance-milestones fund”opentrain admin-balance-milestones fund \ --contract-id <id> \ --milestone-id <id> \ --idempotency-key <key> \ --jsonApplies the restricted ADMIN_BALANCE funding marker to one existing eligible NOT_FUNDED milestone in place. It never creates a replacement milestone. Reuse the same idempotency key when retrying an uncertain request; using the key with a different request fails closed.
The command verifies the contract-to-milestone relationship, amount/rate/volume consistency, milestone state, sequencing, payment holds, and every platform-admin authorization gate. Success changes the existing milestone to ACTIVE_FUNDED, moves $0, and creates no Stripe charge or PaymentIntent. Payment release still requires a separate human approval in OpenTrain.
Wraps POST /api/public/v1/contracts/{contractId}/admin-balance-milestones/{milestoneId}/fund.
milestones create
Section titled “milestones create”opentrain milestones create --contract-id <id> --description <text> [--name <name>] [--amount <usd>] [--volume <n>] [--due-date <iso>] [--json]Adds an unfunded milestone to an active contract — no money moves at creation.
| Flag | Description |
|---|---|
--contract-id <id> | Required. The contract to add to |
--description <text> | Required. What the milestone delivers |
--name <name> | Short milestone name |
--amount <usd> | Milestone amount in USD |
--volume <n> | Unit volume for per-unit milestones (e.g. label count) |
--due-date <iso> | Due date (ISO 8601) |
Wraps POST /api/public/v1/contracts/{contractId}/milestones.
milestones fund
Section titled “milestones fund”opentrain milestones fund --milestone-id <id> [--json]Requests escrow funding. No money moves: the response is a pending approval with an approvalUrl a signed-in human must open and confirm (expires in ~72 h). Track with approvals get or updates poll.
Wraps POST /api/public/v1/milestones/{milestoneId}/fund.
milestones approve
Section titled “milestones approve”opentrain milestones approve --milestone-id <id> [--json]Requests release of a funded milestone’s escrow. Same human co-sign pattern as milestones fund.
Wraps POST /api/public/v1/milestones/{milestoneId}/approve.
approvals get
Section titled “approvals get”opentrain approvals get --approval-id <id> [--json]Checks a pending human co-sign approval: pending, confirmed, declined, or expired, plus the execution result once confirmed. Alias: approval get.
Wraps GET /api/public/v1/approvals/{approvalId}.
Credits
Section titled “Credits”credits show
Section titled “credits show”opentrain credits show [--json]Reads the prepaid credit balance — available vs reserved (escrow-held) — plus recent ledger activity. Alias: credits balance.
Wraps GET /api/public/v1/credits.
credits ledger
Section titled “credits ledger”opentrain credits ledger [--cursor <cursor>] [--limit <n>] [--json]Pages the full ledger of top-ups, holds, releases, captures, refunds, and adjustments, newest first.
Wraps GET /api/public/v1/credits/ledger.
credits top-up
Section titled “credits top-up”opentrain credits top-up --amount <usd> [--json]Starts a Stripe Checkout top-up ($10–$10,000) and returns a checkoutUrl a human must open and pay — no money moves from the command itself.
Wraps POST /api/public/v1/credits/top-ups.
credits top-up-status
Section titled “credits top-up-status”opentrain credits top-up-status --top-up-id <id> [--json]Checks a top-up: pending (awaiting payment), completed, canceled, or expired.
Wraps GET /api/public/v1/credits/top-ups/{topUpId}.
Updates
Section titled “Updates”updates poll
Section titled “updates poll”opentrain updates poll [--cursor <cursor>] [--limit <n>] [--json]Polls the account delta feed — small ID-only events for new proposals, messages, contracts, milestone changes, and pending payments. Persist the returned nextCursor and pass it as --cursor on the next poll.
Wraps GET /api/public/v1/updates.
Webhooks
Section titled “Webhooks”webhooks create
Section titled “webhooks create”opentrain webhooks create --url <url> --events <type,...> [--json]Subscribes an HTTPS URL to platform events. The response includes the signing secret once — store it and use it to verify the X-OpenTrain-Signature header.
| Flag | Description |
|---|---|
--url <url> | Required. HTTPS delivery endpoint |
--events <type,...> | Required. Comma-separated event types, e.g. proposal.received,message.received |
Wraps POST /api/public/v1/webhooks.
webhooks list
Section titled “webhooks list”opentrain webhooks list [--json]Lists subscriptions with status (ACTIVE or DISABLED). Secrets are never included.
Wraps GET /api/public/v1/webhooks.
webhooks get
Section titled “webhooks get”opentrain webhooks get <webhook-id> [--json]Reads one subscription, including disable details after sustained delivery failure. The id can also be passed as --webhook-id. Alias: webhook get.
Wraps GET /api/public/v1/webhooks/{webhookId}.
webhooks delete
Section titled “webhooks delete”opentrain webhooks delete <webhook-id> [--json]Deletes a subscription and stops deliveries. Deleting and re-creating is also how a DISABLED subscription is resumed (the new one gets a new secret).
Wraps DELETE /api/public/v1/webhooks/{webhookId}.
Tokens
Section titled “Tokens”tokens list
Section titled “tokens list”opentrain tokens list [--json]Lists every API token on the account — names, scopes, status, expiry. Secrets are never returned.
Wraps GET /api/public/v1/tokens.
tokens revoke
Section titled “tokens revoke”opentrain tokens revoke --token-id <id> [--json]Revokes a token by id — immediate and irreversible. Revoking the token the CLI is currently using breaks subsequent commands.
Wraps DELETE /api/public/v1/tokens/{tokenId}.
team show
Section titled “team show”opentrain team show [--json]Reads the employer team: organization, members with roles, and pending invites.
Wraps GET /api/public/v1/team.
team invite
Section titled “team invite”opentrain team invite --email <address> [--json]Emails a human an invitation to join the team with shared job and inbox access.
Wraps POST /api/public/v1/team/invites.
Payments
Section titled “Payments”payments pending
Section titled “payments pending”opentrain payments pending [--json]Reads pending payment and milestone state visible to the token owner. Read-only — it never releases funds or changes payment settings.
Wraps GET /api/public/v1/payments/pending.
Instructions
Section titled “Instructions”opentrain instructions <subcommand> [...]Inspect, preview, create, import, upload images, patch, replace, organize, archive, stage a complete tree, apply it atomically, and verify Job Instructions. Every operation is keyed by job ID and addresses the real job tab. Rename commands preflight without writing when --confirm-live is omitted, and bundle plans omit unchanged ordering operations. Version 0.23.0 adds instructions visual sessions, desktop/mobile renders, private artifacts, and short-lived human review links. If an old script references instructions assets, run instructions assets help for the canonical image-upload replacement. See CLI: Job Instructions.
Wraps the Instructions API.