{"slug": "show-hn-aqven-typed-llm-workflows-checked-before-a-token-is-spent", "title": "Show HN: AQVEN – typed LLM workflows, checked before a token is spent", "summary": "AQVEN, a source-available Python framework and local Studio for building typed LLM workflows, launched in alpha with a validation command that checks every connection and simulates every flow before any tokens are spent. AQVEN stores each workflow as typed files in a repository — a flow, one file per step, prompts in Markdown, and declared types, agents and tools — and connects to coding agents including Claude Code and Codex through its MCP server, which registers via a generated .mcp.json. The framework requires Python >=3.14,<3.15 and installs via `uv tool install aqven`; real runs spend against an OPENROUTER_API_KEY, while `aqven check` needs neither a key nor the network.", "body_md": "AQVEN is a Python framework and a local Studio for building reliable LLM workflows: multi-step pipelines of models, tools and human review.\n\nYour coding agent runs the experiments. You see the evidence and decide.\n\n**[Documentation](https://aqvenstudio.com)** · **[Quickstart](https://aqvenstudio.com/start/quickstart/)** · **[Use cases](https://aqvenstudio.com/use-cases/)** · **[Studio](https://aqvenstudio.com/studio/)** · [llms.txt](https://aqvenstudio.com/llms.txt)\n\nAQVEN keeps an AI workflow as typed files in your repository: a flow, one file per step, prompts in\nMarkdown, and declared types, agents and tools. `aqven check` validates every connection and simulates\nevery flow before you spend a token. Studio, a local browser app in the same install, shows each run\nstep by step. Your coding agent (Claude Code, Codex or any MCP client) works on the same files through AQVEN's\nMCP server, and runs experiments whose verdicts AQVEN computes.\n\nNote\n\nAQVEN is in alpha: expect changes between releases. It is source-available, not open source. See\n[License](#license).\n\n| **[Find](https://aqvenstudio.com/use-cases/#find)** | *\"What am I missing?\"* Your agent explores cases and variants you wouldn't try yourself. | \n| **[Explain](https://aqvenstudio.com/use-cases/#explain)** | *\"Why did this fail?\"* Follow a bad answer back to the step where it started. | \n| **[Compare](https://aqvenstudio.com/use-cases/#compare)** | *\"What should I change?\"* Models and prompts side by side, with cost and latency. | \n| **[Confirm](https://aqvenstudio.com/use-cases/#confirm)** | *\"Can I trust this change?\"* A verdict on held-out cases that is allowed to say inconclusive. | \n| **[Build](https://aqvenstudio.com/use-cases/#build)** | *\"How do I keep it readable as it grows?\"* Typed files in your repo, checked before a run costs a token. | \n\nYou need [uv](https://docs.astral.sh/uv/getting-started/installation/). AQVEN runs on Python 3.14,\nand uv fetches it for you.\n\n```\nuv tool install aqven\naqven new my_project --template minimal --provider openrouter\n```\n\n`aqven new` writes the project, installs its environment with `uv sync` and generates typed Python\nmodels. It also prepares the project for a coding agent: `AGENTS.md`, `CLAUDE.md`, an `.mcp.json` that\nregisters AQVEN's MCP server, and Claude Code hooks that run `aqven check` as the agent works.\n\nA real run needs a model key: copy `my_project/.env.example` to `my_project/.env` and set\n`OPENROUTER_API_KEY` in it. A run spends against whichever key it finds, in `.env` or exported in\nyour shell, so a real run is never free. `aqven check` needs neither a key nor the network.\n\n| Platform | Status | \n|---|---|\n| Linux | The full CI suite runs on `ubuntu-latest` on every change. | \n| macOS | Primary development platform. The install path and the offline `aqven check` are smoke-tested from a built wheel by the Platform smoke workflow; the full test suite is not yet run on macOS in CI. | \n| Windows | The install path is not yet proven: the Platform smoke workflow builds and installs the wheel on a Windows runner and runs `aqven check` , but nothing beyond that is tested there. If it breaks for you,[open an issue](https://github.com/lastonoga/AQVEN/issues) — help making AQVEN a proven Windows citizen is welcome. | \n\n**Python version policy.** AQVEN requires `>=3.14,<3.15`: the engine runs on exactly one minor\nversion, so step code behaves the same everywhere. uv fetches 3.14 for you. Python 3.15 was\nreleased in October 2026; support is planned, and it will land in a release when the engine, its\ndependencies and CI are green on it — we are not promising a date.\n\nStart Claude Code in the project and approve the `aqven` server when it asks:\n\n```\ncd my_project\nclaude\n```\n\nThen hand it a task. It builds the flow, runs `aqven check` after every change, and works in rounds:\n\n```\nBuild a flow that reads an incoming support e-mail and returns its intent (defect, delivery or question) and a one-line summary.\nDone means: the intent is right on more than 90% of held-out cases, and a case costs under $0.002.\nWork in rounds: explore on working cases, confirm once on held-out cases. Stop when every \"done\" criterion is confirmed, or when you have spent $5.\nThen report FINDINGS.md, the decisions you made and the risks that are left.\n```\n\nOpen Studio next to it to watch every run, or chat from there: its\n[chat panel](https://aqvenstudio.com/studio/chat/) runs Claude Code or Codex on the same project.\n\n```\nuv run aqven dev my_project\n```\n\nFor Codex, Cursor or another MCP client, see\n[How to set up a coding agent outside Studio](https://aqvenstudio.com/mcp-cli/set-up-an-agent-outside-studio/).\n`aqven new` already puts AQVEN's skills into the project; to have them in Claude Code everywhere, install\nthem as a plugin: `/plugin marketplace add lastonoga/AQVEN`, then `/plugin install aqven@aqven`.\n\nCheck the new project:\n\n```\ncd my_project\nuv run aqven check my_project\nerrors: 0, warnings: 0\n```\n\n`aqven check` validates every file, then simulates a run of every flow with stand-ins for the model\ncalls. Run it after every change. With a key in `.env`, run the flow for real, one line per event as it\nhappens:\n\n```\necho '{\"text\": \"How long does a light strip last?\", \"tone\": \"friendly\"}' > question.json\nuv run aqven run answer_question --root my_project --input question.json\n```\n\nThis is the project, trimmed to the files that define the workflow:\n\n```\nmy_project/\n  AGENTS.md  CLAUDE.md  .mcp.json  .claude/  pyproject.toml\n  my_project/\n    aqven.yaml\n    agents/assistant.yaml\n    tools/count_words.yaml\n    types/enums/tone.yaml  types/records/question.yaml  types/records/answer.yaml\n    flows/answer_question/\n      flow.yaml\n      nodes/prepare/  prepare.node.yaml  prepare.py\n      nodes/reply/    reply.node.yaml  reply.inference.yaml  reply.prompt.md\n```\n\n**`flows/answer_question/flow.yaml`** declares the input, the output and the order of the steps:\n\n```\napiVersion: \"aqven/v1\"\nkind: \"Flow\"\ndescription: \"Cleans up a question and answers it in the requested tone\"\ninput: \"Question\"\noutput: \"Answer\"\nreturns:\n- name: \"reply\"\n  from: \"$reply.out.reply\"\n- name: \"tone\"\n  from: \"$input.tone\"\norder:\n- \"prepare\"\n- \"reply\"\n```\n\n**`flows/answer_question/nodes/reply/reply.node.yaml`** is a model step. It takes `text` from the\n`prepare` step and `tone` from the flow input:\n\n```\napiVersion: \"aqven/v1\"\nkind: \"Node\"\nnode: \"llm\"\ndescription: \"Answers the prepared question with the assistant agent\"\nagent: \"assistant\"\nin:\n- name: \"text\"\n  from: \"$prepare.out.text\"\n- name: \"tone\"\n  from: \"$input.tone\"\n```\n\n**`reply.prompt.md`** is the prompt, a file of its own. `reply.inference.yaml` declares the typed input\nand output of the call.\n\n```\nAnswer the question in a {{ tone }} tone, in at most 120 words.\nIf you are not sure a draft fits, count its words with the count_words tool.\n<question>{{ text }}</question>\n{{ output_format }}\n```\n\nNow break one reference: change `$prepare.out.text` to `$prepare.out.txt` and check again.\n\n``` bash\n$ uv run aqven check my_project\nflows/answer_question/nodes/reply/reply.node.yaml:8:3: error E_REF_MISSING in[0].from: reference $prepare.out.txt: the value has no field txt\nerrors: 1, warnings: 0\n```\n\nThe check exits with code 1, so a hook or a CI job stops there. It also catches a value whose type\ndoesn't fit the slot (`E_BINDING_TYPE`), a prompt variable the inference doesn't declare\n(`E_PROMPT_VARIABLE_UNDECLARED`) and a `switch` that misses a case (`E_SWITCH_NOT_EXHAUSTIVE`).\n→ [All diagnostics](https://aqvenstudio.com/reference/diagnostics/)\n\nThe [quickstart](https://aqvenstudio.com/start/quickstart/) walks through AQVEN's full example,\n`--template showcase`: a support flow with every node kind, human approval and experiments.\n\nOne run proves one case, and `aqven check` proves the wiring. Neither says how the workflow behaves on\nreal inputs. The agent finds out in rounds, and you make the decisions:\n\n1. **You** set the goal, what \"done\" means in numbers, and a budget.\n2. **The agent** builds the simplest flow that works, writes cases with expected outputs, and runs`aqven check` after every change.\n3. **You** read the first traces it hands you, failing runs first, and note the first thing that went\nwrong in each.\n4. **The agent** groups your notes into failure modes you agree on, and writes one experiment per mode\nbefore any data.\n5. **The agent** explores on working cases, one change between series, then confirms once on held-out\ncases, the half of each dataset it never sees case by case. The server writes the verdict\n(`confirmed` ,`refuted` or`inconclusive` ), and the finding lands in`FINDINGS.md` .\n6. **You** decide which limits are requirements, how much quality a cheaper step may lose, and any spend\nabove the project cap. An agent can start a series but never approve its spend.\n\nA verdict holds for the cases, checks and versions it measured. It is evidence for a decision, not a guarantee about every future output.\n\n→ [A day with AQVEN](https://aqvenstudio.com/start/a-day-with-aqven/) ·\n[How an agent takes a task through the research loop](https://aqvenstudio.com/mcp-cli/research-loop/)\n\n| Part | What it is | \n|---|---|\n| **[Flows and nodes](https://aqvenstudio.com/concepts/ten-kinds-of-nodes/)** | Ten node kinds — `llm` ,`code` ,`tool` ,`human` ,`switch` ,`parallel` ,`map` ,`loop` ,`call` ,`narrow` — composed into a typed graph | \n| **[Types](https://aqvenstudio.com/reference/types/)** | Records, enums, unions, IDs, values and media, checked at every boundary. A model can't return a field that isn't declared | \n| **[Prompts](https://aqvenstudio.com/concepts/three-prompt-levels/)** | Plain text, Liquid templates with shared fragments, or a Python function. Always a file of its own, never a string inside YAML | \n| **[Agents and providers](https://aqvenstudio.com/integrations/model-providers/)** | An agent is a model with its settings and output mode, in its own file. The [provider catalog](https://aqvenstudio.com/reference/provider-catalog/) has 28 entries through Pydantic AI, from OpenAI, Anthropic and Google to OpenRouter, Mistral, DeepSeek, Groq and Ollama | \n| **[Tools](https://aqvenstudio.com/engine/tool-node/)** | Python functions or MCP servers, with a declared `read` ,`write` or`external` effect | \n| **[Human review](https://aqvenstudio.com/engine/human-node/)** | A step that waits on a person, with a timeout and a default | \n| **[Cases](https://aqvenstudio.com/reference/datasets/)** | Datasets of tagged cases with expected outputs, split by a hash of each name into working and held-out halves | \n| **[Experiments and findings](https://aqvenstudio.com/engine/experiments/)** | An experiment writes one question down before any data. A series answers it across variants and cases. A verdict on held-out cases becomes a finding in `FINDINGS.md` | \n| **[Durable execution](https://aqvenstudio.com/concepts/run-survives-a-crash/)** | A run survives a crash and resumes where it left off | \n| **[Studio](https://aqvenstudio.com/studio/)** | The local browser app. **Flow** shows a workflow's graph, runs and cases.**Research** shows experiments and series, and launches a series to**Explore** or**Confirm** | \n| **[MCP server](https://aqvenstudio.com/mcp-cli/)** | The same tools Studio's chat uses, for any MCP client: `flow_patch` for cross-file edits,`aqven_check` ,`prompt_preview` ,`run_start` ,`series_start` and more | \n\n- **One prompt, one model call.** Call the model's SDK directly; a flow adds files you don't need.\n- **You only want to trace an app you already have.** AQVEN runs workflows written in its own files. A\ntracing tool fits better.\n- **You need a hosted service for a team.** AQVEN runs locally, on your machine.\n- **You can't run Python 3.14.** The engine requires exactly 3.14, and your step code runs on it\n(see[Tested platforms](#tested-platforms) for the version policy).\n- **You need an OSI-approved open-source license.** AQVEN is source-available.\n\n|  | Tracing tools | Visual builders | AQVEN | \n|---|---|---|---|\n| Where the logic lives | Your code | Their platform | Files in your repo | \n| Checked before it runs | No | No | Yes | \n| Yours if the vendor disappears | Yes | No | Yes | \n| Adds to the app you already have | Yes | No | No: the workflow moves into AQVEN files | \n\nTracing tools means products such as Langfuse, LangSmith and Arize Phoenix. Visual builders means products such as n8n, Dify and Flowise.\n\n[Pydantic AI](https://ai.pydantic.dev/) calls the models, [DBOS](https://www.dbos.dev/) checkpoints\nevery run on SQLite, the official [MCP Python SDK](https://github.com/modelcontextprotocol/python-sdk)\nserves and consumes MCP, [FastAPI](https://fastapi.tiangolo.com/) serves Studio and the API, and\n[python-liquid](https://jg-rp.github.io/liquid/) renders prompt templates.\n→ [What this is built on](https://aqvenstudio.com/concepts/what-this-is-built-on/)\n\n**What is AQVEN?** A Python framework and a local Studio for building reliable LLM workflows. A workflow is\na set of typed files in your repository: a flow, one file per step, prompts in Markdown, and declared\ntypes, agents and tools. AQVEN checks the files before a run, runs the flow with checkpoints, and runs\nexperiments on cases to tell you whether a change helped.\n\n**Is AQVEN open source?** No. It is source-available under the AQVEN License 1.0.0, which is based on the\nPolyForm Shield License 1.0.0. You may use it for any purpose, including production and commercial\nproducts, and the workflows you build are yours to sell. You may not use it to provide a product that\ncompetes with AQVEN, and you may redistribute AQVEN itself only free of charge and for a non-commercial\npurpose. See [License](#license).\n\n**Which Python version does it need?** Python 3.14. uv fetches it for you.\n\n**Which coding agents does it work with?** Claude Code and Codex, from Studio's chat or from your own\nterminal, and any other MCP client, such as Cursor, through AQVEN's MCP server.\n\n**Which model providers can I use?** The provider catalog has 28 entries through Pydantic AI, from OpenAI,\nAnthropic and Google to OpenRouter, Mistral, DeepSeek, Groq and Ollama.\n\n**Do I need an account or a hosted service?** No. AQVEN runs on your machine. `aqven check` needs neither a\nmodel key nor the network; a real run needs a key for the provider you choose.\n\n**What does `aqven check` do?** It validates every file, type reference, binding and prompt, then simulates\na run of every flow with stand-ins for the model calls, so most wiring mistakes surface before a run costs\na token.\n\n**Does a \"confirmed\" verdict guarantee quality?** No. A verdict holds for the cases, checks and versions it\nmeasured. It is evidence for a decision, not a guarantee about every future output.\n\n**How is AQVEN different from an eval library?** Eval libraries typically score the outputs of an app you\nalready have. AQVEN also holds the workflow itself as typed files that are checked before they run, and its\nexperiments write the question down before any data and give a verdict on held-out cases that is allowed\nto say \"inconclusive\". If you only need to score an existing app, an eval library is the lighter choice.\n\n- **Docs:**[aqvenstudio.com](https://aqvenstudio.com) . For an agent,[llms.txt](https://aqvenstudio.com/llms.txt) indexes every page in Markdown.\n- **Bugs and ideas:**[GitHub Issues](https://github.com/lastonoga/AQVEN/issues) .\n\nAQVEN is **source-available**, not open source, under the AQVEN License 1.0.0 — based on the\n[PolyForm Shield License 1.0.0](https://polyformproject.org/licenses/shield/1.0.0), with one\naddition.\n\n- **You may** use it for any purpose, including in production and in commercial products you build\nwith it: the AI workflows you create with AQVEN are yours, and selling them is explicitly permitted.\n- **You may not** use AQVEN — original or modified — to provide a product that competes with it.\n- **You may** redistribute copies of AQVEN itself only free of charge and for a non-commercial purpose.\nThe right to sell AQVEN itself stays with the licensor.\n\nCopyright Kirill Burkhanov. Full terms: [LICENSE](https://github.com/lastonoga/AQVEN/blob/main/LICENSE).", "url": "https://wpnews.pro/news/show-hn-aqven-typed-llm-workflows-checked-before-a-token-is-spent", "canonical_source": "https://github.com/lastonoga/AQVEN", "published_at": "2026-10-29 11:56:19+00:00", "updated_at": "2026-10-29 12:19:08.454338+00:00", "lang": "en", "topics": ["ai-agents", "developer-tools", "large-language-models", "agent-protocols", "ai-tools"], "entities": ["AQVEN", "Claude Code", "Codex", "OpenRouter", "uv", "Python 3.14", "MCP"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/show-hn-aqven-typed-llm-workflows-checked-before-a-token-is-spent", "markdown": "https://wpnews.pro/news/show-hn-aqven-typed-llm-workflows-checked-before-a-token-is-spent.md", "text": "https://wpnews.pro/news/show-hn-aqven-typed-llm-workflows-checked-before-a-token-is-spent.txt", "jsonld": "https://wpnews.pro/news/show-hn-aqven-typed-llm-workflows-checked-before-a-token-is-spent.jsonld"}}