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 v0.8.0 is out! This release brings JavaScript interoperability - the most requested feature since the project’s inception. You c...
New
josevalim
Hi everyone, just a heads up that we announced https://livebook.dev, a website for everyone to learn more about Livebook. One of the coo...
New
DominikWolek
Last Friday we released Membrane Core 0.11.0 :tada: A pipeline’s lifecycle has changed: pipeline is now spawned with a dedicated supervi...
New
zachdaniel
Had a great time at Jax.Ex! Gave a talk called “Model your Domain, Derive the Rest”. Thanks to the folks at HashRocket for having me!
New
zachdaniel
Ash Framework 3.0: Release Candidates! The day is finally here! This is the culmination of years of work from the Ash team and community ...
New
zachdaniel
Hey folks! I’ve begun putting together some concrete, framework-wide tooling and guidance on the usage of LLMs in development. The goal h...
New
sorentwo
Oban.Web is a view of Oban’s inner workings that you host directly within your Phoenix application. Powered by Oban Metrics and Phoenix L...
New
zachdaniel
Ash and AshPostgres generators/installers, built with igniter are available on main! I’ll be very grateful to anyone willing to give the...
New
sorenone
Today we’re releasing Oban for Python. Not an Oban client in Python. Not a pythonx wrapper embedded in Elixir. Nope, it’s a fully operati...
New
polvalente
Nx, EXLA and Torchx 0.12 have just been published! This update set comes with the new Nx.block abstraction and the EXLA.CustomCall proto...
New

Other popular topics Top

aadeshere1
I have a another noob question about loop. Since elixir is immutable, while loop is not directly possible. total = 10 while total != 0 ...
New
9mm
I am constructing a JSON object (map) and I need to conditionally set a field. I’m trying to write proper elixir-way code… and I’m at a l...
New
sorentwo
Hello! tl;dr Announcing Oban, an Ecto based job processing library with a focus on reliability and historical observability. After spen...
985 43487 311
New
jononomo
I am trying to figure out how Mix knows whether the environment is test, dev, or prod – where is this set? Thanks.
New
josevalim
Hi everyone, One of the features added to Elixir early on to help integration with Erlang code was the idea of overridable function defi...
New
Lily
In templates/appointment/index.html.eex: <%= for appointment <- @appointments do %> <tr> <td><%= appoi...
New
jason.o
In the code below, if the create action is not set to accept “extra_key” as an input, it errors out with a message shown above. Is there ...
New
romenigld
I am trying to run a deploy with docker and I successfully runned with this command: docker build -t romenigld/blog-prod . but when I t...
New
jaysoifer
Is there a way to rollback a specific migration and only that one (“skipping” all the other ones)? Would mix ecto.rollback -v 200809061...
New
svb
Hi! Currently I want to submit a form by pressing the Enter key. However, since my input field is of type “textarea” this is just adds a...
New

Latest on Elixir Forum

Elixir Forum

We're in Beta

About us Mission Statement