WORKFLOW GOVERNANCE
Your orchestrator owns execution — SeaOtter is the acceptance layer underneath every step. It tells you what may run next and how each step is governed, and grades each step's output against your policy: ship / route_to_fix / quarantine / block / human_approval. Built for complex systems like mantur.ai — many steps, each with its own controls, decisions, and requirements, across any industry.
THE CONTROL KNOBS
A Workflow is a DAG of steps. Each step composes tighten-only over your org/team acceptance policy — it can add a rule or raise a bar, never remove an org rule or lower one. So you can safely delegate per-step control to a team, or to an external system.
policy_ref — the stored acceptance policy that governs this stepbands — per-step decision thresholds (ship / route_to_fix / quarantine / human_approval_below)hard_rules — deterministic gates (forbidden/required term, PII, regex, citation-required, min-score, max-flaw-severity)requirements — preconditions to ENTER the step (required input, upstream decision/score, manual sign-off)approval — a human-approval gate — required? which roles? SLA? escalation? on-timeout?routing — conditional branches (on_decision), terminal decisions (stop_on), bounded iterate-on-fix loops (max_visits)retry / timeout_secs / cost_cap_usd — execution guardsprovider / model — per-step routing hintsTHE CONNECT LOOP
POST /api/v1/workflows/from-template (browse GET /api/v1/workflows/verticals / …/templates).POST /api/v1/workflows/{id}/steps/{step_id}/evaluate grades each step and returns the governed decision.completed and call plan again until done.POST /api/v1/workflows/{id}/plan
{ "completed": { "draft": { "decision": "ship", "score": 0.9 } },
"inputs": { "query": "..." }, "signoffs": { "legal_ok": true } }
-> { "ready": [ { "step_id": "review",
"controls": { "bands": {...}, "approval": {...}, "policy_chain": [...] } } ],
"blocked": [ { "step_id": "...", "unmet_requirements": [...] } ],
"suppressed": [ "..." ], // a branch the routing did NOT take
"done": false, "terminal": null }DROP-IN SDK
Copy one file (sdk/workflow/) and the whole plan → run → evaluate loop is one call.
from seaotter_workflow import WorkflowClient
otter = WorkflowClient(base_url="https://api.seaotter.ai", api_key="sk-otter-...")
otter.from_template(vertical="comic-drama-video-mantur-ai", new_id="my-wf")
def run_step(step, controls):
return {"artifact_text": my_orchestrator.run(step["step_id"])}
result = otter.run("my-wf", run_step, inputs={"query": "..."}, grade_live=True)
print(result["terminal"]) # { "decision": "ship" | "block" | ... }GO DEEPER
workflows + workflow-templates.