Samsarix Orchestration

August 11, 2026 · View on GitHub

Samsarix Orchestration is a local-first Python library and CLI for defining, validating, planning, and running small dependency-aware workflows. Application code registers ordinary sync or async Python callables as actions; Samsarix supplies graph validation, bounded concurrency, per-step timeouts and retries, failure propagation, and a JSON run report. Schema-v3 workflows can also reverse completed external effects with durable compensating actions after a later failure or approval rejection. Trusted local tools can run through a bounded subprocess JSON protocol when thread cancellation is not strong enough.

It is for Python developers who want a transparent provider-neutral orchestration primitive before adopting a distributed or hosted workflow system. It does not include an LLM provider, execute model-generated code, expose a server, or require private infrastructure.

Status: 0.1 alpha / local release candidate. The implemented CLI and Python journey are tested, including from an exact-pin external package consumer. The distribution has not yet been published to a package index. The protected, provenance-attested publication process is documented in release operations.

What works

  • Versioned JSON workflow definitions with actionable validation errors.
  • Directed acyclic dependency graphs with up to 256 steps.
  • Explicit sync or async Python action registration.
  • Concurrent execution bounded to 1–64 in-flight actions per workflow.
  • Per-step timeouts, 0–10 retries, bounded retry delays, and fail-fast behavior.
  • Opt-in atomic JSON or transactional SQLite checkpoints that resume without repeating verified successful steps.
  • Stable per-step idempotency keys for safely designed external side effects.
  • Ordered, schema-versioned lifecycle events for application-owned logs and metrics.
  • Schema-v2 pre-action approval gates with durable approve/reject decisions and a strict no-handler-before-approval barrier.
  • Schema-v3 orchestrated Saga compensation with reverse dependency ordering, independent retry policies, interruption-safe checkpoints, and stable compensation idempotency keys.
  • Side-effect-free dependency plans and offline Mermaid graph export for preflight review.
  • Shell-free subprocess actions with absolute executables, bounded JSON input/output, explicit environment inheritance, and terminate-then-kill cancellation.
  • A separately installed consumer proving resume, idempotency, and event contracts across a real package boundary.
  • JSON-safe inputs, outputs, errors, and terminal step states.
  • Provider-free CLI examples for successful, approval-gated, and compensating workflows.
  • No runtime dependencies, network calls, telemetry, credentials, or implicit persistence.

Distributed workers, sandboxing, dynamic mid-handler interrupts, provider adapters, and a remote API are deliberately out of scope for 0.1. Subprocess actions isolate lifecycle and memory, but remain trusted local programs with the invoking user's operating-system access.

Fastest successful path

Prerequisites: Git and Python 3.11 or newer.

git clone https://github.com/Deathcharge/samsarix-agent-orchestration.git
cd samsarix-agent-orchestration
python -m venv .venv
python -m pip install .
samsarix-orchestration init workflow.json
samsarix-orchestration validate workflow.json
samsarix-orchestration plan workflow.json
samsarix-orchestration run workflow.json --output run.json

The final command exits with 0 and prints a JSON report whose workflow status is succeeded. It also writes the same report to run.json. Existing workflow and report files are never replaced unless --force or --force-output is explicit.

You can use python -m samsarix_orchestration instead of the installed command.

CLI

samsarix-orchestration --version
samsarix-orchestration actions
samsarix-orchestration init PATH [--force] [--approval | --saga]
samsarix-orchestration validate PATH [--json]
samsarix-orchestration plan PATH [--format text|json|mermaid]
samsarix-orchestration run PATH [--input JSON | --input-file PATH]
                                 [--output PATH] [--force-output]
                                 [--checkpoint-dir PATH | --checkpoint-db PATH]
                                 [--run-id ID] [--resume]
                                 [--approve REQUEST_ID] [--reject REQUEST_ID]
                                 [--decided-by LABEL] [--decision-reason TEXT]
                                 [--events]
samsarix-orchestration runs list DATABASE [--limit N] [--json]
samsarix-orchestration runs show DATABASE RUN_ID [--include-outputs]
samsarix-orchestration runs delete DATABASE RUN_ID --confirm RUN_ID

Exit codes are stable:

  • 0: validation or execution succeeded;
  • 1: workflow execution failed;
  • 2: usage, workflow, input, or output validation failed;
  • 3: execution paused before a gated action and awaits an approval decision;
  • 4: an operator rejected an approval request;
  • 130: the user interrupted execution.

