Quick Reference

Contents

  1. Mycelium Quick Reference
  2. Core API
  3. Compilation Options
  4. Accumulating Data Model
  5. Cell Registration
  6. Cell Registry Helpers
  7. Workflow Definition
  8. Pipeline Shorthand
  9. Branching
  10. Default Transitions
  11. Graph-Level Timeouts
  12. Error Groups
  13. Join Nodes (Fork-Join)
  14. Key Concepts
  15. Join Options
  16. Output Key Conflicts
  17. Join Error Handling
  18. Join Trace
  19. Interceptors
  20. Parameterized Cells
  21. Resilience Policies
  22. Manifest Loading
  23. Manifest Cell Fields
  24. Manifest Validation
  25. Fragment API
  26. Subworkflows (Nested Composition)
  27. Output Schema Formats
  28. Constraints
  29. Compile-Time Validation
  30. Edge Targets
  31. Ring Middleware
  32. Dev Tools
  33. Agent Orchestration
  34. Regions
  35. Workflow Trace
  36. Asserting on Traces
  37. System Queries
  38. Halt & Resume (Human-in-the-Loop)
  39. Halting
  40. Resuming
  41. Key Behaviors
  42. Persistent Store
  43. Workflow Result Keys

Mycelium Quick Reference

Core API

