AItelier makes multi-agent AI pipelines deterministic and fully auditable — define a pipeline, run it, and inspect why it did everything it did. Today that's an open engine (SkillFlow, MIT, on PyPI as skillflow-py) plus a flagship software-delivery pipeline; the broader no-code workflow platform is on the roadmap.
Why AItelier
Most "AI agent" tooling is built for demos, not trust. The tools that build software or automate a workflow for you are non-deterministic black boxes: you can't reproduce a run, audit why the agent did what it did, or insert a human approval where it matters. That's exactly the wall that stops agents from being deployed in anything serious — regulated industries, enterprise, anywhere "it usually works" isn't good enough.
AItelier is built on the opposite premise — that an autonomous pipeline should be trustworthy by construction:
- Deterministic — pipelines are graphs (DAGs) traversed by the engine, not control flow improvised by an LLM. Same config, same path. Loops, gates, retries, and recovery are the engine's job, not the model's.
- Minimal LLM surface (least privilege) — each agent sees only the context it declares, and the SkillFlow engine generates a constrained write tool per declared output (and gates reads to declared context) — so an agent cannot read or write a file outside its contract. Concretely in the software pipeline: the Researcher can only search the web; every other role can write only its own declared output (a design doc, a plan, a review verdict, or the project README) — and only the Implementer's outputs are code. The model makes the judgment calls; the framework and its generated tools do everything deterministic — brain to brain, tools to tools. It's also why cheap models suffice: small, focused, role-scoped context.
- Fully traceable — every run keeps an append-only audit trace that is never deleted: each step, prompt, model response, and tool call. "Why did this run do that?" is one query, not forensic archaeology.
- Human-in-the-loop — approval/reject checkpoints are first-class between stages; review and send work back with feedback at any point.
- Adversarial quality — every step is produced by a Green (Maker) agent and reviewed by a Red (Checker) agent before it advances.
- Config-agnostic — a pipeline can be anything. Nothing about the engine is hardcoded to one workflow; SkillFlow can even generate a new pipeline from a plain-language description.
What you can build
The vision (see Project status for exactly what's built today vs. what's planned).
AItelier is meant to be used two ways:
- Run the flagship software pipeline (DPE) — ✅ works today. Describe a project; it researches, architects, plans, implements, and verifies it end-to-end, with human checkpoints and a complete trace. (That's the demos below.)
- Build your own auditable workflow — just describe it — ✅ works today. Pipelines aren't limited to software. Describe a workflow in chat and AItelier's grounded generator turns it into a real SkillFlow pipeline — provisioning any missing tools, wiring and gating the graph, and registering it to run by name (see Generate a workflow from a description). You can still hand-author YAML directly; a no-code visual builder and managed workspaces are on the roadmap.
Why software-delivery is the wedge and the keystone. We lead with autonomous software-building because it's the hardest possible proof the engine works — and because an AI workflow is software (a pipeline is a graph plus tools plus templates). The same deterministic factory that builds software is what will let you trust a workflow you build on AItelier — building a new auditable workflow is itself a software-engineering task. A trusted software pipeline builds trusted workflows.
Open source. SkillFlow is the engine and is embeddable in any agent system; AItelier is the host application around it. Both are MIT (see License); a managed multi-tenant platform is on the roadmap.
Project status
Honest, current state — so nothing here reads as more finished than it is.
Legend: ✅ Available today (built & tested) · 🚧 Roadmap (designed, not built) · 🔭 Long-term vision
| Capability | Status |
|---|---|
| Flagship DPE software pipeline — research → architect → plan → implement → verify | ✅ Available today |
| Green/Red adversarial review · human approve/reject-with-feedback checkpoints · autonomous goal-loop | ✅ Available today |
| Append-only trace + trace API · Git event-sourcing · Rich CLI/TUI | ✅ Available today |
| Runs on the SkillFlow engine (deterministic DAG execution, tools, checkpoints, durable trace) | ✅ Available today |
| Generate a pipeline from a plain-language description — grounded generator provisions missing tools, wires + gates the graph, registers it to run by name | ✅ Available today |
| MCP endpoint + DeepSeek Harness plugin — drive AItelier from any MCP-speaking agent: list / edit / run / export / import pipelines as native tools | ✅ Available today |
| Final verifier runs the generated app (runtime smoke-test) | 🚧 Roadmap — today it reviews code statically and can miss runtime bugs |
| No-code visual workflow builder · managed multi-tenant SaaS · collaboration & compliance tooling | 🚧 Roadmap |
| Horizontal expansion beyond software delivery, on the same engine | 🔭 Vision |
Where the company is: the engine and the flagship pipeline are built and tested; there are no users, revenue, or managed platform yet. This is a working foundation, not a finished product.
Install
Requires Python 3.12+ (check with python3 --version; on macOS the system python3 is often older — use a 3.12 venv).
python3.12 -m venv .venv && source .venv/bin/activate
# Install AItelier (the skillflow-py framework is pulled from PyPI automatically)
pip install -e .
Quick Start
First, pick your providers. AItelier is provider-agnostic in two layers, and both are deployment config, not repo content — they are gitignored like .env, and what ships is an example:
cp llm_providers.example.json llm_providers.json # which vendors, which endpoints, which key names
cp model_routes.example.json model_routes.json # which of them serves each internal model
The internal model names are the contract — agent_configs/*.yaml and the vision gate reference flash / pro / glm / smart / vision, so those keys must exist in model_routes.json. Which endpoints sit behind them is entirely yours to choose; the examples are one operator's answer, not a requirement. Nothing in the code names a vendor.
Both files fall back to their .example if you skip this, so a fresh clone runs — but then you are running on someone else's provider list, and it is worth ten seconds to say which vendors are actually yours.
The internal models, and what each is for
model_routes.json must define these names. What sits behind them is your choice; what they are FOR is fixed, because the pipelines and tools pick by job:
| name | used by | what it has to be |
|---|---|---|
flash |
most maker and reviewer roles — the bulk of every run | cheap and fast. This is where the token budget goes, so a costly model here is felt everywhere |
pro |
the PM, and roles whose output the rest of the run is built on | a stronger generalist |
glm |
the architect, the final verifier, long-form authored documents | an alternative strong generalist |
smart |
offered to generated pipelines for judges and architects | strong at one-shot reasoning; not for long agentic tool loops |
vision |
the Godot readability gate (godot_vision) |
must accept image input — verify with a real frame, not a model card |
Two rules the code enforces rather than trusts:
- Every route should end with a pay-as-you-go endpoint. Token plans run out; the last candidate is what turns "everything stops until the window resets" into "the next call goes elsewhere". A spent plan is parked until the provider's own reset time, so the list is consumed in order.
- Failover is sticky per step, never per call. Provider prefix caches are per-provider, and this workload measures 26:1 prefill:decode at an 89.4% hit rate — alternating endpoints mid-step converts cached input into full-price input and costs more than a second plan saves.
Check what your table implies before running:
python -c "from core.external_deps import required_llm_keys, failover_llm_keys; \
print('required:', required_llm_keys()); print('failover:', failover_llm_keys())"
required is the first candidate of each route — the endpoints a run actually binds to. failover is everything behind them: not needed to start, needed for an outage to be a slowdown instead of a stop. Out of the box the key you need is ARK_API_KEY. Ask the code rather than trusting this sentence:
python -c "from core.external_deps import required_llm_keys, failover_llm_keys; \
print('required:', required_llm_keys()); print('failover:', failover_llm_keys())"
DEEPSEEK_API_KEY shows up as failover, not required: the shipped routes try Ark first and fall through to DeepSeek direct on a dead key, a spent token plan, a 429 or a 5xx. You can run on one provider — but with only one, a spent plan parks the whole scheduler until the window reopens, whereas a second candidate just picks up the next call. Failover is sticky per step, never round-robin, so it does not cost you the provider prefix cache.
Keys are secret FILES, not environment variables — so the test and build subprocesses a pipeline runs cannot inherit them:
mkdir -p ~/.aitelier-secrets && chmod 700 ~/.aitelier-secrets
printf '%s' "<your-key>" > ~/.aitelier-secrets/ARK_API_KEY
chmod 600 ~/.aitelier-secrets/ARK_API_KEY
cp .env.example .env # endpoints and options; NOT the keys
To use a different provider, add it to llm_providers.json and point the agent configs at it — see docs/external-dependencies.md. A missing key fails naming the provider, the key and the file to create.
The backend runs in Docker, always — there is no host-process fallback, because a host process would make the pipeline's git commits carry your own
~/.gitconfigidentity.aitelierstarts the container for you (and creates the secret files it mounts).
aitelier # Interactive CLI dashboard
aitelier "build me a todo app" # One-shot pipeline
aitelier server # Backend container (start/reuse); --no-docker to run in-process
Run with Docker (+ Cloudflare)
The backend and web UI also ship as a container. The CLI starts it automatically if Docker is running (and reuses it if already up), or you can manage it directly:
docker compose up -d # multi-stage build (Node.js → Svelte bundle + Python runtime); serves API + web UI on :4444
docker compose logs -f
Compose mounts its API keys as secret files, and Docker refuses to start a
service whose secret source is missing. The CLI creates them for you; if you run
docker compose by hand, create them first (empty means "I don't use this"):
mkdir -p ~/.aitelier-secrets && chmod 700 ~/.aitelier-secrets
cd ~/.aitelier-secrets && touch DEEPSEEK_API_KEY ARK_API_KEY GITHUB_TOKEN LOCAL_QWEN_API_KEY && chmod 600 *
printf '%s' "<your-key>" > ~/.aitelier-secrets/ARK_API_KEY
Publishing through an existing cloudflared connector is one line. The network
lives in docker-compose.yml itself and is selected BY NAME, with no
external: and no -f overlay — there used to be one, and forgetting it on a
rebuild took the public path down while every container stayed healthy.
echo 'AITELIER_EDGE_NETWORK=cloudflare_edge' >> .env # docker network ls → your connector's
Confirm the name against docker network ls and against the network your
connector is actually on. A name that matches nothing is created, not
refused: the container comes up healthy, 127.0.0.1:4444 answers 200, and the
tunnel is dark with nothing logging an error. Leave the variable unset and
AItelier stays on loopback.
Other than that, a clean checkout starts with no pre-existing Docker resources.
Every capability that needs something outside this repo — the LLM key, web
search, media generation, the Godot gates — is optional, refuses with a message
naming the config it wants, and is listed in
docs/external-dependencies.md. For the whole path from an empty machine to a finished pipeline — every step, what can go wrong at it, and what covers it — see docs/install-route.md.
If a run looks stuck, read the scheduler tick log rather than the container
log. The scheduler advances one project per tick, so a project that cannot
advance blocks the others — and the tick log is where it says why:
grep 'outcome=claim_failed' ~/.AItelier/logs/scheduler_ticks.log
# project=my-project outcome=claim_failed run=2f6c30c4
# error=Required context source resolved to no content: finalize.
It rotates (5MB × 3) and lives on the mounted volume, so it survives container
recreation. One line per tick; outcomes are idle, locked, run_start_failed,
active_claim, terminal, claim_failed, no_claim, executed.
In Docker the API key is a secret file, not an env var (so the pipeline's test/build subprocesses never inherit it). Put the key outside the repo and mount it:
mkdir -p ~/.aitelier-secrets && chmod 700 ~/.aitelier-secrets
printf '%s' "<your-key>" > ~/.aitelier-secrets/ARK_API_KEY
chmod 600 ~/.aitelier-secrets/ARK_API_KEY # keys are FILES, never .env
State lives in host ~/.AItelier (bind-mounted). The port is published on loopback only; expose it publicly via a Cloudflare tunnel. With Cloudflare Access in front, reads are open to any logged-in user and writes are restricted to an allowlist — set AITELIER_CF_TEAM_DOMAIN, AITELIER_CF_AUD, and AITELIER_WRITERS in .env (all documented in .env.example). The CLI authenticates to its own container with AITELIER_ADMIN_TOKEN.
Demos
The flagship DPE pipeline planning, building, and reviewing a real e-commerce app — a customer storefront and an admin panel — end to end: 66 pipeline steps, 0 failures, entirely on cheap non-frontier models (DeepSeek — no GPT/Claude/Gemini in the loop). The hero GIF at the top and the trace below are from this run. Separately, when a bug report was later fed back in, AItelier diagnosed and fixed its own code (see below).
The generated app — customer storefront & admin panel (from a single goal, pure Python standard library)
📂 Browse the full generated source: linxuhao/aitelier-e-commerce-store-demo — every file was produced by the pipeline (the commit history is the build log); only its README is hand-written.
| Customer storefront | Admin panel |
|---|---|
![]() |
![]() |
Browse → cart → checkout → order confirmed, and admin login → dashboard → add / edit / delete.
Every decision is auditable — the trace API

1000+ durable records per run — every prompt, model response, tool call, and Green/Red review verdict — queryable by step or category.
What this run demonstrates
- The goal-loop fired autonomously (final verifier → back to planning → converged on the next pass) — not scripted.
- Re-pointed at the existing codebase with a bug report, AItelier diagnosed the root cause and authored the fix itself.
- The intelligence is in the orchestration, not the model bill — the whole pipeline runs on DeepSeek
v4-flash/v4-pro.
Honest caveat: the cart bug above slipped past the pipeline's verifier because it reviews code statically and doesn't yet run the app — see Project status and Roadmap. Finding it required running the app by hand; AItelier then fixed it.
See it in action
A typical run with the flagship DPE pipeline:
- Describe what you want. Tell the butler your goal. It picks one of two paths automatically:
- Path A — Pipeline Offload (fast): for small bug fixes or features (~5 files) on existing projects, offloads directly to a subagent/fix_tests/investigate pipeline — no requirements conversation needed.
- Path B — DPE (safe default): for new projects and non-trivial changes, asks scoping questions, drafts a project brief, and — once you approve — starts the full research → architect → plan → build pipeline.
- Watch it work, with checkpoints. Research → Architect → PM → per-task Plan/Implement/Review → Final Verification. It pauses at review checkpoints so you can approve or reject with feedback (e.g. "the design is missing input validation") and watch the agent revise.
- Inspect the trace. Every prompt, response, and tool call is in an append-only audit log — answer "why did it do that?" for any step, after the fact.
- Run the result. The generated project (code + tests + README) lands in your workspace, ready to run.
Generate a workflow from a description
Don't want to hand-write a pipeline? Describe it. ✅ Works today. In the butler's coding mode, the generate_pipeline tool turns a plain-language workflow into a real, runnable SkillFlow pipeline — grounded in the live tool registry, self-provisioning any tools it needs, and gated before it ships. No YAML by hand, no server restart.
- Describe it. "Make a pipeline that researches a topic, drafts a summary, then fact-checks it." The grounded
pipeline_forgegenerator surveys the real tool registry → designs the graph → builds and registers any missing tools → emits the config → passes a 3-part gate (lint + registry check + dry-run smoke) → pauses at a review checkpoint. - It's registered automatically. On approval the graph lands under a namespaced name like
gen_research_draft_factcheck(thegen_prefix can never clash with a built-in config). - Run it by name. "Run it on 'CRISPR gene editing'." → the butler launches it, and it shows up in the dashboards — and the trace — like any other run.
- Iterate in place. "Add a citation step and run it again." → re-describe it under the same name and it's updated in place; the next run uses the new version.
Every generated run gets the same deterministic execution, human checkpoints, and append-only trace as the flagship pipeline. Generated pipelines are stored as gitignored user data under ~/.AItelier/configs/, so they survive a restart but never land in the repo. This is the working core of the no-code workflow platform — the visual builder on top of it is still to come.
Use AItelier from another agent (MCP)
AItelier's backend exposes its whole pipeline surface as an MCP endpoint (/mcp, streamable HTTP) — so any MCP-speaking agent can use AItelier as a subagent: 30 tools covering the four artefact kinds (pipeline graph, agent roles, prompt templates, custom tools) with list / get / edit on each, plus:
run_pipeline+wait_for_run— start a run (returns immediately; runs are long and may pause for human approval) and block until it settles at a checkpoint, completion, or failure — push-based, no polling.- the full generate → drive → observe → fix loop —
generate_pipelinewrites a new pipeline,run_pipeline+wait_for_run+answer_checkpointdrive it,get_run_summaryand thetrace_*tools say what broke, and theedit_*tools fix it. AItelier's scheduler runs the pipeline; the external agent only decides at checkpoints and between runs. export_pipeline/import_pipeline— carry a generated pipeline between machines as one self-contained JSON bundle: its graph, its roles with their prompts, and any custom tool it needs. Import validates everything before writing, renames safely, and refuses to silently overwrite a same-named tool that differs.
Authorization is per tool, not per route: read tools are open, write tools require the same authorization as the web UI (Cloudflare Access allowlist, or AITELIER_ADMIN_TOKEN off-tunnel). Without credentials you get a legitimate read-only installation — write tools answer denied: … and change nothing.
For DeepSeek Harness (dsh) there's a ready plugin bundle in integrations/dsh/ — one command installs it into a profile and registers the tools as mcp__aitelier__*:
dsh plugin --profile headless add <path-to>/AItelier/integrations/dsh
echo 'AITELIER_MCP_URL=http://127.0.0.1:4444/mcp' >> ~/.dsh/.env # where your AItelier runs
Any other MCP host configures the same endpoint URL directly (streamable HTTP transport).
Configuration
To change which models or agents the pipeline uses, edit the config files directly:
llm_providers.json— LLM providers (base URLs, API-key env var names). Register a provider here before pointing an agent at it.agent_configs/— per-role model, template, tools, and thinking settings. Every agent's model is just a YAML field here: the DPE pipeline roles live indpe_default.yaml, and the chat butler / meta agent lives inmeta_conversation.yaml(meta_agent.model) — so the conversational front-end is configurable exactly like the pipeline roles.templates/— the LLM prompt templates each step usesAITELIER_HOST_AGENT_MODEL(env, defaultark/deepseek-v4-flash) — the model for skillflow host-delegated agents. A generated pipeline ships its agents asmodel:"host"with the prompt embedded; AItelier maps that single token to this one model, so you don't declare a per-role config for them (see Generate a workflow from a description).
How it works
AItelier defines its workflow as a SkillFlow graph of stateless agent steps. The SkillFlow engine owns traversal, tool execution, checkpoints, and the durable trace; AItelier supplies the agents, templates, tools, and UI.
Agents never hold state in memory. Each step receives its context from the outputs of prior steps, writes its results into a per-step staging directory that the engine validates and then promotes, and every promoted change is committed to Git (event sourcing) — so any run can be replayed or inspected after the fact. A scheduler drives the loop one step at a time: advance → claim → execute → confirm. The default DPE pipeline applies this to software delivery, but because a pipeline is just config, the same engine runs any auditable multi-agent workflow.
Architecture
AItelier is a host application on top of the SkillFlow framework:
- Configs (
configs/,agent_configs/) — pipeline graph and LLM agent definitions - Templates (
templates/) — per-step LLM system prompts - Tools (
aitelier/tools/) — AItelier custom tools + SkillFlow native tools - Core (
core/) — agents, scheduler, AI router, DB, workspace - API (
api/,web_api/) — the CLI backend, plus an early multi-tenant Web backend. Includes admin endpoints (/api/admin/) for user tracking with per-user delete, writer-only access via Cloudflare Access, and the MCP endpoint (api/mcp_router.py, served at/mcp) that exposes the pipeline surface to external agents. - Web (
web/) — Svelte 5 + Vite SPA, compiled toweb/dist/and served by FastAPI - CLI (
cli/) — Rich TUI dashboard
Meta Conversation (gather requirements)
→ DPE Pipeline:
Research → Architect → PM → [per task: Plan → Implement → Review]
→ Final Verification
Roadmap
Building on the foundation that works today (Project status above), in priority order.
🚧 Next (designed, not yet built)
- Runtime-verifying delivery — the final verifier reasons about code statically today; next it boots the generated app and smoke-tests it, so the goal-loop triggers on real runtime failures, not just static review.
- The managed platform — multi-tenant workspaces, a no-code visual workflow builder, shareable/managed runs, and the audit & compliance tooling teams need to deploy agents in production.
🔭 Longer-term (the bet, not a commitment)
- The open format as a standard — if SkillFlow's YAML becomes a common way to define agentic workflows, every config in the ecosystem runs natively here.
- Audit-first & EU-resident — position the immutable, never-deleted trace as the compliance-grade record that environments like the EU AI Act's traceability requirements demand.
Tests
pytest tests/unit/ -v # ~700 unit tests
pytest tests/integration/ -v # ~245 integration tests
pytest tests/ -v # full suite (~945 tests)
Web Frontend
The web UI is a Svelte 5 + Vite SPA (web/src/), replacing the original vanilla HTML/CSS/JS frontend. The compiled bundle (web/dist/) is served directly by the FastAPI backend.
cd web
npm install # install dependencies
npm run build # compile to web/dist/
npm test # run ~120 vitest tests (stores, lib, views)
npm run lint # ESLint + eslint-plugin-svelte
npm run dev # dev server with HMR
The frontend uses Svelte 5 runes ($props(), $state(), $derived()) throughout. Key libraries: marked (Markdown), DOMPurify (HTML sanitization), svelte-spa-router (client-side routing). The DPE pipeline's test step (run_tests, 5_test) gates node projects automatically: it finds package.json (root or one level deep, e.g. web/) and runs npm ci + npm run build + npm test, folding failures into the goal-loop.
i18n (Internationalization)
The app supports 8 languages: English (en), Simplified Chinese (zh-CN), Traditional Chinese (zh-TW), Japanese (ja), Korean (ko), French (fr), German (de), and Spanish (es). The i18n module (web/src/lib/i18n.svelte.ts) uses a Svelte 5 $state rune + langStore.subscribe() pattern to make the t() translation function reactive — switching languages in the AppBar dropdown triggers an automatic live re-render of all visible components, with no page navigation required.
node web/audit-i18n.mjs # verify all t() keys exist in all 8 languages
The persistent language store (web/src/stores/i18n.ts) syncs the user's selection to localStorage and the backend API (POST /api/settings/user/language).
License
AItelier is open source under the MIT license, as is the pipeline engine it runs on, SkillFlow.

