Process Flows
Author Process Flows via the SDK — stages, tasks, personas, action templates, and voice triggers — and ship them as packs
This artifact ships inside a Pack. For the shared lifecycle — install, pack build, upload — see Packs & Authoring SDK.
A Process Flow is a structured, repeatable workflow with stages, tasks, and personas — kickoffs, audits, onboarding, due-diligence reviews. You author it once as a Process Flow using this SDK and ship it inside a .scrydon-pack.tar.gz; the platform instantiates it per run as a Process Flow.
SDK and pack are the only authoring path. Process Flows are defined in code using this SDK and installed via the platform's Settings → Packs upload. There is no in-app editor. Once a pack is installed, workspace admins add the template to an environment from the Marketplace, making it instantiable in Process Flows.
process flow bundles are pure data. The bundle is JSON — no executable code ever ships in the archive. Custom logic is referenced by ID against system or organization-level workflows.
Scrydon Pack Bundles. Process flows ship as .scrydon-pack.tar.gz archives that bundle the flow alongside its ontology (and, in future releases, KB seeds and block packs). The pack imports atomically — ontology install, slug → tenant class ID rebind, process-flow materialise, all in one transaction. Build with bunx @scrydon/sdk-authoring pack build; inspect with bunx @scrydon/sdk-authoring pack inspect. See the spec and packages/sdk-authoring/src/packs/examples/ai-boardroom/ for a worked example.
Install
bun add -d @scrydon/sdk-authoring zodnpm install --save-dev @scrydon/sdk-authoring zodimport {
defineProcessFlow,
defineStage,
defineTask,
defineAction,
definePersona,
defineVoiceTrigger,
} from '@scrydon/sdk-authoring/process-flows'Anatomy of a template
| Element | Purpose |
|---|---|
| Package | Identity of the bundle: id, name, version |
| Template | The flow itself — default view, execution config, metadata |
| Persona | Roles a task can be assigned to (one, many, or system) |
| Stage | An ordered phase. Transitions are manual, automatic, or approval |
| Task Template | Work items inside stages. Carry actions, dependencies, default attributes |
| Action Template | The thing a task asks the user to do — checklist, document, approval, workflow, entity_link, file_upload, distribution, voice_trigger |
| Voice Trigger | Optional voice-driven enrichment block scoped to a path |
A complete example
import {
defineProcessFlow,
defineStage,
defineTask,
defineAction,
definePersona,
} from '@scrydon/sdk-authoring/process-flows'
export default defineProcessFlow({
manifestVersion: 1,
package: {
id: 'acme.kickoff',
name: 'Acme Customer Kickoff',
version: '1.0.0',
},
template: {
slug: 'acme-kickoff',
name: 'Customer Kickoff',
description: 'Standard onboarding flow for new enterprise customers',
version: '1.0.0',
defaultView: 'wizard',
executionConfig: {
stageFlow: 'sequential',
taskFlow: 'parallel',
allowRuntimeTaskCreation: true,
},
metadata: {
icon: 'rocket',
color: '#2563eb',
tags: ['onboarding', 'sales'],
},
personas: [
definePersona({ slug: 'csm', displayName: 'Customer Success Manager', cardinality: 'one' }),
definePersona({ slug: 'champion', displayName: 'Customer Champion', cardinality: 'one' }),
definePersona({ slug: 'system', displayName: 'System', cardinality: 'system' }),
],
stages: [
defineStage({
slug: 'discovery',
name: 'Discovery',
transitionMode: 'manual',
estimatedDuration: { value: 5, unit: 'days' },
}),
defineStage({
slug: 'rollout',
name: 'Rollout',
transitionMode: 'approval',
}),
],
taskTemplates: [
defineTask({
slug: 'collect-stakeholders',
stageSlug: 'discovery',
name: 'Collect stakeholders',
defaultAssignedRoleSlug: 'csm',
actions: [
defineAction({
name: 'Stakeholder list',
actionType: 'document',
isRequired: true,
metadata: { persona: 'csm' },
}),
],
}),
defineTask({
slug: 'kickoff-call',
stageSlug: 'discovery',
name: 'Kickoff call',
dependsOnTaskSlugs: ['collect-stakeholders'],
actions: [
defineAction({
name: 'Record kickoff call',
actionType: 'voice_trigger',
isRequired: true,
metadata: { triggerPath: '/kickoff/' },
}),
defineAction({
name: 'Capture summary to KB',
actionType: 'workflow',
isRequired: false,
workflowId: 'system.summarize-meeting',
metadata: { promoteToCorpus: 'summary' },
}),
],
}),
defineTask({
slug: 'rollout-plan',
stageSlug: 'rollout',
name: 'Approve rollout plan',
dependsOnTaskSlugs: ['kickoff-call'],
actions: [
defineAction({
name: 'Approve plan',
actionType: 'approval',
isRequired: true,
metadata: { persona: 'champion' },
}),
],
}),
],
voiceTriggers: [],
},
})Action Types
| Action type | Use it for |
|---|---|
checklist | A simple to-do the user marks complete |
document | A document the user must produce or attach |
approval | An approval gate — assigned to a persona, blocks downstream tasks until granted. Rejecting the gate (the Reject button) halts the flow: the gate's task stays open and no downstream stage unlocks, whether or not the approval action is marked required, until the gate is re-decided to approved or skipped as an explicit override |
workflow | Reference an executable workflow — either by workflowId (a pre-existing system or org workflow in the tenant) or by workflowSlug (a workflow shipped in the same Pack — see Workflows). The two are mutually exclusive |
entity_link | Link the task to a typed Object instance via the ontology |
file_upload | A file drop — bytes get ingested into the instance KB |
distribution | Send to a channel (email, slack, teams); supports quorum, fire-and-forget, all-acknowledged |
voice_trigger | Capture audio against a path — STT runs and the transcript flows into KB |
See Action Types for a per-type deep-dive with copy-pasteable examples, runtime UX notes, and the metadata fields each type reads.
Approval-gate routing
When a stage has transitionMode: "approval", the platform notifies the right people the moment a task reaches the gate. Three fields on defineStage control who is notified and how many approvals are required:
| Field | Type | Default | Description |
|---|---|---|---|
approverPersona | string (slug) | "owner" | The persona whose current members receive the approval-request notification. Falls back to the org owner role when no users hold the persona. |
resolutionMode | "first_claim" | "all_must_approve" | "quorum" | "first_claim" | When multiple approvers are notified, determines the decision rule. first_claim — any one approver can decide. all_must_approve — every notified user must approve. quorum — at least quorumN approvers must approve. |
quorumN | number (integer ≥ 1) | — | Required when resolutionMode: "quorum". The minimum number of approvals needed. |
When the gate is reached, the platform sends a process.approval_requested notification to each resolved user and displays "Approval request sent · N notified · sent <date>" in the approval task sheet.
Example — legal-quorum gate:
defineStage({
slug: 'legal-review',
name: 'Legal review',
transitionMode: 'approval',
approverPersona: 'legal-reviewer',
resolutionMode: 'quorum',
quorumN: 2,
})The flow halts at the gate until the quorum is satisfied. Rejecting the gate halts the flow regardless of quorum count — a single rejection is always final.
Grounding an AI step in workspace documents (metadata.retrieval)
The reverse direction: a workflow action that runs an agent — a @system/*
built-in or a pack/canvas workflow (inline or sibling) — can be
grounded in one or more documents uploaded earlier in the flow, so the agent reasons over real inputs instead of the task name alone. Declare it with
metadata.retrieval on the action:
defineAction({
name: "AI Qualification Assessment",
actionType: "workflow",
isRequired: false,
executionMode: "automatic", // run when the stage is entered
workflowId: "@system/agent-project-qualifier",
metadata: {
aiAgent: "project-qualifier",
// Where the agent result lands, by target ACTION TYPE (see below):
// an assessment on this workflow step itself, and an advisory banner
// on the flow's human approval action.
outputSurface: [
{
kind: "workflow",
contentType: "project_qualification_assessment",
pageTitle: "AI Qualification Assessment",
},
{
kind: "approval",
targetTaskSlug: "go-no-go-decision",
advisorySource: "ai-qualification",
},
],
retrieval: {
// The document(s) the agent must judge. `fromTask` is the slug of an
// earlier task: its completed document action's page, its file_upload
// action's ingested documents, and/or its workflow (agent) action's
// assessment page are injected in full.
inputs: [{ fromTask: "upload-source", mode: "full" }],
// Optional. The per-input-document character cap: in `full` mode the
// verbatim clip ceiling, in `summary` mode the target the condense fits
// to. Raise it when a large `mode: "full"` document is being clipped.
// Omitted → mode-derived default (full: 24,000; summary: 4,000).
inputDocMaxChars: 60_000,
},
},
})| Field | Meaning |
|---|---|
retrieval.inputs[] | { fromTask, mode }. Loads the document(s) produced at fromTask (a task slug): the page written by the task's completed document action, the pages derived from its file_upload action's uploads, and/or the assessment page written by its agent workflow action — resolved deterministically from the task itself, with a lexical KB search as fallback for runtime-created tasks. Pointing fromTask at an earlier agent step is how one agent grounds on another agent's output (e.g. a consolidation step over several advisory steps) — the upstream agent step must declare outputSurface: "workflow" (surfaces are author-declared, never implicit), otherwise no assessment page exists for the downstream step to load. mode: "full" (default) injects the verbatim document, clipped to the cap (default 24,000 chars) when it exceeds it — a […document truncated] marker is emitted and the step's Prompt & Context panel warns you that content was dropped, so clipping is never silent; raise retrieval.inputDocMaxChars for large full-mode inputs. mode: "summary" produces a real condense — the document is summarised to fit the cap (default 4,000 chars) by the platform LLM, preserving decision-relevant detail rather than just clipping more aggressively; if no LLM is configured it degrades to a clip. The panel shows, per input, whether a document was clipped or condensed. |
retrieval.inputDocMaxChars | Optional positive integer (max 200,000). Overrides the per-input-document cap for every input in this step — in full mode the verbatim clip ceiling, in summary mode the condense target. Omitted → the mode-derived default above. |
outputSurface | Optional. One selection or an array. Each selection's kind is the target action type the result lands on, plus per-surface config. kind: "workflow" writes the assessment onto the agent step itself AND as a clearance-capped page in the instance KB (contentType, pageTitle): a verdict-shaped reply ({verdict, confidence, rationale, …} JSON) renders the verdict layout; any other reply (prose, other JSON schemas) renders the agent's own text as the page body. kind: "approval" merges a one-line advisory onto the approval action of the task named by targetTaskSlug (advisorySource labels its provenance). Other action types are reserved for future surfaces. Surfaces are never implicit — an agent step without outputSurface writes no assessment page. |
mode: "summary" is lossy — do not use it for compliance-critical scoring.
This mode is optimised for readability and fitting the LLM's context window; it
does not guarantee a loss-free representation of every fact. For
compliance-critical tasks — strict RFP evaluation, legal or contractual scoring —
use mode: "full" together with the pull channel
(<start.processFlow.knowledgeBaseId> + the knowledge RAG tools), so that
decision-relevant criteria are never silently dropped by the condense.
Today workflow (assessment on the step) and approval (advisory on a target
approval action) are the implemented output surfaces. The retrieval spec
itself is generic and works for any agent-bearing workflow step that needs
grounding — @system/* built-ins receive the gathered context as their user
message automatically, while pack/canvas workflows must additionally reference
<start.processFlowContext> in a block to receive it (see
Receiving process-flow context
— without the reference the gathered context is dropped).
Task DAG validation
Tasks can declare:
dependsOnTaskSlugs— other tasks that must complete firstunlockAfterTaskSlug+unlockDelay— a soft gate that opens N days/weeks after a predecessor finishes
The inspect CLI runs DFS cycle detection (WHITE/GRAY/BLACK) and fails closed on any cycle. Stable error codes:
| Code | Meaning |
|---|---|
task_cycle | A dependency edge participates in a cycle |
unknown_dep_slug | dependsOnTaskSlugs references an unknown task slug |
stage_unknown | taskTemplates[].stageSlug doesn't match any stage |
Build, inspect, upload
bunx @scrydon/sdk-authoring pack validate src/pack.tsbunx @scrydon/sdk-authoring pack build src/pack.ts --outDir dist
# → dist/<package.id>-<package.version>.scrydon-pack.tar.gzbunx @scrydon/sdk-authoring pack inspect dist/acme-kickoff-1.0.0.scrydon-pack.tar.gzSign in as an org admin and open Settings → Packs in the platform app. Click Upload pack and drop your .scrydon-pack.tar.gz. When the pack ships a workflow, the dialog will ask you to pick a workspace environment — the workflow definitions install into that environment. Ontology and process-flow content install at the org level regardless.
The platform upload flow is the canonical entry point for all pack content kinds since ADR 2026-05-21 Unified pack upload surface.
After the pack is installed, a workspace admin opens Marketplace in the agentic sidebar and clicks Add on the Process Flow row to make it available in that environment. Once added, any workspace member can start a new Process Flow from it. See Marketplace.
For automation, the underlying agentic route still accepts uploads. Pass workspaceEnvironmentId only if the pack ships workflow content; otherwise it's optional.
curl -X POST "$AGENTIC_URL/api/packs/import?organizationId=$ORG_ID&workspaceEnvironmentId=$ENV_ID" \
-H "Cookie: $SESSION_COOKIE" \
-F "file=@dist/acme-kickoff-1.0.0.scrydon-pack.tar.gz"Bundle layout
<bundle>.scrydon-pack.tar.gz
├── pack.json # top-level pack manifest (PackBundleManifestSchema)
├── ontology/
│ └── manifest.json # OntologyManifestSchema — may be empty for flow-only packs
├── workflow-<slug>/ # optional — zero or more workflow subdirs
│ └── manifest.json # WorkflowManifestSchema
└── process-flow/
├── manifest.json # ProcessFlowManifestSchema
├── assets/ # optional — JSON / image assets referenced by the flow
│ ├── icon.svg
│ └── preview.png
└── meta/ # optional — non-functional metadata (e.g. sbom.cdx.json)Each subdir round-trips as a valid standalone artifact. Allowed asset extensions: .json, .svg, .png, .jpg, .jpeg, .gif, .md. Symlinks, hardlinks, absolute paths, and path traversal (..) are rejected by the inspector.
When a pack ships workflows, the importer runs them in their own phase before process-flow install — that way every workflowSlug on an action template resolves to a materialized workflowId before the process flow lands in the database. See Workflows for the slug-rebind contract.
Security caps
The runtime inspector reads the archive in streaming mode (tar.list parser-only — never extracts to disk) and enforces hard caps:
| Cap | Limit | Failure code |
|---|---|---|
| Compressed archive | 5 MB | archive_too_large |
| Total uncompressed | 10 MB | total_size_exceeded |
| Per-file size | 5 MB | file_too_large |
| File count | 200 | too_many_files |
| Symlink / hardlink | n/a | symlink_rejected |
| Absolute path | n/a | absolute_path_rejected |
| Path traversal | n/a | path_traversal_rejected |
| Disallowed top-level dir | n/a | disallowed_path |
| Disallowed extension | n/a | disallowed_extension |
The /import route returns 413 for size violations and 400 for structure or graph violations.
Why no executable code
process flows are declarative. Custom logic is referenced — by workflowId (a workflow already living in the tenant) or by workflowSlug (a workflow shipped alongside the template in the same Pack) — not bundled. Even when a Pack ships workflows in workflow-<slug>/ subdirs, the on-disk representation is pure JSON; the runtime block catalog lives in the platform. This keeps the surface deterministic, reproducible, and uploadable by non-engineering authors.
Where to next
Action Types
Per-type reference — one page per actionType with examples, metadata fields, and the runtime UX.
Marketplace
After installing a pack, workspace admins add Process Flows to an environment and deploy Workflows from the Marketplace.
Examples
Download ready-made process-flow archives — ISO Quarterly Review, ISO Yearly Review.
Ontologies
Process flows produce typed instances against the ontology — author the type system first.
Workflows
Ship actionType: workflow actions and the workflows they reference in the same Pack via workflowSlug.
Integrations
Workflows referenced by actionType: workflow are built from blocks — many of which come from integrations.