(require '[mycelium.core :as myc])

;; Pre-compile once at startup (recommended for production)
(def compiled (myc/pre-compile workflow-def opts))

;; Run a pre-compiled workflow (zero compilation overhead)
(myc/run-compiled compiled resources initial-data)
(myc/run-compiled-async compiled resources initial-data)  ;; returns a future

;; Convenience: compile + run in one step (re-compiles every call)
(myc/run-workflow workflow-def resources initial-data)
(myc/run-workflow workflow-def resources initial-data opts)

;; Async convenience (returns a future)
(myc/run-workflow-async workflow-def resources initial-data)

;; Resume a halted workflow (human-in-the-loop)
(myc/resume-compiled compiled resources halted-result)
(myc/resume-compiled compiled resources halted-result {:human-input "value"})

;; Compile a system (all workflows)
(myc/compile-system {"/route" manifest, ...})

Compilation Options

pre-compile and run-workflow accept an opts map:

{:pre      (fn [fsm-state resources] fsm-state)  ;; pre-interceptor for every state
 :post     (fn [fsm-state resources] fsm-state)  ;; post-interceptor for every state
 :on-error (fn [resources fsm-state] data)        ;; runs when FSM enters error state
 :on-end   (fn [resources fsm-state] data)}       ;; runs when FSM enters end state

Accumulating Data Model

Cells communicate through an accumulating data map. Every cell receives the full map of all keys produced by every prior cell in the path. Cells assoc their outputs and the enriched map flows forward.

start → validate → fetch-profile → fetch-orders → render
         adds :user-id  adds :profile   adds :orders   needs :profile AND :orders

A cell can depend on data produced several steps earlier without special wiring — keys persist through intermediate cells. The schema chain validator walks each path and confirms required keys are available from upstream outputs.

Cell Registration

(require '[mycelium.cell :as cell])

(defmethod cell/cell-spec :namespace/cell-id [_]
  {:id       :namespace/cell-id
   :handler  (fn [resources data] (assoc data :result "value"))
   :schema   {:input  [:map [:key :type]]
              :output [:map [:result :string]]}
   :requires [:db]         ;; optional — resource dependencies
   :async?   true          ;; optional — async handler signature
   :doc      "..."})       ;; optional

;; Async handler signature (4-arity with callbacks):
;; (fn [resources data callback error-callback] ...)

Cell Registry Helpers

(cell/list-cells)                     ;; => (:ns/a :ns/b ...) — all registered IDs
(cell/get-cell :ns/id)                ;; => spec map or nil
(cell/get-cell! :ns/id)               ;; => spec map or throws
(cell/set-cell-schema! :ns/id schema) ;; overwrite schema on registered cell
(cell/clear-registry!)                ;; remove all cells (testing only)

Workflow Definition

{:cells       {:start :cell/id, :step2 :cell/id2}    ;; or {:id :cell/id :params {...}}
 :edges       {:start {:label :step2}, :step2 {:done :end}}
 :dispatches  {:start [[:label (fn [data] (:key data))]]
               :step2 [[:done (constantly true)]]}
 :joins       {:join-name {:cells [:a :b] :strategy :parallel}}  ;; optional
 :input-schema [:map [:key :type]]                                ;; optional
 :interceptors [{:id :x :scope :all :pre (fn [d] d)}]            ;; optional
 :resilience  {:start {:timeout {:timeout-ms 5000}}}              ;; optional
}

Pipeline Shorthand

;; Instead of :edges + :dispatches for linear flows:
{:pipeline [:start :process :render]
 :cells    {:start :cell/a, :process :cell/b, :render :cell/c}}
;; Expands to :edges {:start :process, :process :render, :render :end}
;; Mutually exclusive with :edges, :dispatches, :fragments, :joins

Branching

Edges map transition labels to targets. Dispatch predicates examine data to pick the edge:

{:cells {:start :check/threshold
         :big   :process/big-values
         :small :process/small-values}
 :edges {:start {:high :big, :low :small}
         :big   {:done :end}
         :small {:done :end}}
 :dispatches {:start [[:high (fn [data] (> (:value data) 10))]
                      [:low  (fn [data] (<= (:value data) 10))]]
              :big   [[:done (constantly true)]]
              :small [[:done (constantly true)]]}}

Handlers compute data; dispatch predicates decide the route.

Default Transitions

Use :default as an edge label for a catch-all fallback when no other dispatch predicate matches:

{:cells {:start :check/validate, :ok :process/run, :err :process/error}
 :edges {:start {:success :ok, :default :err}
         :ok :end, :err :end}
 :dispatches {:start [[:success (fn [d] (:valid d))]]}}
;; :default auto-generates (constantly true) as the last predicate
;; No need to add [:default ...] to :dispatches
  • :default must not be the only edge (use an unconditional keyword edge instead)
  • You can provide an explicit :default predicate in :dispatches to override the auto-generated one
  • :default is always evaluated last, even if listed first in :dispatches
  • Works with join nodes — add :default alongside :done/:failure edges
  • Trace entries record :default as the transition label

Graph-Level Timeouts

Move timeout logic from handlers to the workflow definition. When a cell exceeds its timeout, the framework injects :mycelium/timeout true into data and routes to the :timeout edge target:

{:cells {:fetch-tags :mp3/parse-id3
         :render     :ui/render-tags
         :fallback   :ui/show-error}
 :edges {:fetch-tags {:done :render, :timeout :fallback}
         :render     :end
         :fallback   :end}
 :dispatches {:fetch-tags [[:done (fn [d] (not (:mycelium/timeout d)))]]}
 :timeouts {:fetch-tags 5000}}  ;; ms
  • Timeout values must be positive integers (milliseconds)
  • Cells with timeouts must have a :timeout edge target
  • A :timeout dispatch predicate is auto-injected and evaluated first (before user predicates)
  • Works with both sync and async cells (async cells become blocking with timeout)
  • Output schema validation is skipped for timed-out cells (handler didn't produce normal output)
  • Trace entries include :timeout? true when a cell times out
  • Distinct from resilience :timeout policies — graph timeouts route, resilience timeouts error

Error Groups

Declare shared error handling for sets of cells. If any cell in the group throws, the framework catches the exception, injects :mycelium/error into data, and routes to the group's error handler:

{:cells {:fetch     :data/fetch
         :transform :data/transform
         :err       :data/handle-error}
 :edges {:fetch     :transform
         :transform :end
         :err       :end}
 :error-groups {:pipeline {:cells [:fetch :transform]
                            :on-error :err}}}
  • At compile time, unconditional edges are expanded to map edges with :on-error target
  • :on-error dispatch predicate is auto-injected and evaluated first
  • :mycelium/error contains {:cell :cell-name, :message "..."} — available to the error handler
  • Output schema validation is skipped for errored cells
  • Error handler cells can dissoc :mycelium/error to clean up
  • Grouped cells must exist, error handler must exist, no cell in multiple groups

Join Nodes (Fork-Join)

When multiple independent cells can run concurrently, declare a join node:

{:cells {:start          :auth/validate-session
         :fetch-profile  :user/fetch-profile     ;; join member
         :fetch-orders   :user/fetch-orders      ;; join member
         :render-summary :ui/render-summary
         :render-error   :ui/render-error}

 :joins {:fetch-data {:cells    [:fetch-profile :fetch-orders]
                      :strategy :parallel}}

 :edges {:start          {:authorized :fetch-data, :unauthorized :render-error}
         :fetch-data     {:done :render-summary, :failure :render-error}
         :render-summary {:done :end}
         :render-error   {:done :end}}

 :dispatches {:start [[:authorized   (fn [d] (:session-valid d))]
                       [:unauthorized (fn [d] (not (:session-valid d)))]]
              :render-summary [[:done (constantly true)]]
              :render-error   [[:done (constantly true)]]}}

Key Concepts

  • Join members (:fetch-profile, :fetch-orders) exist in :cells but have no entries in :edges — the join consumes them
  • The join name (:fetch-data) appears in :edges like a regular cell
  • Each member receives the same input snapshot — branches cannot see each other's outputs
  • After all branches complete, results are merged into the data map
  • Default dispatches :done / :failure are provided based on whether any branch threw an exception

Join Options

OptionDefaultDescription
:cells(required)Vector of cell names to run
:strategy:parallel:parallel or :sequential
:merge-fnnil(fn [data results-vec]) — custom merge when output keys overlap
:timeout-ms30000Timeout for async cells within the join

Output Key Conflicts

At compile time, output keys from all join members are checked for overlap:

  • No :merge-fn — compile-time error listing conflicting keys
  • :merge-fn provided — user handles conflict resolution
    ;; Both cells produce :items — requires :merge-fn
    :joins {:gather {:cells    [:source-a :source-b]
                     :merge-fn (fn [data results]
                                 (assoc data :items
                                        (vec (mapcat :items results))))}}
    

Join Error Handling

All branches run to completion (no early cancellation). Errors are collected in :mycelium/join-error. The join's default dispatches route to :failure when errors are present:

:edges {:fetch-data {:done :render-summary, :failure :render-error}}

Join Trace

Each join produces a trace entry with per-member timing:

{:cell :fetch-data
 :cell-id :mycelium.join/fetch-data
 :transition :done
 :join-traces [{:cell :fetch-profile, :cell-id :user/fetch-profile,
                :duration-ms 12.3, :status :ok}
               {:cell :fetch-orders, :cell-id :user/fetch-orders,
                :duration-ms 8.7, :status :ok}]}

Interceptors

Workflow-level interceptors wrap cell handlers at compile time:

:interceptors [{:id    :log-timing
                :scope :all                              ;; every cell
                :pre   (fn [data] (assoc data ::t0 (System/nanoTime)))
                :post  (fn [data] (dissoc data ::t0))}

               {:id    :ui-only
                :scope {:id-match "ui/*"}                ;; glob on cell :id
                :pre   (fn [data] data)}

               {:id    :targeted
                :scope {:cells [:render :fetch]}         ;; explicit cell names
                :post  (fn [data] data)}]

Scope forms:

ScopeMatches
:allEvery cell
{:id-match "ui/*"}Cell registry :id matching glob (e.g. :ui/render-dashboard)
{:cells [:x :y]}Specific workflow cell names

Interceptor :pre/:post receive and return the data map (not fsm-state).

Parameterized Cells

Reuse the same handler with different config by passing a map instead of a bare keyword:

{:cells {:triple {:id :math/multiply :params {:factor 3}}
         :double {:id :math/multiply :params {:factor 2}}}
 :pipeline [:triple :double]}

Params are injected as :mycelium/params in the data map and cleaned up after each step. Access via (get-in data [:mycelium/params :factor]).

Resilience Policies

Wrap cells with resilience4j policies via :resilience:

{:cells {:start :api/call, :fallback :ui/error}
 :edges {:start {:done :end, :failed :fallback}, :fallback :end}
 :dispatches {:start [[:failed (fn [d] (some? (:mycelium/resilience-error d)))]
                       [:done   (fn [d] (nil? (:mycelium/resilience-error d)))]]}
 :resilience {:start {:timeout        {:timeout-ms 5000}
                       :retry          {:max-attempts 3 :wait-ms 200}
                       :circuit-breaker {:failure-rate 50 :minimum-calls 10
                                         :sliding-window-size 100 :wait-in-open-ms 60000}
                       :bulkhead       {:max-concurrent 25 :max-wait-ms 0}
                       :rate-limiter   {:limit-for-period 50
                                        :limit-refresh-period-ms 500 :timeout-ms 5000}
                       :async-timeout-ms 30000}}}

When triggered, handler returns data with :mycelium/resilience-error (map with :type, :cell, :message). Error types: :timeout, :circuit-open, :bulkhead-full, :rate-limited, :unknown.

Stateful policies (circuit breaker, rate limiter) require pre-compile + run-compiled to share state across calls.

:async-timeout-ms controls how long the resilience wrapper waits for an async handler's promise (default 30s). Independent of the resilience4j :timeout policy.

Manifest Loading

(require '[mycelium.manifest :as manifest])

(def m (manifest/load-manifest "path/to/file.edn"))
(def wf (manifest/manifest->workflow m))
(manifest/cell-brief m :cell-name)  ;; LLM-friendly prompt

Manifest Cell Fields

{:id       :namespace/name    ;; cell registry ID
 :schema   {:input  [...]     ;; Malli schema
            :output [...]}    ;; single or per-transition
 :doc      "..."              ;; optional description
 :requires [:db]              ;; optional resource dependencies
 :on-error :cell-name}        ;; or nil — required in strict mode (default)

Use :schema :inherit to resolve schema from the cell registry (avoids duplicating schemas in manifest):

{:id :user/fetch-profile
 :schema :inherit             ;; pulls :input/:output from cell/cell-spec
 :on-error :error-handler}

Manifest Validation

(manifest/validate-manifest manifest)                ;; strict mode (default)
(manifest/validate-manifest manifest {:strict? false}) ;; skip :on-error requirement

Fragment API

(require '[mycelium.fragment :as fragment])

(fragment/load-fragment "fragments/auth.edn")              ;; load from classpath
(fragment/validate-fragment fragment-data)                  ;; validate structure
(fragment/expand-fragment frag mapping host-cells)          ;; expand one
(fragment/expand-all-fragments manifest)                    ;; expand all

Manifest fragment references support classpath refs or inline data:

:fragments
  {:auth {:ref "fragments/auth.edn"             ;; loaded from classpath
          :as :start
          :exits {:success :dashboard, :failure :login-error}}
   :log  {:fragment {...inline fragment data...} ;; inline definition
          :as :start
          :exits {:success :next-step}}}

Subworkflows (Nested Composition)

Wrap a workflow as a single opaque cell. See subworkflows.md.

(require '[mycelium.compose :as compose])

;; Register a workflow as a reusable cell
(compose/register-workflow-cell!
  :payment/flow
  {:cells {...} :edges {...} :dispatches {...}}
  {:input [:map ...] :output [:map ...]})

;; Or create spec without registering
(compose/workflow->cell :payment/flow workflow-def schema)

Default dispatches :success / :failure are provided automatically based on :mycelium/error.

Output schema is inferred automatically by walking child workflow edges to :end and collecting output keys. Pass an explicit :output schema to override.

Output Schema Formats

;; Single (all transitions)
:output [:map [:result :int]]

;; Per-transition
:output {:success [:map [:data :string]]
         :failure [:map [:error :string]]}

Per-transition schemas are validated based on which dispatch matched. The schema chain validator tracks available keys independently per path.

Constraints

Declare compile-time path invariants that are checked against all enumerated paths:

{:constraints [{:type :must-follow,      :if :flag-missing, :then :apply-tags}
               {:type :must-precede,     :cell :validate,   :before :process}
               {:type :never-together,   :cells [:manual-review :auto-approve]}
               {:type :always-reachable, :cell :audit-log}]}
TypeMeaning
:must-followIf :if cell appears on a path, :then cell must appear later on that path
:must-precede:cell must appear before :before on every path containing :before
:never-togetherAll listed :cells must never appear on the same path
:always-reachable:cell must appear on every path that reaches :end (ignores :error/:halt paths)
  • Constraints reference workflow cell names (including join names), not join member cells or cell registry IDs
  • :always-reachable passes vacuously if no paths reach :end (all paths go to :error/:halt)
  • Violations throw at compile time with the specific path that violates the constraint

Compile-Time Validation

compile-workflow validates before any code runs:

  • Cell existence — all referenced cells must be registered
  • Edge targets — must point to valid cells, join names, or :end/:error/:halt
  • Reachability — every cell and join must be reachable from :start
  • Dispatch coverage — every edge label must have a dispatch predicate, and vice versa
  • Schema chain — each cell's input keys must be available from upstream outputs (join-aware)
  • Constraints — path invariants checked against all enumerated paths (see Constraints)
  • Graph timeouts — timeout cells exist, values are positive integers, cells have :timeout edge
  • Error groups — grouped cells exist, error handler exists, no cell in multiple groups
  • Resilience validation — policy keys valid, referenced cells exist, timeout-ms positive
  • Join validation — member cells exist, no name collisions, members have no edges, output keys disjoint (or :merge-fn provided)

Edge Targets

TargetMeaning
:cell-nameNext cell in workflow
:join-nameEnter a join node
:endWorkflow completes successfully
:errorWorkflow terminates with error
:haltWorkflow halts
:_exit/nameFragment exit reference (resolved during expansion)

Ring Middleware

(require '[mycelium.middleware :as mw])

;; Create a Ring handler from a pre-compiled workflow
(mw/workflow-handler compiled {:resources {:db db}})

;; With custom input/output transforms
(mw/workflow-handler compiled
  {:resources {:db db}
   :input-fn  (fn [req] {:http-request req})   ;; default
   :output-fn mw/html-response})               ;; default

;; :resources can be a function for per-request construction
(mw/workflow-handler compiled
  {:resources (fn [req] {:db db :request req})})

;; Standard HTML response helper
(mw/html-response result)  ;; => {:status 200 :body (:html result) ...}

Dev Tools

(require '[mycelium.dev :as dev])

;; Test a cell in isolation
(dev/test-cell :cell/id {:input {:key "val"} :resources {:db db}})
;; => {:pass? true, :output {...}, :errors [], :duration-ms 0.42}

;; Test with dispatch verification
(dev/test-cell :cell/id
  {:input      {:key "val"}
   :dispatches [[:success (fn [d] (:result d))]
                [:failure (fn [d] (:error d))]]
   :expected-dispatch :success})
;; => {:pass? true, :matched-dispatch :success, :output {...}, ...}

;; Test multiple transitions
(dev/test-transitions :cell/id
  {:found     {:input {:id "alice"} :resources {:db db}
               :dispatches [[:found (fn [d] (:profile d))]
                            [:not-found (fn [d] (:error d))]]}
   :not-found {:input {:id "nobody"} :resources {:db db}
               :dispatches [[:found (fn [d] (:profile d))]
                            [:not-found (fn [d] (:error d))]]}})

;; Enumerate all paths from :start to terminal states
(dev/enumerate-paths workflow-def)

;; Generate DOT graph for visualization
(dev/workflow->dot workflow-def)

;; Check cell implementation status
(dev/workflow-status manifest)
;; => {:total 4, :passing 2, :failing 1, :pending 1, :cells [...]}

;; Static analysis — reachability, unreachable states, cycles
(dev/analyze-workflow workflow-def)
;; => {:reachable #{:start :step2} :unreachable #{} :no-path-to-end #{} :cycles []}

;; Infer accumulated schema at each cell
(dev/infer-workflow-schema workflow-def)
;; => {:start  {:available-before #{:x}, :adds #{:result}, :available-after #{:x :result}}
;;     :step2  {:available-before #{:x :result}, :adds #{:total}, ...}}

analyze-workflow and infer-workflow-schema are also available as myc/analyze-workflow and myc/infer-workflow-schema.

Agent Orchestration

(require '[mycelium.orchestrate :as orch])

;; Generate briefs for all cells (for parallel agent assignment)
(orch/cell-briefs manifest)
;; => {:start {:id :auth/parse, :prompt "## Cell: ...", ...}, ...}

;; Generate a targeted brief after a cell implementation fails
(orch/reassignment-brief manifest :validate
  {:error "Output missing key :session-valid"
   :input {:user-id "alice" :auth-token "tok_abc"}
   :output {:session-valid nil}})

;; Build plan — which cells can be implemented in parallel
(orch/plan manifest)
;; => {:scaffold [:start :validate ...], :parallel [[...]], :sequential []}

;; Progress report
(println (orch/progress manifest))

;; Region brief — scoped context for a subgraph cluster
(orch/region-brief manifest :auth)
;; => {:cells [{:name :start, :id :auth/parse, :schema {...}}, ...]
;;     :internal-edges {:start {:ok :validate-session}}
;;     :entry-points [:start]
;;     :exit-points [{:cell :validate-session, :transitions {:authorized :fetch-profile}}]
;;     :prompt "## Region: auth\n..."}

Regions

Group cells into named regions in the manifest for LLM context scoping:

{:cells {:start :auth/parse, :validate :auth/validate, :fetch :user/fetch, :render :ui/render}
 :regions {:auth       [:start :validate]
           :data-fetch [:fetch]}}
  • Region cells must exist in :cells
  • No cell may appear in multiple regions
  • region-brief returns cell schemas, internal edges, entry/exit points, and a prompt
  • Exit point :transitions is always a map — unconditional edges use {:unconditional :target}
  • Regions are purely informational — no runtime behavior change

Workflow Trace

Every run produces :mycelium/trace — a vector of step-by-step execution records:

;; Each trace entry:
{:cell        :fetch-user       ;; workflow cell name
 :cell-id     :user/fetch       ;; registry cell ID
 :transition  :success          ;; dispatch label taken (nil for unconditional)
 :data        {...}             ;; data snapshot after handler ran
 :duration-ms 12.4              ;; execution time
 :error       {...}             ;; schema error details (only on validation failure)
 :join-traces [{...}]}          ;; per-member timing (only for join nodes)

Asserting on Traces

(let [result (myc/run-workflow wf {} {:x 5})
      trace  (:mycelium/trace result)]
  (is (= [:start :add] (mapv :cell trace)))
  (is (= [:done :done] (mapv :transition trace)))
  (is (= 20 (get-in (last trace) [:data :result]))))

System Queries

(require '[mycelium.system :as sys])

(sys/cell-usage system :cell/id)        ;; => ["/route1" "/route2"]
(sys/route-cells system "/route")       ;; => #{:cell/a :cell/b}
(sys/route-resources system "/route")   ;; => #{:db}
(sys/schema-conflicts system)           ;; => [{:cell-id ... :routes ...}]
(sys/system->dot system)                ;; => DOT graph string

Halt & Resume (Human-in-the-Loop)

A cell can pause the workflow by returning :mycelium/halt in its data. The workflow halts after that cell, preserving all accumulated data and trace. A human (or external process) can later resume the workflow from where it stopped.

Halting

;; Cell signals halt by assoc'ing :mycelium/halt into data
(defmethod cell/cell-spec :review/check [_]
  {:id      :review/check
   :handler (fn [_ data]
              (assoc data :mycelium/halt {:reason :needs-approval
                                          :item   (:item-id data)}))
   :schema  {:input [:map [:item-id :string]] :output [:map]}})

:mycelium/halt can be true or a map with context for the human reviewer.

Resuming

(let [compiled (myc/pre-compile workflow-def)
      halted   (myc/run-compiled compiled resources {:item-id "X"})
      ;; halted contains :mycelium/halt and :mycelium/resume
      ;; Inspect halted, get human input, then resume:
      result   (myc/resume-compiled compiled resources halted {:approved true})]
  ;; result has data from before + after halt, :mycelium/halt cleared
  (:approved result)) ;; => true

resume-compiled takes an optional merge-data map (4th arg) that is merged into the data before resuming — useful for injecting human-provided input.

Key Behaviors

  • Data accumulates — all keys from before the halt are available after resume
  • Trace is continuous:mycelium/trace spans the full execution (before + after halt)
  • Multiple halts — a workflow can halt and resume multiple times
  • Branching — if a halting cell dispatches to a branch, resume continues on the correct branch
  • Halt trace entry — the trace entry for the halting cell has :halted true
  • Resume validation — calling resume-compiled on a non-halted result throws an exception

Persistent Store

For workflows that halt across process restarts or sessions, use the WorkflowStore protocol to persist and retrieve halted state:

(require '[mycelium.store :as store])

;; In-memory store (dev/testing)
(def s (store/memory-store))

;; Run — auto-persists on halt, returns {:mycelium/session-id id, :mycelium/halt context}
(def halted (store/run-with-store compiled resources initial-data s))

;; Resume by session ID — loads from store, resumes, cleans up on completion
(def result (store/resume-with-store compiled resources (:mycelium/session-id halted) s))

;; Resume with human input
(store/resume-with-store compiled resources session-id s {:approved true})

Implement the protocol for your persistence backend (DB, Redis, etc.):

(defrecord MyStore [conn]
  store/WorkflowStore
  (save-workflow! [_ session-id data] ...)
  (load-workflow [_ session-id] ...)
  (delete-workflow! [_ session-id] ...)
  (list-workflows [_] ...))
  • On halt: state persisted, :mycelium/session-id returned (:mycelium/resume hidden from caller)
  • On resume completion: state deleted from store automatically
  • On re-halt: store updated with new state, same session ID reused
  • Custom session IDs: (store/run-with-store compiled res data s {:session-id "my-id"})

Workflow Result Keys

KeyDescription
:mycelium/traceVector of execution trace entries (see Workflow Trace)
:mycelium/input-errorInput schema validation failure (workflow didn't run)
:mycelium/schema-errorRuntime schema violation details
:mycelium/join-errorJoin node error details
:mycelium/timeouttrue when a cell exceeded its graph-level timeout
:mycelium/errorError group error details ({:cell :name, :message "..."})
:mycelium/resilience-errorResilience policy trigger details (:type, :cell, :message)
:mycelium/child-traceNested workflow trace (composed cells)
:mycelium/haltHalt context (true or map) — present when workflow is halted
:mycelium/resumeResume state token — present when workflow is halted
:mycelium/session-idStore session ID — present when using run-with-store/resume-with-store on halt