The data model
- An item is one logical to-do on a job, organized under an optional category.
- Every edit publishes a new immutable version. History is never rewritten.
- An assignment is one person’s obligation for one item version, with an append-only event and evidence trail.
- Quizzes are to-do items pinned to one immutable published form version.
Audiences are always explicit
Every create, assign, or reissue names its audience. There is no default: omittingaudience fails with 400 instead of assigning anyone.
SELECTED fails closed. The list must be non-empty and duplicate-free, and every ID must be an active contract of that exact job. An unknown, ended, or foreign ID rejects the whole request with each offender named — nothing is silently dropped, and SELECTED can never turn on future-hire auto-assignment.
Preflight receipts for broad assignments
ACTIVE, FUTURE, and ACTIVE_AND_FUTURE fan out beyond an explicit list, so they require a two-step confirmation:
- Call the no-write preflight with the exact request you intend to send. It returns the live recipients (masked names, contract IDs, and counts), future-hire semantics, projected due and blocking behavior, duplicate candidates, and a signed
receipt. - Send the mutation unchanged with
preflightReceiptset to that token.
409 and a PREFLIGHT_RECEIPT_* reason, and you preflight again. Roster changes that land between the receipt check and the write itself also fail closed with 409 RECIPIENTS_CHANGED.
SELECTED does not need a receipt: the explicit ID list is already the exact confirmation.
Idempotency is bound to the whole request
Every mutation requires anidempotencyKey (8–200 characters). For item creation the key is bound to the complete request — definition, audience, selected contracts, placement, and future-hire semantics:
- The same key with the same request replays: you get the committed result with
replayed: true, and no new assignments are created. A replay never re-resolves the roster, so a person hired after the original create is not silently added. - The same key with a changed request fails with
409— a reused key can never widen a fan-out. - A different key with an identical active request fails with
409 LIKELY_DUPLICATEunless you explicitly passallowDuplicate: true.
Normalized results
Mutations return an explicit, machine-readable outcome: the item and version IDs, the audience echo with future-hire semantics, a fan-out summary (matchedContracts, createdAssignments, assignmentIds), the masked recipients the request was verified against, a replayed flag, and warnings. Archiving returns the exact number of open assignments it closed, and that archiving is not reversible through this surface while history is retained.
Provider-backed obligations use the same control plane
Configuring a provider connection does not invite or enroll anyone. It publishes the provider-verified to-do dormant, with no audience and future-hire assignment off. Assigning that normal Project To-do is the only action that provisions the selected people with the provider. Closing one person’s provider to-do is the canonical unassignment: future sync and provider enrollment stop while the person’s event history remains available for audit. There is no parallel manual-invite path.WAIVE remains the audited administrative override, but it terminates only the OpenTrain obligation and does not stop provider sync; use CLOSE whenever the intent is to remove provider access.
Selective coaching is not a full retake
Selective coaching lets an employer draft threaded feedback and choose the exact quiz questions a worker must redo. The employer first creates a no-write send-back plan; confirmation applies only the signed selection and rejects review-state drift. The worker can then start or resume, edit only the requested answers, reply to visible threads, and resubmit. A full retake reopens the whole quiz and grants another attempt on the same immutable version. Batch full retakes use a separate no-write plan and checksum-bound apply. Keeping these workflows separate prevents a targeted correction from silently widening into a full reassessment.Privacy
Agent responses identify people by contract ID, user ID, and a masked display name (first name plus last initial). Personal emails never appear in list responses, and the CSV export serves theworker_email column blank.
Permissions
Employer reads requireproject_todos:read; employer mutations require project_todos:write, employer access to the job, and a claimed account. Those two scopes are available on fine-grained employer keys and included in employer Full access. Worker coaching instead requires a worker-minted project_todos:respond key and exact assignment ownership; that worker-only scope is deliberately excluded from employer Full access.
The account must also have the default-off project_todos_integrations agent-surface family enabled; a full-access key does not bypass that separate gate. Static coaching-capability discovery is the only ungated exception and returns no tenant data. See Scopes and capabilities.
Where to go next
- API reference — endpoints, actions, and errors.
- Quiz surface — authoring, assigning, grading, and retakes.
- Selective coaching — targeted redo, threads, worker responses, exports, and feedback images.
- CLI — preview-first
opentrain todoscommands. - MCP tools — the same safety contract for MCP agents.