webofbits

webofbits

Squidie - durable workflow runtime - 0.3.0 released

Squidie 0.3.0 is out.

Main announcement thread:

Hex: squidie | Hex
GitHub release: Release v0.3.0 · dark-trench/squidie · GitHub
Docs / Livebooks: squidie v0.3.1 — Documentation

Short naming note: Squidie was previously called Squid Mesh. The package, modules, docs, examples, and repository metadata now use the shorter Squidie name.

Squidie is an embedded durable workflow runtime for Elixir/Phoenix and OTP apps. It keeps workflow state in the host app, rather than running as a separate workflow service.

{:ok, run} =
Squidie.start(MyApp.Workflows.Checkout, :manual, %{order_id: “order_123”})

{:ok, _snapshot} =
Squidie.execute_next(owner_id: “checkout-worker-1”)

Current capability shape:

Authored / visual workflows

  • Runtime-authored workflow specs via start_spec/3 and start_spec/4
  • JSON-safe visual editor round trips with Squidie.Workflow.EditorSpec
  • Draft graph previews and editor diffing
  • Host-owned action and guardrail registries
  • UI-friendly run graph serialization
  • Dynamic work preview, record, and schedule APIs
:ok = Squidie.Workflow.EditorSpec.validate_map(editor_map,
  action_registry: registry
)

{:ok, graph} = Squidie.Workflow.EditorSpec.preview_graph(editor_map,
  action_registry: registry
)

Code DSL workflows

  • Spark-backed workflow DSL
  • Durable run history, attempts, retries, approvals (HITL), replay, cancellation, and inspection
  • Squidie.execute_next/1 execution boundary for host-owned workers
defmodule MiddleEarth.Workflows.RingErrand do
  use Squidie.Workflow

  workflow do
    trigger :leave_shire do
      manual()

      payload do
        field :bearer, :string, default: "Frodo"
        field :ring_id, :string
        field :route_preference, :string, default: "moria"
      end
    end

    step :pack_provisions, Hobbiton.Steps.PackProvisions,
      output: :provisions

    step :hide_at_prancing_pony, :pause

    approval_step :council_vote,
      output: :council,
      deadline: [within: 300_000, due_soon: 60_000, escalation: :operator_action]

    step :choose_path, Rivendell.Steps.ChoosePath,
      input: [bearer: [:bearer], decision: [:council, :decision]],
      output: :route

    step :cross_moria, Fellowship.Steps.CrossMoria,
      input: [:bearer, :provisions, :route],
      retry: [max_attempts: 3, backoff: [type: :exponential]],
      deadline: [within: 30_000, due_soon: 5_000, escalation: :diagnostic]

    step :reserve_eagle, Eagles.Steps.ReserveRide,
      compensate: Eagles.Steps.CancelRide

    step :toss_ring, Mordor.Steps.TossRing,
      irreversible: true

    transition :pack_provisions, on: :ok, to: :hide_at_prancing_pony
    transition :hide_at_prancing_pony, on: :ok, to: :council_vote
    transition :council_vote, on: :ok, to: :choose_path
    transition :choose_path, on: :ok, to: :cross_moria
    transition :cross_moria, on: :ok, to: :reserve_eagle
    transition :cross_moria, on: :error, to: :complete, recovery: :undo
    transition :reserve_eagle, on: :ok, to: :toss_ring
    transition :toss_ring, on: :ok, to: :complete
  end
end

Cron-triggered workflows use scheduling declarations:

defmodule Gondor.Workflows.BeaconWatch do
  use Squidie.Workflow

  workflow do
    trigger :nightly_beacon_check do
      cron "0 21 * * *", timezone: "Etc/UTC"

      payload do
        field :beacon_count, :integer, default: 7
      end
    end

    step :inspect_hilltops, Gondor.Steps.InspectHilltops,
      retry: [max_attempts: 3]

    step :light_beacon, Gondor.Steps.LightBeacon,
      compensate: Gondor.Steps.ExtinguishBeacon

    transition :inspect_hilltops, on: :ok, to: :light_beacon
    transition :light_beacon, on: :ok, to: :complete
  end
end


The runtime is executor-agnostic. A simple supervised worker loop can call Squidie.execute_next/1, or a host app can put a backend behind the delivery/lease boundary. Bedrock is a good fit when the app needs backend-owned delivery, delayed visibility, leases, heartbeats, retries, and dead-letter behavior.