Workflow and input files are limited to 1 MiB. Each step result is also limited to 1 MiB by default. See the workflow format for the complete schema and the architecture for execution semantics.

Inspect before execution

Build a static plan without loading handlers, running actions, reading workflow input, or making a network request:

samsarix-orchestration plan workflow.json
samsarix-orchestration plan workflow.json --format json
samsarix-orchestration plan workflow.json --format mermaid > workflow.mmd

The plan preserves workflow order for its step inventory while deriving deterministic dependency waves, roots, leaves, dependants, the longest dependency chain, maximum wave width, retry-attempt ceilings, the canonical workflow digest, approval-barrier locations, and compensating-action inventory. A wave marked as an approval barrier reflects the runtime's global rule: none of that dependency-ready group starts while a request remains pending. Mermaid output uses internal node IDs and omits approval prompts; it is source text only, so rendering remains an explicit caller choice. Python callers use build_workflow_plan(definition) and then to_dict(), to_text(), or to_mermaid().

--events writes one compact, privacy-minimized JSON event per line to stderr while the final run report remains on stdout. This makes CLI progress consumable without parsing human text or mixing it with the terminal report.

Python API

import asyncio

from samsarix_orchestration import ActionContext, WorkflowDefinition, WorkflowRunner


async def fetch(_context: ActionContext) -> dict[str, list[int]]:
    return {"values": [2, 3, 5]}


def total(context: ActionContext) -> int:
    return sum(context.dependencies["fetch"]["values"])


async def main() -> None:
    definition = WorkflowDefinition.from_dict(
        {
            "version": 1,
            "name": "sum-values",
            "steps": [
                {"id": "fetch", "agent": "source", "action": "fetch"},
                {
                    "id": "total",
                    "agent": "calculator",
                    "action": "total",
                    "dependencies": ["fetch"],
                },
            ],
        }
    )
    result = await WorkflowRunner({"fetch": fetch, "total": total}).run(definition)
    print(result.to_dict())


asyncio.run(main())

The same runnable example is in examples/python_workflow.py. An action receives an ActionContext containing the workflow input, its validated step definition, dependency outputs, workflow name, and current attempt number. Handlers run with the privileges of the Python process; only register trusted code.

Run blocking tools in bounded subprocesses

Use subprocess_action when a trusted command-line tool, legacy program, or blocking Python worker needs an operating-system process boundary:

import sys
from pathlib import Path

from samsarix_orchestration import WorkflowRunner, subprocess_action

worker = subprocess_action(
    (sys.executable, "-I", str(Path("worker.py").resolve())),
    environment={"APPLICATION_MODE": "production"},
)
runner = WorkflowRunner({"external-tool": worker})

The executable path must be absolute and is invoked directly—never through a shell. For each attempt the child reads one UTF-8 JSON envelope from stdin and writes exactly one finite JSON value to stdout. The version-1 envelope includes workflow/run/step identity, parameters, input, dependency outputs, attempt, and idempotency key; compensation calls also include the original forward output. It deliberately omits approval prompts and reviewer metadata.

Input, stdout, and stderr are independently bounded. Nonzero exits become ordinary failed attempts. Stderr is excluded from errors by default because reports and checkpoints may persist error messages; expose_stderr=True is an explicit debugging/privacy decision. The child receives only explicit environment entries by default, plus a small Windows platform allowlist required to start normal programs. Set inherit_environment=True only when the child is authorized to receive all parent environment variables.

When a workflow timeout or caller cancellation arrives, Samsarix terminates the direct child, waits for a bounded grace period, then kills it if necessary before propagating cancellation. This fixes the lifecycle problem of uninterruptible worker threads; it does not sandbox filesystem/network access, kill arbitrary descendant processes, or make an external side effect exactly once. Pass the protocol idempotency key to effect destinations. The runnable subprocess pipeline is one file that acts as both orchestrator and isolated worker.

Observe progress without exposing payloads

Pass one or more sync or async event handlers when constructing the runner:

from samsarix_orchestration import WorkflowEvent


async def observe(event: WorkflowEvent) -> None:
    await metrics.increment(f"workflow.{event.kind.value}")


