{"id":49692497,"url":"https://github.com/duriantaco/marlin","last_synced_at":"2026-05-07T18:49:22.571Z","repository":{"id":352380533,"uuid":"1214897370","full_name":"duriantaco/marlin","owner":"duriantaco","description":"Typed AI workflow compiler/runtime in Rust with durable execution and schema-first flows","archived":false,"fork":false,"pushed_at":"2026-04-19T09:46:34.000Z","size":2682,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-04-19T10:30:52.862Z","etag":null,"topics":["ai-workflows","compiler","developer-tools","durable-execution","llm","runtime","rust","type-system","workflow-engine"],"latest_commit_sha":null,"homepage":"","language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"apache-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/duriantaco.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-19T07:39:13.000Z","updated_at":"2026-04-19T08:55:13.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/duriantaco/marlin","commit_stats":null,"previous_names":["duriantaco/marlin"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/duriantaco/marlin","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fmarlin","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fmarlin/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fmarlin/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fmarlin/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/duriantaco","download_url":"https://codeload.github.com/duriantaco/marlin/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/duriantaco%2Fmarlin/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":32751758,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-07T02:14:30.463Z","status":"ssl_error","status_checked_at":"2026-05-07T02:14:29.405Z","response_time":62,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["ai-workflows","compiler","developer-tools","durable-execution","llm","runtime","rust","type-system","workflow-engine"],"created_at":"2026-05-07T18:49:21.802Z","updated_at":"2026-05-07T18:49:22.566Z","avatar_url":"https://github.com/duriantaco.png","language":"Rust","funding_links":[],"categories":[],"sub_categories":[],"readme":"\u003cp align=\"center\"\u003e\n  \u003cimg src=\"marlin.png\" alt=\"Marlin logo\" width=\"420\"\u003e\n\u003c/p\u003e\n\n# Marlin\n\nMarlin is a small language and local-first runtime for long-running AI workflows that need to pause, survive restarts, and resume safely with typed state.\n\nUse Marlin when your workflow cannot afford to lose its place.\n\n## Why Marlin Exists\n\nTypical workflow today:\n\n```text\nLLM/API call -\u003e tool/API call -\u003e wait for human -\u003e process crashes -\u003e rebuild state by hand or replay work\n```\n\nWith Marlin:\n\n```text\neffectful steps run -\u003e workflow enters a durable wait state -\u003e run state and effect log are persisted -\u003e restart later -\u003e continue or resume from the saved workflow state\n```\n\nThat is a real runtime behavior in this repo:\n\n- wait steps persist a durable waiting state to disk\n- completed steps stay recorded in the persisted run\n- `continue` and `resume` reload that persisted run instead of starting from scratch\n\nImportant caveat:\n\n- Marlin does **not** truthfully promise \"nothing ever re-runs\"\n- interrupted `Pure` steps may replay\n- interrupted `Effectful` steps may require explicit recovery instead of blind replay\n- committed wait steps resume from saved state, but interrupted waits still follow recovery rules\n\nThe exact implementation lives in:\n\n- [`crates/marlin-runtime/src/lib.rs`](./crates/marlin-runtime/src/lib.rs)\n- [`crates/marlin-nodes/src/lib.rs`](./crates/marlin-nodes/src/lib.rs)\n- [`examples/review_wait.marlin`](./examples/review_wait.marlin)\n\nOne concrete example:\n\n- a plugin-backed LLM/API drafts an outbound sales message\n- a human approves it\n- a second plugin-backed LLM/API step finalizes the approved message\n- the workflow pauses again before dispatch\n- after restart, Marlin reloads that saved run instead of replaying the finalized message step\n\nThe worked version of that story lives in [`docs/why-marlin.md`](./docs/why-marlin.md).\n\nIf you want the easiest real app example to copy, start with:\n\n- built-in support triage app: [`examples/real_world/support_triage`](./examples/real_world/support_triage)\n\nThe repo also ships the longer outbound comparison:\n\n- without Marlin: [`examples/real_world/without_marlin`](./examples/real_world/without_marlin)\n- with Marlin: [`examples/real_world/with_marlin`](./examples/real_world/with_marlin)\n\n## What To Measure\n\nMarlin is trying to solve brittle long-running workflows, not raw model throughput.\n\nSo the most important metrics are:\n\n- `expensive_step_replay_rate` after restart\n- `manual_recovery_rate` after interrupted work\n- `operator_visibility` of current step, completed steps, pending steps, and last effect events\n- `time_to_recover` from restart to a useful inspectable state\n\nUseful secondary metrics later:\n\n- `draft_calls_avoided`\n- `tokens_avoided`\n- `cost_avoided_usd`\n\nMarlin now surfaces token/cost-style usage data in `inspect` when a node records it in effect detail.\nThe real-world `DraftOutboundMessage` plugin example does this today.\n\n## Observed Example Results\n\nThese long-running comparison results came from a manual local rerun against [`examples/real_world/fake_openai_server.py`](./examples/real_world/fake_openai_server.py), so both sides used the same HTTP-backed draft step.\n\nImportant:\n\n- token counts are real observed values from that rerun\n- USD figures are estimates derived from the example's configured token pricing, not billed provider invoices\n\nObserved result without Marlin:\n\n- initial draft cost:\n  - `49` total tokens\n  - `0.000041` USD estimated from configured pricing\n- after manager approval, the app ran a second expensive finalize step\n- the process crashed after finalize completed but before that result became durable workflow state\n- `recover` had to replay finalize\n- final stored record showed:\n  - `finalize_attempts = 2`\n  - `finalize_recovery_replays = 1`\n  - `finalize_total_tokens_total = 170`\n  - `finalize_cost_usd_estimate_total = 0.0001328`\n  - `dispatch_status = pending`\n  - `recovery_status = manual_recovery_replayed_finalize`\n- extra post-crash finalize cost:\n  - `85` extra tokens\n  - `0.0000664` USD estimated from configured pricing\n\nObserved result with Marlin:\n\n- the draft + finalize steps together reported:\n  - `134` total tokens\n  - `0.000107` USD estimated from configured pricing\n- after `approve`, the run entered a second durable wait at `workflow.dispatch`\n- after cold restart, `continue` reloaded the same saved run at `workflow.dispatch`\n- after `dispatch`, the run completed with:\n  - `workflow.finalize.attempts = 1`\n  - `workflow.notify.status = completed`\n- extra post-restart finalize cost:\n  - `0` extra tokens\n  - `0` extra USD estimated\n\nThat is the current proof point: Marlin keeps completed expensive step state on disk across restart, so the workflow does not lose its place at later wait boundaries either.\n\n## Status\n\nMarlin is a very early beta.\n\nThis repository is:\n\n- unstable\n- incomplete\n- still evolving at the language and runtime boundary\n\nDo not treat the current syntax, IR, runtime artifact, or CLI output as stable yet.\n\n## What Marlin Is\n\nMarlin is meant to be:\n\n- a small language\n- a type checker and validator\n- a durable execution engine\n- a node/plugin system for AI workflows\n- an additive inference-aware execution layer through `marlin-llm` and `marlin-gateway`\n- a CLI-first tool\n\n## What Marlin Is Not\n\nMarlin does **not** make the LLM itself infer tokens faster.\n\nIt does not make GPT, Claude, or other models run faster at the GPU level.\n\nWhat it can do is make **systems around LLMs** faster and better:\n\n- faster to describe\n- faster to validate\n- faster to iterate on\n- less wasteful in retries and bad wiring\n- more reliable when humans, tools, and long-running waits are involved\n- easier to recover after a crash because workflow state is persisted to disk\n\nSo the promise is not \"faster neural nets\".\n\nThe promise is closer to:\n\n\u003e a better language and runtime for building LLM-driven systems\n\nToday that also includes one real execution path for model calls:\n\n```text\nworkflow -\u003e built-in LLMCall or plugin -\u003e marlin_gateway_openai -\u003e OpenAI-compatible upstream\n```\n\nThat path gives Marlin a place to normalize:\n\n- backend and model choice\n- usage and cost metadata\n- latency\n- deterministic route selection\n\nwithout pretending Marlin itself is a serving engine.\n\n## What Is Being Done Right Now\n\nThe current work is focused on the core, not product surfaces.\n\nActive work:\n\n- tightening `marlin-lang`\n- benchmarking Marlin over stable workload shapes and persisted runtime lifecycle phases\n- keeping one semantic source of truth\n- locking the typed IR and prepared-program boundary\n- hardening persisted recovery semantics\n- expanding runtime/operator measurements beyond compiler phases\n- making the LLM execution path more inference-aware through `marlin-llm` and `marlin-gateway`\n- surfacing richer usage and routing metadata to operators through `inspect`\n\nNot being built yet:\n\n- frontend studio\n- cloud control plane\n- browser extension\n- multi-service product surface\n\n## Install\n\nPrerequisite:\n\n- Rust toolchain with `cargo`\n\nInstall the CLI directly from GitHub:\n\n```bash\ncargo install --locked --git https://github.com/duriantaco/marlin.git marlin-cli\n```\n\nCheck that the binary is available:\n\n```bash\nmarlin --help\n```\n\n## Documentation\n\nLong-form docs live in [`docs/`](./docs) and are set up to publish to GitHub Pages from [`.github/workflows/docs.yml`](./.github/workflows/docs.yml).\n\nThe docs are written to treat the codebase as the source of truth. Start with:\n\n- why Marlin: [`docs/why-marlin.md`](./docs/why-marlin.md)\n- real-world examples: [`examples/real_world/README.md`](./examples/real_world/README.md)\n- real-world built-in app example: [`examples/real_world/support_triage/README.md`](./examples/real_world/support_triage/README.md)\n- built-in LLM example with typed structured output: [`examples/llm_call_builtin.marlin`](./examples/llm_call_builtin.marlin)\n- landing page: [`docs/index.md`](./docs/index.md)\n- quickstart: [`docs/getting-started.md`](./docs/getting-started.md)\n- integration guide: [`docs/integrating-marlin.md`](./docs/integrating-marlin.md)\n- plugin guide: [`docs/plugins.md`](./docs/plugins.md)\n- LLM gateway path: [`docs/llm-gateway.md`](./docs/llm-gateway.md)\n- worked examples: [`docs/examples.md`](./docs/examples.md)\n- runtime behavior: [`docs/runtime-semantics.md`](./docs/runtime-semantics.md)\n\nSupporting docs:\n\n- language/runtime boundary: [`docs/language-and-artifact.md`](./docs/language-and-artifact.md)\n- CLI: [`docs/cli.md`](./docs/cli.md)\n- limits: [`docs/limits-and-guarantees.md`](./docs/limits-and-guarantees.md)\n\n## How To Use It\n\nPrerequisite:\n\n- Rust toolchain with `cargo`\n\nFrom the repo root, validate the example program:\n\n```bash\ncargo run -p marlin-cli -- check examples/lead_review.marlin\n```\n\nPrepare the example program for runtime:\n\n```bash\ncargo run -p marlin-cli -- run examples/lead_review.marlin\n```\n\nRun the built-in `LLMCall` example against a local OpenAI-compatible endpoint:\n\n```bash\n/usr/bin/env python3 examples/real_world/fake_openai_server.py --port 8080\ncargo run -p marlin-cli -- run examples/llm_call_builtin.marlin\n```\n\nThat example uses `output_schema: \"Answer\"` so downstream bindings like `call.structured.answer`\nare type-checked, while `call.text` still stays available for plain-text flows.\n\nRun the simplest app-level example:\n\n```bash\ncd examples/real_world/support_triage\n/usr/bin/env python3 ../fake_openai_server.py --port 8080\n/usr/bin/env python3 app.py start \\\n  ticket-123 \\\n  \"Taylor at ExampleCo\" \\\n  \"Locked out after password reset\" \\\n  \"We reset the password twice and still cannot sign in from either laptop.\"\n/usr/bin/env python3 app.py status ticket-123\n```\n\nThat example shows the same typed `LLMCall` surface inside a thin app wrapper that only stores\n`ticket_id -\u003e run_dir` and resumes `workflow.review` when a human decides.\n\nExplain what Marlin will prepare from source:\n\n```bash\ncargo run -p marlin-cli -- explain examples/lead_review.marlin\n```\n\nRun a workflow that enters a wait state:\n\n```bash\ncargo run -p marlin-cli -- run examples/review_wait.marlin\n```\n\nIf your workflow uses external plugin nodes, Marlin discovers them from:\n\n- `MARLIN_PLUGIN_DIRS`\n- `.marlin/plugins` under the current project tree or run directory tree\n\nRead [`docs/plugins.md`](./docs/plugins.md) for the manifest format and runtime contract.\n\nIf you want the shipped LLM/API execution path, read [`docs/llm-gateway.md`](./docs/llm-gateway.md), the built-in app example under [`examples/real_world/support_triage`](./examples/real_world/support_triage), and the plugin-backed comparison under [`examples/real_world/with_marlin`](./examples/real_world/with_marlin).\n\nInspect a persisted run:\n\n```bash\ncargo run -p marlin-cli -- inspect .marlin/runs/\u003crun-id\u003e\n```\n\nGet the same lifecycle state in machine-readable form:\n\n```bash\ncargo run -p marlin-cli -- status .marlin/runs/\u003crun-id\u003e --json\n```\n\nResume a waiting run:\n\n```bash\ncargo run -p marlin-cli -- resume .marlin/runs/\u003crun-id\u003e workflow.review true\n```\n\nContinue a persisted run after restart:\n\n```bash\ncargo run -p marlin-cli -- continue .marlin/runs/\u003crun-id\u003e\n```\n\nCancel an active run:\n\n```bash\ncargo run -p marlin-cli -- cancel .marlin/runs/\u003crun-id\u003e \"operator stop\"\n```\n\nRun the workspace tests:\n\n```bash\ncargo test --workspace\n```\n\nRun the benchmark harness:\n\n```bash\ncargo run --release -p marlin-bench -- --format markdown\n```\n\nList the benchmark workloads:\n\n```bash\ncargo run --release -p marlin-bench -- --list-workloads\n```\n\nWhat the CLI currently does:\n\n- `check` parses source, loads built-ins plus discovered plugins, and lowers source into validated typed IR\n- `check`, `run`, `continue`, `resume`, `status`, and `cancel` now also support `--json` for machine-readable lifecycle output\n- `explain` compiles and prepares a workflow, then prints the prepared step plan and runtime-facing metadata\n- `run` prepares the program, persists a run record under `.marlin/runs`, and either completes or enters a wait state\n- `continue` reloads a persisted run, reapplies recovery rules, re-checks provider/version and executor provenance compatibility, and can re-check waiting runs against persisted deadlines\n- `inspect` loads a persisted run plus recent effect-log entries and now starts with the current status, next recommended action, run-level usage, and latest LLM/routing summary before the per-step detail dump\n- `status` reads a persisted run directory and now surfaces the current runtime state, waiting step/kind, and next recommended operator action alongside total attempts, retried steps, and timed-out steps\n- `resume` resumes a waiting step from disk with a JSON payload after verifying the persisted node provider and executor provenance still match the loaded runtime\n- `cancel` marks active work cancelled and persists that terminal state\n- pure steps can retry from persisted state when their manifest retry policy allows it\n- pure and wait steps can time out from persisted state when their manifest timeout policy allows it\n- external plugin executors run through the subprocess contract in `crates/marlin-plugin`\n- gateway-backed LLM plugins can route OpenAI-compatible calls through `marlin_gateway_openai` with deterministic rule-based routing\n\nWhat it does not do yet:\n\n- production-grade replay guarantees\n- robust effect recovery for real external systems\n- hard timeout preemption for arbitrary executor code\n- automatic retries or timeout enforcement for effectful steps\n- stable public language/runtime guarantees\n\nRuntime limits that matter today:\n\n- retry policy is implemented only for `Pure` steps\n- timeout policy is implemented only for `Pure` and `Wait` steps\n- effectful executors still need explicit idempotent recovery instead of automatic replay\n- a restart during an in-flight effectful step may block for recovery instead of blindly continuing\n- source syntax does not yet expose retry/timeout configuration directly; today those policies come through manifests/catalog entries\n\n## Initial Scope\n\nThe first version of Marlin should avoid product bloat.\n\nWe start with:\n\n- one Rust workspace\n- one CLI\n- one semantic core\n- one runtime core\n- no frontend\n- no browser extension\n- no cloud control plane\n\nThose can come later if the core proves worth it.\n\n## Workspace Layout\n\n`crates/marlin-lang`\n\n- syntax\n- AST\n- validation\n- typed IR\n- runtime preparation\n\n`crates/marlin-runtime`\n\n- execution model over flattened plans\n- durable state and effect log\n- recovery rules for restarted runs\n- scheduler interfaces\n\n`crates/marlin-nodes`\n\n- built-in manifests and runtime executors\n\n`crates/marlin-plugin`\n\n- plugin manifest loading\n- subprocess executor protocol\n- external node registry wiring\n\n`crates/marlin-llm`\n\n- shared `LLMCall` request/response/accounting contract\n- normalized routing, cache, and budget hint types\n\n`crates/marlin-gateway`\n\n- OpenAI-compatible LLM execution layer\n- routing policy loading\n- usage/cost/latency normalization\n\n`crates/marlin-cli`\n\n- `marlin check`\n- `marlin run`\n- `marlin continue`\n- `marlin status`\n- `marlin resume`\n- `marlin cancel`\n\n`crates/marlin-bench`\n\n- benchmark harness for Marlin compiler and persisted runtime lifecycle cost\n- stable workload suite for tracking performance over time\n\n## Current State\n\nThis repository is intentionally minimal.\n\nThe current scaffold exists to lock the semantic/runtime boundary before we commit to syntax sugar or UI. Today that boundary is:\n\n- source text -\u003e AST\n- AST -\u003e typed IR\n- typed IR -\u003e prepared program\n- runtime -\u003e schedules persisted execution over the prepared program\n\nThat is the contract the current compiler/runtime work is optimizing around.\n\n## Current Language Direction\n\nMarlin is aiming for:\n\n- schema-first data shapes\n- reusable groups/modules\n- null-aware flow semantics\n- one canonical typed IR\n- CLI-first workflows\n\nSee [DESIGN.md](/Users/oha/marlin/DESIGN.md) for the design contract, [docs/ARCHITECTURE.md](/Users/oha/marlin/docs/ARCHITECTURE.md) for crate boundaries, and [ROADMAP.md](/Users/oha/marlin/ROADMAP.md) for the current implementation status and next milestones.\n\nSee [docs/PERFORMANCE.md](/Users/oha/marlin/docs/PERFORMANCE.md) for the current Marlin performance snapshot and [docs/BENCHMARKS.md](/Users/oha/marlin/docs/BENCHMARKS.md) for the benchmark design and methodology.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduriantaco%2Fmarlin","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fduriantaco%2Fmarlin","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fduriantaco%2Fmarlin/lists"}