Built on Rust: real speed, not a slow graph
Weft compiles the graph to native Rust. One command starts it as a live service.
Our founder red-teamed AI since davinci for
▶ Meet Tangle

Left: a real request for a WhatsApp bot that transcribes voice notes. Right: the program Tangle built, running.
From an idea to a deployed product, without you steering each step.
30min
for Tangle to build what the best AI models take tens of hours to write alone.
Tells you the plan first
And asks you when there is a real choice to make.
Writes expert prompts and missing pieces
Expert-written prompts, and a new building block when none does the job.
Tests every piece
Every piece has run, and anything wrong has been fixed, before you see it.
Fixes a case and keeps it fixed
Give it a failing case. It fixes it, then freezes the right answer.
Builds the frontend
A site or an app that talks to your program.
Deploys it
On your own cloud, so it runs with your laptop closed.
Works with
▶ Try it

Install Weft to click around in yours.
▶ Scoped runs
Made-up values, a saved real input, or live services. Everything else is reused from the last run.
Fix a case that failed in production, then freeze the right answer. After any change, see exactly what moved.
Run a piece, read the result, fix, run again. That is how Tangle tests on its own.
▶ Why orchestration
Reliable
The program holds the job together, so no single model has to keep track of everything.
Smarter
Each model only sees its own step, so it does that step better.
Faster
Steps run side by side, where an agent goes one at a time.
Cheaper
At every move an agent re-reads the whole conversation, and you pay for it. Each step here pays once.
Who decides what happens
01 / 04
01 · Who decides what happens
Reliable
The program holds the job together, so no single model has to keep track of everything.
02 · How good the work is
Smarter
Each model only sees its own step, so it does that step better.
One agent juggling everything
Each step handed just its part
03 · How long it takes
Faster
Steps run side by side, where an agent goes one at a time.
04 · What it costs
Cheaper
At every move an agent re-reads the whole conversation, and you pay for it. Each step here pays once.
each call re-reads the whole conversation
each step reads only its own input
▶ Flexibility
A bare agent is just one step with the dial turned all the way up.
Orchestration · the same run, freedom set per step
Locked
does one exact thing
Full agent
anything can happen
Scoped agent
free, but only these tools
Locked
does one exact thing
turn the dial from pure logic, up to a full agent, anywhere in between
An agent · one step, freedom maxed everywhere
full freedom is the only setting, and it covers everything at once
▶ Comparison
Traditional languages
None was made for this. You fight the language
Visual flow builders
Locked to pre-made blocks
Tangle + Weft
Built for orchestration
Tangle + Weft
Built for orchestration
Traditional languages
You fight the language
Visual flow builders
Locked to pre-made blocks
An agent’s one edge is that it starts fast. Tangle builds so fast that building, then running, still beats it.
build + run, end to end, beats the agent in most real cases
▶ Custom tools
To the llm, buy is one tool. Inside, it’s the tiers, approvals and secure payment you built.
pick the next action to take
search the web for offers
ask the supplier a question
buy within the spending rules
route the order by its amount
under €100
buy now, capped €1k/hr
€100–1k
a teammate approves
over €1k
another team signs off
pay through the secure gateway
▶ Who it's for
Hobbyists & small businesses
Build the things that make your life easier
A phone line that books your clients, a bot that runs your store. Describe it and ship it the same day.
Vertical-AI & enterprises
Robust systems running at scale
You bring the domain expertise, we embed with your team. White-label it, run it on your own servers, audit every step.
▶ Humans
outreach · run
pauseddraft the email to this lead
approve or skip this lead
send the email once it's approved
Lead
Subject
Message
▶ Python vs Weft
import os, json, time, base64, threading, logging
from email.mime.text import MIMEText
from google.oauth2.credentials import Credentials
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
import anthropic, psycopg2, psycopg2.extras
from flask import Flask, request, render_template_string, abort
SCOPES = ["https://www.googleapis.com/auth/gmail.readonly", "https://www.googleapis.com/auth/gmail.send"]
log = logging.getLogger("inbox-bot")
app = Flask(__name__)
def gmail_service():
creds = Credentials.from_authorized_user_file("token.json", SCOPES) if os.path.exists("token.json") else None
if not creds or not creds.valid:
if creds and creds.expired and creds.refresh_token: creds.refresh(Request())
else: raise RuntimeError("run the oauth flow first") # TODO: who does this on the server?
open("token.json", "w").write(creds.to_json())
return build("gmail", "v1", credentials=creds, cache_discovery=False)
gmail, llm = gmail_service(), anthropic.Anthropic(api_key=os.environ["ANTHROPIC_API_KEY"])
db = psycopg2.connect(os.environ["DATABASE_URL"], cursor_factory=psycopg2.extras.RealDictCursor)
def decode_body(payload):
if payload.get("body", {}).get("data"): return base64.urlsafe_b64decode(payload["body"]["data"]).decode("utf-8", "replace")
for part in payload.get("parts", []) or []:
if part.get("mimeType") == "text/plain" and part["body"].get("data"): return decode_body(part)
for part in payload.get("parts", []) or []:
found = decode_body(part)
if found: return found # html only? strip tags? attachments?
return ""
def draft_reply(text, attempt=0):
try:
r = llm.messages.create(model="claude-sonnet-5-5", max_tokens=1024, messages=[{"role": "user", "content": text}])
return "".join(b.text for b in r.content if b.type == "text")
except (anthropic.RateLimitError, anthropic.APIConnectionError) as e:
if attempt >= 5: raise
time.sleep(2 ** attempt); return draft_reply(text, attempt + 1)
def poll_forever():
seen = {r["msg_id"] for r in query("SELECT msg_id FROM reviews")}
while True:
try:
res = gmail.users().messages().list(userId="me", q="label:inbox -from:me", maxResults=50).execute()
except HttpError as e:
log.warning("gmail list failed: %s", e); time.sleep(30); continue
for m in res.get("messages", []):
if m["id"] in seen: continue
msg = gmail.users().messages().get(userId="me", id=m["id"], format="full").execute()
headers = {h["name"].lower(): h["value"] for h in msg["payload"]["headers"]}
draft = draft_reply(decode_body(msg["payload"]))
execute("INSERT INTO reviews (msg_id, thread_id, sender, message_id, draft, status) VALUES (%s,%s,%s,%s,%s,'pending')",
(m["id"], msg["threadId"], headers.get("from"), headers.get("message-id"), draft))
seen.add(m["id"]); notify_reviewer(m["id"]) # slack? email? sms?
time.sleep(60)
@app.route("/review/<msg_id>", methods=["GET", "POST"])
def review(msg_id):
row = one("SELECT * FROM reviews WHERE msg_id = %s", (msg_id,)) or abort(404)
if request.method == "GET": return render_template_string(REVIEW_PAGE, row=row) # auth? csrf?
if request.form.get("decision") != "send": return mark(msg_id, "rejected")
reply = MIMEText(request.form["reply"])
reply["To"], reply["In-Reply-To"], reply["References"] = row["sender"], row["message_id"], row["message_id"]
raw = base64.urlsafe_b64encode(reply.as_bytes()).decode()
gmail.users().messages().send(userId="me", body={"raw": raw, "threadId": row["thread_id"]}).execute()
...
# query, execute, one, mark, notify_reviewer, REVIEW_PAGE, the
# schema, the deploy, restarts mid-review, a second worker, ...
... google = GoogleAccess email = GmailNewEmail { account: google.access query: "label:inbox -from:me"} draft = LlmInference -> (response: String) { prompt: email.body provider: OpenRouterProvider { model: "anthropic/claude-sonnet-5.5" }.provider params: LlmParams { systemPrompt: "Draft a short, friendly reply to this email." }.params} review = HumanQuery { fields: [ { "kind": "editable_textarea", "key": "reply" }, { "kind": "approve_reject", "key": "send" } ] reply: draft.response} send = GmailSend { _should_flow: review.send_approved account: google.access to: email.from replyTo: email.id text: review.reply}Fewer lines, so the AI builds faster and gets more right.
The compiler catches a broken system before it runs.
▶ Dynamic vocabulary
Blender on a GPU, a shared browser, your own API or model.
Its inputs and outputs, plus the Rust that does the work. Credentials, storage and run history come free.
It wires to any node whose types fit, and the compiler checks its wiring rules.
Against fakes on your machine, or live against the real service.
Nodes somebody built for their own job
render the scene on a GPU
keep a browser open to share
price the order with our rules
score the order with our model
▶ Folding
check for new leads every morning
look up the lead's company
decide whether the lead fits
draft the email to this lead
approve or edit the draft
send the email once it's approved
log the result in the CRM
Visual builders turn to spaghetti past twenty nodes. Weft folds, so it stays readable at any size.
Use the arrows on a group’s header to fold it or open it.
▶ And more
Weft compiles the graph to native Rust. One command starts it as a live service.
store the program's data in Postgres
started for you
Write pg = PostgresDatabase and the program gets a Postgres of its own, with no YAML to write.
your machine
Docker
your cloud
Serverless
Serverless workers that cost nothing while idle and scale up when work arrives. Tangle sets up the rest once you log in to Google Cloud and GitHub.
carry the caller's audio both ways
turn speech into text live
decide what to say back
read the answer aloud to the caller
In a phone-call agent, speech-to-text, the model and the voice all share one live bus. Every message is visible and replayable.
▶ Pricing
Price
$0
No plans, no seats, no usage meter
Self-hosted Weft stays free.
Fund development
If Weft is running your automations in production, put something back: one-time tips and monthly support both go straight into the build.
Fund on Ko-fi▶ Founder
I'm a software and ML engineer by training. The day ChatGPT came out I went full time on prompting and doing research on llm behavior. I spent the last three years breaking AI for a living: for Anthropic, OpenAI, METR, etc. The more I learned about how these models behave, the more I wanted to work on the system around them instead of the model itself.
Everyone is racing to get AI to actually do things now: act, call tools, run real processes. And we hand all of that to one agent and hope it carries the whole job from start to finish. Models are not there yet, and I don't want to wait years for them to catch up before AI can take on long, real jobs reliably.
Having built software for years, the answer is obvious to me: we need something shaped like a program, but with the same magic as an agent. A company already works this way: it chases one goal for years, even though each person only handles their own part and people come and go. Weft does the same in code. No model has to carry the whole job, because the program does, and it keeps going for days if it has to. Each agent or model call only gets a short job, the kind today's models already do well, so this works now instead of in a few years. And it's cheaper and faster than handing everything to one agent.
I believe this is the shape we'll all be building in a year, and no one else is looking here yet as a language design problem. Programming languages have always been the foundation on which the evolution of software has been built, and I believe right now is the time to build the one that will support this next generation of software.