{"slug": "dot-factory-a-spec-to-describe-complex-agentic-workflows", "title": "Dot factory – a spec to describe complex (agentic) workflows", "summary": "A new specification called dotFactory proposes an eight-concept language for describing agentic and non-agentic automation workflows as typed dataflow graphs, with no runtime to install and the interface itself as the deliverable. The spec defines types, triggers, steps, runners, bindings, loops, sinks and external ports, and leaves trigger kinds, runner backends, sink destinations and port resolution to host adapters such as local Docker containers with the OpenCode server, Cloudflare Workers with R2, or AWS/GCP Lambda, Batch and SQS. The author argues the approach lets the same factory be hosted anywhere so adapters can compete without locking in workflows.", "body_md": "A spec, not a runtime\n\n# Describe the workflow.\n\nNot the implementation.\n\n        dotFactory is a small language for automations with and without AI agents.\n        You write the *dataflow* — typed values moving through triggers,\n        steps and sinks — and leave the object models, async runtimes and\n        dependency-injection frameworks behind.\n      \n\nNo runtime to install. No platform to sign up for. The interface is the deliverable.\n\nThe problem\n\n## You are thinking in dataflow. You are writing everything else.\n\nA trigger feeds a step, the step calls an agent, the output feeds another step, maybe a retry, then a sink. That picture is simple. But the moment you open an editor, the language makes you manage machinery that has nothing to do with it.\n\n### What you actually mean\n\n- The trigger fires on a GitHub issue.\n- The step drafts a reply.\n- The reviewer approves or sends it back.\n- The sink pings the team on Slack.\n\n### What the language asks about\n\n- `class` hierarchies & metaclasses\n- interface satisfaction & goroutine lifecycle\n- ownership, borrowing, lifetimes\n- the event loop, the DI wiring, the framework\n\n        When the language fits the domain, the code becomes a direct\n        translation of intent. Everything else follows from that.\n      \n\nThe whole vocabulary\n\n## Eight concepts. No spare parts.\n\nEvery idea earns its place by being needed to describe how work flows through a graph. This is the entire language.\n\n### Type\n\nStructural records. Fields and shapes — no classes, inheritance, or constructors.\n\n```\ntype Issue = { number: int }\n```\n\n### Trigger\n\nAdmits one seed value and holds it constant for the whole run. The host supplies the kind.\n\n```\ntrigger issue_opened:\n  kind: github\n  config: { path: \"/api/github/webhook\", target: { one: { repo: \"acme/widgets\" } } }\n```\n\n### Step\n\nWhere work happens. Invokes a unit and binds its typed outputs.\n\n```\nstep draft:\n  runner: agent\n```\n\n### Runner\n\nHow a step runs: a shell command, a container, or an agent behind a typed interface.\n\n```\nrunner agent:\n  kind: opencode\n```\n\n### Binding\n\nNamed edges that move values between ports. The bindings *are* the program.\n\n```\nin: { issue: in.issue }\n```\n\n### Loop\n\nA `prev` (loop-carried) binding re-fires a step with feedback — a retry, not control flow.\n\n```\nprev feedback: review.result\n```\n\n### Sink\n\nAn effect. Inside a loop it fires each pass; downstream it fires once.\n\n```\nsink result:\n  kind: file\n  config: { path: \"out/result.json\" }\n```\n\n### External port\n\nA bridge to the outside, implemented by the host. Secrets are opaque — redacted everywhere.\n\n``` php\nexternal port credential\n  (key: text) -> secret\n```\n\nAnatomy of a factory\n\n## One screen of code, read top to bottom.\n\n        The smallest factory that still shows the three things a factory is for:\n        a credential, an agent runner, and a review loop with a bounded retry.\n        **Pick a part** to see what it does.\n      \n\nThe execution model\n\n## A run is a round of firings until nothing can fire.\n\n        Press play. The trigger admits a GitHub issue, the loop runs ```\ndraft →\n        review\n```\n, the reviewer sends the draft back once, then approves.\n        The `progress` sink fires **inside** the loop —\n        once per pass — while `notify` waits downstream and fires\n        **once**.\n      \n\n**0**\n\nWhy a spec\n\n## Write the factory once. Host it anywhere.\n\n        The factory describes *what should happen*. The host supplies\n        *how*: which trigger kinds exist, which runner backends run, where\n        sinks write, how ports resolve. Those are adapter concerns — so they can\n        compete without locking in your workflows.\n      \n\ntrigger issue_opened: kind: github\n\nstep draft: runner: agent\n\nsink notify: kind: slack\n\n- **Local** — docker containers & the OpenCode server\n- **Cloudflare** — workers as steps, R2 as sink\n- **AWS / GCP** — Lambda/Batch steps, SQS triggers\n- **Your own** — register the kinds your domain needs\n\nThe spec defines the concepts; implementations follow. Tooling — validators, diagrammers, editors — can be built against the interface, independently of any one host.", "url": "https://wpnews.pro/news/dot-factory-a-spec-to-describe-complex-agentic-workflows", "canonical_source": "https://redbeardlab.github.io/dotFactory/", "published_at": "2026-10-18 05:11:32+00:00", "updated_at": "2026-10-18 06:13:25.059810+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "agent-protocols", "ai-tools"], "entities": ["dotFactory", "OpenCode", "Cloudflare", "AWS", "GCP", "GitHub", "Slack"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/dot-factory-a-spec-to-describe-complex-agentic-workflows", "markdown": "https://wpnews.pro/news/dot-factory-a-spec-to-describe-complex-agentic-workflows.md", "text": "https://wpnews.pro/news/dot-factory-a-spec-to-describe-complex-agentic-workflows.txt", "jsonld": "https://wpnews.pro/news/dot-factory-a-spec-to-describe-complex-agentic-workflows.jsonld"}}