{"slug": "show-hn-woml-a-markup-language-for-building-workflows-and-ai-agents", "title": "Show HN: WOML – A markup language for building workflows and AI agents", "summary": "An open-source project released WOML, a code-first markup language and runtime for building automated workflows, backend applications, and AI agents, distributed as the woml-cli package via npm, Bun, or pnpm. Each .woml file combines HTML-inspired markup for triggers, steps, branches, loops, parallel work, approvals, and policies with inline JavaScript or imported JavaScript/TypeScript modules, while the runtime manages attempts, retries, state, waits, workflow calls, recovery, and execution history. WOML requires Bun 1.3.14 or later, and its Linux packages require glibc 2.31 or newer.", "body_md": "WOML is an open-source, code-first language and runtime for building automated workflows, backend applications, and AI agents. Describe the process in readable, HTML-inspired markup, use JavaScript for logic, and connect the APIs, services, databases, local tools, and infrastructure involved.\n\nEach `.woml` file combines three parts:\n\n- **Readable structure** — triggers, steps, branches, loops, parallel work, approvals, and policies remain visible as markup.\n- **Real code** — inline JavaScript and imported JavaScript or TypeScript modules implement custom behavior without waiting for a built-in connector.\n- **Managed execution** — the runtime handles attempts, retries, state, waits, workflow calls, recovery, and execution history.\n\nThe workflow source is the program, its readable architecture, and its execution policy. It can live in Git, move through pull requests and CI, and run locally or on infrastructure you control.\n\nStart with one workflow for a local task or webhook. As the work grows, extract reusable modules, call or start other workflows, publish events, and operate the result as a coordinated system without changing its underlying model.\n\n| Build | Use WOML to | \n|---|---|\n| **Automated workflows** | Process orders, onboard customers, generate reports, review content, and coordinate human approvals. | \n| **Backend applications** | Handle webhooks, expose workflow APIs, run scheduled jobs, and coordinate event-driven services. | \n| **AI agents** | Connect models, tools, memory, specialist workflows, and human review in one durable process. | \n| **Data pipelines** | Import, validate, transform, classify, and store data with explicit control flow and recovery. | \n| **Infrastructure systems** | Run deployment checks, supervise local processes, coordinate infrastructure changes, and respond to incidents. | \n\n- **Read the whole process** — semantic markup keeps execution order, decisions, parallel work, and policies visible from top to bottom.\n- **Use code where it belongs** — write JavaScript inline or import JavaScript and TypeScript modules for application-specific logic.\n- **Integrate what your system needs** — call APIs, query databases, run approved local tools, and expose project-owned services without waiting for a connector catalog.\n- **Grow through composition** — split large systems into reusable workflows that call each other, start background work, and communicate through events.\n- **Keep operational history** — durable execution records attempts, decisions, waits, results, and failures so important work can be inspected and recovered.\n- **Own the source and runtime** — review workflows in Git and run them on a developer machine, server, container, or infrastructure you control.\n\n1. **Describe the process** in a`.woml` file using triggers, steps, control flow, and runtime policies.\n2. **Connect your tools** with inline JavaScript, imported modules, managed services, secrets, and reusable child workflows.\n3. **Run and operate it** with the WOML runtime, which records durable state and provides inspection, cancellation, recovery, logs, and backups.\n\nWOML requires [Bun](https://bun.sh/) 1.3.14 or later. Install the global CLI with npm:\n\n```\nnpm install --global woml-cli\n```\n\nOr install it with Bun or pnpm:\n\n```\nbun add --global woml-cli\npnpm add --global woml-cli\n```\n\nAll three commands install the same `woml` executable:\n\n```\nwoml --version\n```\n\nNative engines are selected automatically for supported macOS, Linux, and Windows systems. You do not need to install the platform packages or configure a database manually.\n\nLinux packages require glibc 2.31 or newer.\n\nCreate a file named `order-router.woml`:\n\n```\n<woml>\n  <workflow\n    id=\"order-router\"\n    name=\"Order Router\"\n    description=\"Check inventory and risk concurrently, then route the order.\"\n    version=\"1.0.0\"\n  >\n    <triggers>\n      <webhook\n        id=\"newOrder\"\n        path=\"/webhooks/orders\"\n        method=\"POST\"\n        auth=\"none\"\n      >\n        <schema>\n          {\n            \"type\": \"object\",\n            \"required\": [\"orderId\", \"amount\", \"inStock\", \"riskScore\"],\n            \"properties\": {\n              \"orderId\": { \"type\": \"string\" },\n              \"amount\": { \"type\": \"number\" },\n              \"inStock\": { \"type\": \"boolean\" },\n              \"riskScore\": { \"type\": \"number\" }\n            },\n            \"additionalProperties\": false\n          }\n        </schema>\n      </webhook>\n    </triggers>\n\n    <steps>\n      <step\n        id=\"prepareOrder\"\n        name=\"Prepare order\"\n        description=\"Normalize the order received by the webhook.\"\n      >\n        <script>\n          return {\n            orderId: context.payload.orderId,\n            amount: context.payload.amount\n          };\n        </script>\n      </step>\n\n      <parallel\n        id=\"orderChecks\"\n        name=\"Run order checks\"\n        description=\"Check inventory and risk at the same time.\"\n        concurrency=\"2\"\n        on-error=\"wait-all\"\n      >\n        <step\n          id=\"inventoryCheck\"\n          name=\"Check inventory\"\n          description=\"Confirm that the requested item is available.\"\n        >\n          <script>\n            return { available: context.payload.inStock };\n          </script>\n        </step>\n\n        <step\n          id=\"riskCheck\"\n          name=\"Check risk\"\n          description=\"Accept orders with a risk score below seventy.\"\n        >\n          <script>\n            return {\n              approved: context.payload.riskScore < 70,\n              score: context.payload.riskScore\n            };\n          </script>\n        </step>\n      </parallel>\n\n      <step\n        id=\"canFulfill\"\n        name=\"Make decision\"\n        description=\"Combine the inventory and risk results.\"\n      >\n        <script>\n          return {\n            value:\n              context.steps.inventoryCheck.available &&\n              context.steps.riskCheck.approved\n          };\n        </script>\n      </step>\n\n      <choose\n        id=\"orderRoute\"\n        name=\"Route order\"\n        description=\"Accept the order or send it for review.\"\n      >\n        <when test=\"{{context.steps.canFulfill.value}}\">\n          <step id=\"acceptOrder\" name=\"Accept order\">\n            <script>\n              return {\n                status: \"accepted\",\n                message: `Order ${context.steps.prepareOrder.orderId} is ready for fulfillment.`\n              };\n            </script>\n          </step>\n          <result value=\"{{context.steps.acceptOrder}}\" />\n        </when>\n\n        <otherwise>\n          <step id=\"reviewOrder\" name=\"Request review\">\n            <script>\n              return {\n                status: \"review\",\n                message: `Order ${context.steps.prepareOrder.orderId} needs review.`\n              };\n            </script>\n          </step>\n          <result value=\"{{context.steps.reviewOrder}}\" />\n        </otherwise>\n      </choose>\n\n      <step\n        id=\"response\"\n        name=\"Build response\"\n        description=\"Publish one predictable result for the caller.\"\n      >\n        <script>\n          return {\n            orderId: context.steps.prepareOrder.orderId,\n            amount: context.steps.prepareOrder.amount,\n            ...context.steps.orderRoute\n          };\n        </script>\n      </step>\n    </steps>\n  </workflow>\n</woml>\n```\n\nCheck it without starting the automation:\n\n```\nwoml check order-router.woml\n```\n\nThen run it:\n\n```\nwoml run order-router.woml\n```\n\nWOML keeps the automation active and prints its webhook URL together with a generated `curl` command. Trigger it from another terminal:\n\n```\ncurl --request POST http://127.0.0.1:3000/webhooks/orders \\\n  --header 'content-type: application/json' \\\n  --data '{\"orderId\":\"order-42\",\"amount\":240,\"inStock\":true,\"riskScore\":18}'\n```\n\nUse `auth=\"none\"` only for local development. Configure authenticated webhooks before exposing an endpoint outside a trusted environment.\n\n``` php\nflowchart TD\n    trigger[POST /webhooks/orders] --> prepare[Prepare order]\n    prepare --> parallel{Run concurrently}\n    parallel --> inventory[Check inventory]\n    parallel --> risk[Check risk]\n    inventory --> decision[Make decision]\n    risk --> decision\n    decision --> route{Route order}\n    route -->|Accepted| accept[Accept order]\n    route -->|Needs review| review[Request review]\n    accept --> response[Build response]\n    review --> response\n```\n\nWOML presents each run as an organized, colored terminal report. You will see output like this:\n\n```\nRUN  run_8f21c4                                                Order Router\n\n  ✓  Prepare order                                              3 ms\n     Normalize the order received by the webhook.\n     → { orderId: \"order-42\", amount: 240 }\n\n  ✓  Check inventory                                            2 ms\n     → { available: true }\n\n  ✓  Check risk                                                 2 ms\n     → { approved: true, score: 18 }\n\n  ✓  Make decision                                              1 ms\n     → { value: true }\n\n  ✓  Accept order                                               1 ms\n     → { status: \"accepted\", message: \"Order order-42 is ready for fulfillment.\" }\n\n  ✓  Build response                                             1 ms\n     → { orderId: \"order-42\", amount: 240, status: \"accepted\" }\n\nCompleted in 10 ms · 6 succeeded\n```\n\nThe exact run ID and timings will differ. Press `Ctrl`+` C` to stop the active workflow host.\n\n- **`<webhook>`** validated an HTTP request and created a durable workflow run.\n- **`context.payload`** exposed the validated trigger input to every script.\n- **`<parallel>`** ran two independent checks concurrently and waited for both.\n- **`context.steps.<id>`** made completed step results available downstream.\n- **`<choose>`** selected one route and published a stable merged result.\n- **The terminal experience** showed each step, result, duration, and final outcome.\n\nEvery example below is checked against the current WOML compiler.\n\n| Build | What it demonstrates | Run | \n|---|---|---|\n| [Durable run counter](https://github.com/dali-benothmen/woml/blob/master/examples/durableStateWorkflow.woml) | State that survives future runs and process restarts | `woml run examples/durableStateWorkflow.woml` | \n| [Personalize a customer list](https://github.com/dali-benothmen/woml/blob/master/examples/forEachWorkflow.woml) | Durable per-item execution, bounded concurrency, and ordered results | `woml run examples/forEachWorkflow.woml` | \n| [Social distribution](https://github.com/dali-benothmen/woml/blob/master/examples/forkDistributionWorkflow.woml) | Several independent multi-step branches with an explicit join | `woml run examples/forkDistributionWorkflow.woml` | \n| [Telegram approval](https://github.com/dali-benothmen/woml/blob/master/examples/telegramApprovalWorkflow.woml) | Human approval, interactive notification buttons, and durable waiting | `woml run examples/telegramApprovalWorkflow.woml` | \n| [Workflow composition](https://github.com/dali-benothmen/woml/blob/master/examples/workflowCallManual) | One workflow calling another and using its returned result | `woml run examples/workflowCallManual` | \n| [Durable external callback](https://github.com/dali-benothmen/woml/blob/master/examples/durableWaits/ciCallback.woml) | A run that releases its worker and resumes from an idempotent CI signal | `woml run examples/durableWaits/ciCallback.woml` | \n| [Preview environment saga](https://github.com/dali-benothmen/woml/blob/master/examples/compensationAndCleanup/previewEnvironment.woml) | Explicit rollback and mandatory cleanup for partial infrastructure success | `woml run examples/compensationAndCleanup/previewEnvironment.woml` | \n| [Streamed Terraform release](https://github.com/dali-benothmen/woml/blob/master/examples/streamingOutput) | Live process output, structured progress, review, locking, compensation, and replay | See the example runbook | \n| [Local TypeScript module](https://github.com/dali-benothmen/woml/blob/master/examples/moduleWorkflow.woml) | Reusable project code exposed through `services.*` | `woml run examples/moduleWorkflow.woml` | \n\nProvider examples require their documented credentials. Browse the [complete example catalog](https://github.com/dali-benothmen/woml/blob/master/examples) for webhooks, schedules, intervals, internal events, databases, storage, cache, lifecycle, retries, communication providers, and production deployment.\n\nA WOML project can begin with one file and grow into a system of focused workflows and modules. Workflows can call another workflow and wait for its result, start independent work in the background, or publish events that other workflows consume.\n\nCreate a project with workflow discovery and operator-owned configuration already in place:\n\n```\nwoml init my-project\ncd my-project\nwoml check\nwoml test\n```\n\nThe generated `workflow.json` keeps workflow discovery, policies, reviewers, and execution targets reviewable while secret values remain outside source control. The same project model supports local execution, durable artifacts and waits, rich approvals, infrastructure policies, streamed output, OpenTelemetry, and authenticated remote targets. Remote work never silently falls back to the coordinator.\n\nRead the [project manifest reference](https://github.com/dali-benothmen/woml/blob/master/docs/project-manifest.md), follow the [infrastructure-agent tutorial](https://github.com/dali-benothmen/woml/blob/master/docs/infrastructure-agent-tutorial.md), or use the [operator runbook](https://github.com/dali-benothmen/woml/blob/master/docs/combined-developer-experience-operator-runbook.md).\n\n- **Embedded JavaScript** — use`context.payload` ,`context.steps` ,`attempt` ,`services` , and explicitly referenced`secrets` inside scripts.\n- **Project-owned modules** — import local JavaScript or TypeScript and expose reusable logic through`services.*` .\n- **Managed capabilities** — use supervised HTTP, SQLite/PostgreSQL, storage, cache, state, events, workflow calls, and communication services.\n- **Production triggers** — start work manually or from webhooks, schedules, intervals, internal events, Slack, Telegram, Discord, and WhatsApp.\n\n- **Explicit control flow** — combine sequential steps, durable bounded item loops, parallel groups, choices, switches, and concurrent forks with explicit joins.\n- **Reusable workflows** — call a workflow for a result, start background work, and coordinate independent components through events.\n- **Human decisions** — pause durably for approval, preserve the decision, and continue through approved or rejected routes.\n- **Runtime policies** — define concurrency, rate limits, queues, timeouts, retries, and lifecycle hooks beside the workflow they govern.\n\n- **Durable execution** — preserve attempts, decisions, waits, results, failures, and operation identities across process restarts.\n- **Retries and idempotency** — declare retry behavior while retaining stable attempt and operation identities.\n- **Durable waits and signals** — suspend without holding a worker and resume the same run from timers or authenticated callbacks.\n- **Locks, leases, and fencing** — serialize shared-resource work and reject stale owners with monotonic fencing tokens.\n- **Compensation and cleanup** — correct proven partial success, always run cleanup, and stop for review when an external effect is ambiguous.\n\n- **Inspection and recovery** — inspect activity, follow logs, cancel runs, retry verified-safe work, back up state, and prune old history.\n- **Streaming output and progress** — follow supervised process output live, reconnect by cursor, and replay bounded redacted records.\n- **Portable deployment** — run the same project locally or against authenticated remote targets without silent fallback.\n- **Cross-platform runtime** — install one CLI that selects the appropriate native Rust engine automatically.\n\nWhen an interrupted external effect has an uncertain outcome, WOML marks it **ambiguous** instead of retrying it automatically. Inspect the real system with `woml dispatch inspect`, then record an audited decision with `woml dispatch reconcile`.\n\n```\nwoml check workflows/                    # Parse, validate, and compile\nwoml run workflows/                      # Activate workflows in the foreground\nwoml run workflows/ --background         # Activate them in the background\nwoml inspect                             # Open the colored runtime inspector\nwoml list                                # List workflows and recent runs\nwoml get run_...                         # Inspect one run and its event history\nwoml cancel run_...                      # Cancel a pending or running workflow\nwoml recover run_... --retry action-id   # Resume a verified-safe corrective attempt\nwoml logs workflow-id --follow           # Follow live process output and progress\nwoml secrets set API_TOKEN               # Store a secret without printing it\nwoml backup backups/latest               # Back up the durable state store\nwoml prune --before 30d --dry-run        # Preview retention cleanup\n```\n\nSee the [CLI reference](https://github.com/dali-benothmen/woml/blob/master/docs/cli-reference.md) for all commands, flags, exit behavior, and machine-readable output.\n\nThe [WOML extension](https://github.com/dali-benothmen/woml/blob/master/woml-vscode) gives `.woml` files HTML-style markup highlighting, embedded JavaScript syntax, highlighted runtime bindings such as `context` and `services`, reference-expression highlighting, snippets, and a dedicated file icon.\n\nThe extension follows your existing VS Code theme instead of requiring a separate WOML color theme.\n\nWOML is structured source code, so coding agents can create and change workflows in the same environment as the rest of your project. The **WOML Skill** teaches agents the language structure, runtime bindings, control-flow patterns, services, secrets, and validation workflow they need to produce real `.woml` files without inventing syntax.\n\n```\nUse the WOML skill to build an order-processing workflow that starts from a\nwebhook, checks inventory and risk concurrently, and routes the result.\n```\n\nThe generated workflow remains readable, reviewable in Git, and verifiable with `woml check` before it runs.\n\nFor Claude Code, install the complete skill in the current project:\n\n```\nmkdir -p .claude/skills/woml\ncurl -fsSL https://github.com/dali-benothmen/woml/releases/latest/download/woml-skill.tar.gz \\\n  | tar -xz -C .claude/skills/woml\n```\n\nFor Codex and other clients that use the Agent Skills project convention:\n\n```\nmkdir -p .agents/skills\ncp -R skills/woml .agents/skills/woml\n```\n\n[View the WOML Skill and installation guide →](https://github.com/dali-benothmen/woml/blob/master/skills/woml)\n\nUse [GitHub Discussions](https://github.com/dali-benothmen/woml/discussions) for questions and [GitHub Issues](https://github.com/dali-benothmen/woml/issues) for reproducible bugs. Follow the [support guide](https://github.com/dali-benothmen/woml/blob/master/SUPPORT.md) when sharing diagnostics, and report vulnerabilities privately according to the [security policy](https://github.com/dali-benothmen/woml/blob/master/SECURITY.md).\n\nContributions are welcome, including bug reports, documentation improvements, tested examples, provider work, compiler changes, and runtime improvements. Read [CONTRIBUTING.md](https://github.com/dali-benothmen/woml/blob/master/CONTRIBUTING.md) before opening a pull request.\n\nWOML is released under the [Apache License 2.0](https://github.com/dali-benothmen/woml/blob/master/LICENSE).", "url": "https://wpnews.pro/news/show-hn-woml-a-markup-language-for-building-workflows-and-ai-agents", "canonical_source": "https://github.com/dali-benothmen/woml", "published_at": "2026-10-28 15:54:42+00:00", "updated_at": "2026-10-28 16:12:58.306333+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "ai-tools"], "entities": ["WOML", "Bun", "npm", "pnpm", "woml-cli"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-woml-a-markup-language-for-building-workflows-and-ai-agents", "markdown": "https://wpnews.pro/news/show-hn-woml-a-markup-language-for-building-workflows-and-ai-agents.md", "text": "https://wpnews.pro/news/show-hn-woml-a-markup-language-for-building-workflows-and-ai-agents.txt", "jsonld": "https://wpnews.pro/news/show-hn-woml-a-markup-language-for-building-workflows-and-ai-agents.jsonld"}}