runner = WorkflowRunner(actions, event_handlers=(observe,))

Within each run, handlers receive monotonically sequenced events one at a time, including attempts, retries, restored steps, checkpoint commits, failures, blocks, and cancellation. Event payloads deliberately exclude workflow inputs, step parameters, outputs, dependency values, error messages, and idempotency keys. Run, workflow, and step identifiers plus error type names remain operational data and may still be sensitive.

Delivery is ordered and backpressured: the next lifecycle transition waits for every handler. A handler exception raises EventDeliveryError rather than silently losing an audit event. Wrap a non-critical telemetry sink in its own error policy if business work must continue during a telemetry outage. The runnable observer example adapts the stream to JSON logs and counters using only the standard library.

Ordering is per run. If one runner executes multiple runs concurrently, a shared sync handler can be called from different worker threads and must provide its own cross-run thread safety.

Pause before high-risk actions

Approval gates are static pre-action barriers in workflow schema version 2. Generate a runnable example and start it with durable storage:

samsarix-orchestration init approval.json --approval
samsarix-orchestration run approval.json \
  --checkpoint-db .samsarix-runs/approvals.db \
  --run-id release-2026-08-01

The command exits with 3, reports status: "paused", and prints a 64-character request ID. No handler in that ready batch starts. Review the completed preparation-step outputs, then resume with exactly one decision:

samsarix-orchestration run approval.json \
  --checkpoint-db .samsarix-runs/approvals.db \
  --run-id release-2026-08-01 --resume \
  --approve REQUEST_ID

Use --reject REQUEST_ID to terminate the gated step without invoking its handler. When several requests are pending, the flags may be repeated; one rejection cancels other pending requests and fail-fast blocks remaining work.

Python applications resume with ApprovalDecision.approve(...) or ApprovalDecision.reject(...). The optional decided_by and reason fields are bounded audit labels supplied by the caller; Samsarix records but does not authenticate them. An approved handler receives the durable record as context.approval.

The runtime commits a decision before invoking an approved handler. Each request is bound to the run ID and canonical workflow, input, and dependency-output state. Competing SQLite decisions serialize, and only one divergent decision can win. Schema v2 rejects unknown workflow fields; older Samsarix runtimes reject version 2 rather than ignoring an approval gate.

This primitive records authorization decisions but does not authenticate the person making them. Applications own reviewer authentication, authorization policy, presentation of prepared outputs, and protection of checkpoint files. Approval request IDs are identifiers, not bearer secrets.

Roll back partial external effects

Schema-v3 steps may name a separately registered compensating action. Generate and run a complete local Saga demonstration:

samsarix-orchestration init order-saga.json --saga
samsarix-orchestration plan order-saga.json
samsarix-orchestration run order-saga.json \
  --checkpoint-db .samsarix-runs/sagas.db \
  --run-id order-42 --events

The demo intentionally fails its final forward step, compensates charge before reserve, and exits with 1 because the business workflow did not succeed. Its report separately records compensation_status: "succeeded". This distinction prevents a successful rollback from being mistaken for successful business completion.

Python applications pass a separate compensations mapping to WorkflowRunner. A CompensationContext contains the original step output, its dependency outputs, workflow input, and a stable run-id:step-id:compensate idempotency key. Compensable steps in the same reverse dependency wave may run concurrently; prerequisites are not compensated until all still-pending compensable dependants succeed.

The runtime checkpoints the compensating phase before invoking a compensator and records each successful reverse effect after its dependency wave. If a compensator exhausts its bounded retry policy, earlier prerequisites remain untouched and a later resume=True attempt retries only unfinished compensation. As with forward actions, the effect and its checkpoint cannot be made atomic by this library: compensators must honor their idempotency key. Compensation is application-defined semantic repair, not database rollback or proof that the original side effect was perfectly reversible. The runnable compensating order example shows the same contract with application-defined Python handlers.

Resume expensive or side-effecting work

Checkpointing is explicit and remains local. Give a run a stable identifier and a store:

from samsarix_orchestration import JsonDirectoryCheckpointStore

store = JsonDirectoryCheckpointStore(".samsarix-runs")
result = await runner.run(
    definition,
    workflow_input,
    run_id="customer-import-2026-08-01",
    checkpoint_store=store,
    resume=True,
)

