Cases, tasks, and records
Preserve useful shared state without turning Epismo into the execution runtime.
A case is one real matter. It can be pinned to an immutable playbook version or started ad hoc with a title. A playbook-backed case stores the playbook ID and version ID; it does not track step progress. Every case receives an internal UUID id and an immutable, pronounceable Case code (e.g. PANDA-317). Case detail and access reads accept either identifier. When another operation asks for a case ID, use the UUID.
Case lifecycle
A case has a status of open, completed, or cancelled. Moving a case to completed requires every task to be closed; moving to cancelled closes remaining open tasks as part of the case transition. Reopening a case sets its status back to open but does not reopen its tasks.
Archiving is separate from closing. An archived case leaves every list, count, and handoff graph and stops resolving for reads, while its tasks, records, and handoffs are retained rather than deleted. Only the current case assignee can archive one, from the web app.
A case may finish with no tasks and no records. Use that lightweight form when only the fact of the case needs to be retained.
Public cases publish records, not tasks
A case can include public in its ACL, the same sentinel playbooks use. Anyone with only the public grant reads the published title, input, records, and readable handoff neighborhood. Tasks, assignment, and collaborator identities are not published; if a task's outcome matters, it should already be a record.
Collaborators on the case ACL still see the live case. Publishing does not start a new case. The same case continues, and later records stay in that public projection.
Case mutations use optimistic concurrency. Send the latest lockVersion; after a conflict, re-read the case and reconsider the change rather than replaying stale intent. Collaborators with work access may assign the case, retitle it, close it, reopen it, and connect handoffs. Replacing the ACL or access, and archiving, stay with the current assignee. started_by is history.
Tasks are created on demand
A task is explicit work within a case. Its kind is work or approval; it may be assigned to a user, linked to a source step, and, for approval work, point to the exact subject record. An approval task is a human or agent judgment of that record. It is distinct from an Epismo AI review, which queues Epismo AI to judge the case's shared evidence and later append a review record with origin=system.
Starting a case does not create one task per step. Create a task only when responsibility, handoff, approval, or a separately tracked piece of work should be visible. Multiple tasks can be open and closing one does not advance the case automatically.
Task updates also use lockVersion. Any case editor may update an open task, including its assignee. A closed task can be reopened only while its parent case is open.
Directed handoffs connect cases
Cases can be linked into a directed acyclic graph (DAG) using handoffs (fromCaseId -> toCaseId). Handoffs model multi-stage or cross-team continuations while preserving individual case ACLs and lifecycles. Creating or removing a handoff requires read access on the source and work access on the destination: a public case can be continued into a case the caller can edit, but a reader cannot attach work into a public case.
- Cycle prevention: handoff creation enforces cycle-free graphs using transactional reachability checks. Self-links and cyclic paths are rejected.
- Candidate discovery: Query eligible upstream or downstream cases to discover valid connection targets without trial-and-error.
- Handoff graph: View the connected DAG around a root case across configurable scopes (
self,ancestors,descendants,neighbors,connected). Traversal continues through every readable case, including public cases, and stops at cases the caller cannot read. A public reader can therefore see other published branches of the same connected graph.
Records are the handoff surface
Records are shared context entries on a case timeline and may also belong to a task or source step. kind is closed: clients write note (commentary, a decision, or a handoff), output (a durable deliverable; appending one can trigger an Epismo AI review), or review (a verdict; data.verdict must be pass, changes_requested, or insufficient). The server writes activity (a coordination event) and Epismo AI reviews (origin=system). Records also include optional human-readable content, structured data, origin (user, agent, or system), creator, client identity, and creation time. Human- and agent-authored records can be updated or redacted by their creator; task and provenance fields stay fixed. A delete leaves a tombstone (deleted_at) so references keep working.
Good records include outcomes, evidence, decisions, file or object references, handoff summaries, and meaningful errors. Do not automatically store chain-of-thought, every tool call, raw shell output, credentials, retry history, heartbeat, or the runtime graph. Any case editor can request an Epismo AI review with POST /v1/cases/{caseId}/review; that call queues the review and returns immediately. Optional prompt adds caller guidance after the fixed review rules. Enable case autoReview so appending an OUTPUT record enqueues one. Poll those records with kinds=review and origins=system. Any case editor can also request a one-shot situational overview with POST /v1/cases/{caseId}/overview; it runs synchronously and returns the brief in the response. Replay the same idempotency key to receive the prior brief without regenerating. Auto and manual reviews, and overviews, charge the case billing account captured at start. The case home must allow Epismo AI (AI settings); when it does not, turning autoReview on and manual review or overview requests are rejected, while already-on auto reviews skip without a record or charge.
The creator of a record can update its kind, content, or data, or redact it. Anyone covered by the case ACL can still append a new record. Records are listed within a case, with stable cursor pagination and optional task, author, kind, origin, ACL, and sort-order filters. Passing a handoff scope (such as ancestors or connected) expands the query across connected handoffs while evaluating caller access for each case independently.