Under the hood, Squidie uses a Jido journal runtime: actions, signals, agents, thread journals, checkpoints, storage, and supervised execution are used as runtime primitives, while Squidie exposes workflow-level APIs.

What is new in 0.3.0:

  • Projection-backed run timeline inspection

  • Runtime spec preview execution for visual editors and draft workflow validation

  • Guardrail validator registries for host-approved input, action, and output guardrails

  • Persisted completed guardrail decisions for inspection/explanations

  • Better validation for incompatible guardrail policy/placement combinations and malformed
    guardrail config

  • Structural quality gates in release and CI verification

There are Livebooks for the docs/getting-started path, including workflow creation, durable run execution, inspection, runtime-authored specs, and visual editor round trips.

There is also SquidSonar: GitHub - dark-trench/squid_sonar: Durable Workflow Dashboard · GitHub

SquidSonar is the optional read-only Phoenix LiveView dashboard for Squidie. It can be mounted inside a Phoenix host app to inspect recent runs, filter by status, search runtime metadata, and view run details with diagnosis, history counts, last error information, and workflow graph visualization.

There’s a short example workflow OTP that fetches Elixir CVEs every 15min and posts to a discord channel, for quick reference: GitHub - dark-trench/the-beacon: Plain OTP app for scheduled monitoring and notifications · GitHub

Where Next?

Popular in News & Updates Top

bartblast
Hologram UI is in the works - the official component library for Hologram - and the waiting list is now open. A common reaction when I m...
New
mobileoverlord
New versions of the Kiosk systems are out. These systems update official Nerves systems with a local web browser for rendering user inter...
New
zachdaniel
What if you had full stack types for SPAs built with tech like React, Inertia, Vue, Svelte… but all of the power Ash Framework and Elixir...
New
zachdaniel
Hey everyone! What I’ll cover in this post: Major refactors The future of Ash.Flow Current state of atomics and bulk actions Whats nex...
New
hugobarauna
Welcome to the second day of Livebook Launch Week! :tada: Today we will discuss all the new Machine Learning capabilities in Elixir and ...
New
josevalim
Hi everyone, We have just released Mime v2.0.4 with a potential security fix. Before this version, Mime.extensions("foo/bar+baz") would ...
New
fhunleth
The Nerves core team is proud to announce the Nerves v1.8.0 release. Nerves provides the core tooling for creating self-contained, BEAM-...
New
bartblast
Hey there! :slight_smile: We need help completing Elixir’s browser runtime by porting some Erlang functions to JavaScript. Hologram aut...
New
jjcarstens
Testing code destined for hardware can be tricky, but it just got one tiny bit easier! :tty0tty was just released which is an Elixir por...
New
jjcarstens
Hey friends! :waving_hand: With NervesConf 2024 around the corner, Frank, myself, and the greater Nerves team wanted to share a survey w...
New

Other popular topics Top

TunkShif
This post is an instruction guide to help you setup your Neovim for Elixir development from scratch. It includes general information on h...
274 41539 114
New
alice
Hey, Just curious what are the main benefits of Elixir compared to Clojure? When is Elixir more useful than Clojure and vice versa? Th...
New
belgoros
I’m not a pro in using Regex and can’t figure out why the following behaviour happens, especially if we take into account the difference ...
New
grych
Hi folks, Few months ago I have announced the proof-of-concept of the library to manipulate the browsers DOM objects directly from Elixi...
639 52341 488
New
RisingFromAshes
I’ve read in another post that it may be possible with a router helper - but I couldn’t find an appropriate one, and tbh, I’m still just ...
New
Qqwy
Original source of discussion: This topic on the Pragmatic Programmers’ Functional Web Development with Elixir, OTP, and Phoenix forum. ...
New
joaquinalcerro
Hi there, I am working with Ecto-Postgresql and I need to call all of the records from a specific table but the table has 40,000 records...
New
Qqwy
Update: How to use the Blogs & Podcasts section You can post links to your blog posts or podcasts either in one of the Official Blog...
3271 126479 1222
New
jononomo
For some reason my phoenix channels are working for me in my local dev environment, but as soon as I deploy via Docker, I get a 403 error...
New
lanycrost
Hi everyone! I need implement if…else if…else condition from my elixir code, and anymore of this control flow structures not work proper...
New

Latest on Elixir Forum

We're in Beta

About us Mission Statement