The first attempt omits resume=True. A resumed attempt must use the exact same workflow definition and JSON input; canonical SHA-256 identities prevent accidental replay against changed work. Schema-v1/v2 forward recovery restores only successful steps, so failed steps run again. Schema-v3 checkpoints additionally retain terminal forward results once a Saga enters compensation, allowing resume to continue rollback without replaying forward work. Every handler receives a stable context.idempotency_key of run-id:step-id across attempts. Starting a new checkpointed run with an existing run id fails closed; explicitly resume it or choose another id.

This is an at-least-once contract, not an exactly-once claim. A process can stop after an external effect succeeds but before its checkpoint is written, so effectful handlers must pass the idempotency key to the target system or otherwise deduplicate it. The runnable resumable order example demonstrates that crash window without duplicating a receipt. See real use cases for fit and non-fit guidance and external consumer evidence for the independently installed redaction pipeline.

For multiple runs in one trusted host, use the standard-library SQLite store:

from samsarix_orchestration import SqliteCheckpointStore

store = SqliteCheckpointStore(".samsarix-runs/runs.db")

It uses short-lived connections, bounded lock waits, BEGIN IMMEDIATE writes, WAL mode, and full synchronous durability. Distinct run IDs may be saved from multiple threads or processes on the same machine. SQLite serializes writers; competing divergent saves for one run fail closed. It is not a cross-host coordinator and must live on a local filesystem, not a network filesystem. Run summaries exclude outputs, and runs show also omits outputs unless --include-outputs is explicit. Deletion requires the run ID twice.

The SQLite batch example executes and inspects several independent runs. SQLite's upstream documentation describes the WAL concurrency model and runtime pragmas used here.

Development

python -m pip install -e ".[dev]"
python -m ruff check .
python -m mypy
python -m pytest
python -m bandit -q -r src
python -m build
python -m twine check dist/*

The test command enforces at least 85% branch-aware coverage. CI runs linting, strict typing, tests, package builds, and an installed-wheel smoke test on Python 3.11–3.13. Python libraries do not normally lock their consumers' dependency graph; this package has no runtime dependencies, while bounded development ranges live in pyproject.toml.

Distribution

The supported artifact is the samsarix_orchestration package built from the src layout and the samsarix-orchestration console script:

python -m build
python -m pip install --force-reinstall --no-deps dist/samsarix_orchestration-0.1.0-py3-none-any.whl
samsarix-orchestration --version

The helix_orchestration import, python -m helix_orchestration, and helix-orchestration command are compatibility aliases during the 0.1.x series. They delegate to the Samsarix implementation and do not maintain a second runtime. See the migration guide. Unsupported historical research modules were removed from the active tree and remain recoverable from Git revision 6e10c5b.

Security, privacy, and cost

The core Python runtime performs no network requests, loads no dynamic modules from workflow data, and executes no workflow strings as code. Registered subprocess handlers can access the network with the invoking user's privileges. Subprocess environment access follows the host application's explicit subprocess_action policy; the built-in CLI path does not use that adapter. Workflow JSON selects only action names that the host application explicitly registered. Concurrency, step count, timeouts, retries, input size, and output size are bounded. Cancellation propagates to running async actions.

Action and compensation handlers are trusted application code. In-process handlers have the Python process's privileges; subprocess handlers run as the same operating-system user. Samsarix Orchestration is not a sandbox. A handler that calls a model or external API owns its authentication, destination validation, timeout, cancellation, privacy, and cost controls. The built-in CLI path has no API or operating cost beyond local compute and disk space for explicitly requested reports or checkpoints.

No telemetry is collected implicitly. Lifecycle events are delivered only to handlers the application explicitly registers or when the CLI's --events flag is present. Run inputs and outputs stay in memory unless --output is provided or checkpointing is explicitly enabled. Both stores contain successful step outputs in plaintext; SQLite may also create -wal and -shm sidecars. The caller controls filesystem permissions, encryption, backups, retention, and deletion.

Project and license status

Copyright 2026 Samsarix LLC and contributors. Source code is licensed under the Mozilla Public License 2.0. MPL-2.0 permits commercial use and combination with proprietary applications while requiring distributed modifications to covered source files to remain available under MPL-2.0.

See LICENSING.md for the model and historical-license note, TRADEMARKS.md for brand use, and CONTRIBUTING.md for contribution terms.