#Languages
Anvil wraps JavaScript and TypeScript call sites. If your application is written in something else, nothing on this site protects it yet — and we won't imply otherwise.
That's the short answer. Below: exactly what "JavaScript or TypeScript" covers, which parts of Anvil never look at your language at all, and how to tell us which language you need.
#JavaScript and TypeScript — supported today
| The piece | What it needs |
|---|---|
@useanvil/sdk runtime — wrap, safe.protect, guard, key | Node.js 20 or newer |
anvil protect — finds the risky call and writes the wrap for you | .ts · .tsx · .js · .jsx |
| VS Code / Cursor extension — the Protect with Anvil CodeLens | TypeScript, JavaScript, TSX, JSX files |
Auto-instrumentation — node --import @useanvil/sdk/init | Node.js 20 or newer and one of four covered packages — your source is never read |
| Dashboard, Policy Studio, decision log, receipts, approvals | Nothing — it's a web app |
Those four extensions are the whole list. anvil protect and anvil remove walk exactly the same set — deliberately, so an unwrap can never miss a call site the wrap found — and a call in .mjs or .cjs is simply invisible to them. You get no calls found rather than an error, which reads like a broken tool and isn't one. Two ways through: the startup flag below, which never reads your source, or safe.protect by hand. Both are spelled out in when the codemod can't find your call.
One of those rows isn't about your source at all. Auto-instrumentation patches a covered package's own prototypes at startup, so Anvil can protect a call it has never parsed — in a plain-JavaScript service, in code that ships bundled or transpiled, in a file the codemod can't make sense of. What decides coverage there is your dependencies and your runtime, not your file extensions.
Four packages are covered today — money, deletion, and messaging:
| Package | Tested versions | Calls it covers |
|---|---|---|
stripe | 12–18 | refunds.create · charges.create · payouts.create · transfers.create |
@octokit/rest | 21–22 | rest.repos.delete · rest.git.deleteRef |
twilio | 5–6 | messages.create |
resend | 5–6 | emails.send |
Eight calls across four packages, stable releases only — that is the whole list, and everything else on this page applies as written. Outside a tested range Anvil declines to patch and reports the version it found, rather than guessing at code that moves money or deletes a repository.
Those are package names, not vendor names. Coverage binds the exact module in the left column. @octokit/rest is covered; the umbrella octokit, @octokit/core with plugins, and @actions/github each load a different module and get nothing. Anvil reports them as absent rather than claiming them — but the names are close enough that it's worth checking which one your package.json actually has.
Bundling your own code is fine; inlining a covered package is not. The hook patches module loads, by name — which is why it never needs your source, and why it has nothing to hold onto when stripe itself ends up inside your output file. Nothing is patched, nothing is reported, and anvil doctor is the only place it shows — everywhere else the call simply runs as it always did. Keep covered packages external to the bundle, or wrap those call sites by hand.
Node 20 is what Anvil is built, tested, and deployed on; that's the one we vouch for. Newer majors generally work. Other JavaScript runtimes — Deno, Bun, edge runtimes — are untested, and there is no browser build: Anvil runs server-side, next to the call that moves the money.
One version line inside Node 20 decides auto-instrumentation. The ESM half of the hook needs module.register(), which arrived in Node 20.6. Below that the CommonJS hook still installs, so a require('stripe') app is fully covered; an ESM app on such a Node is reported as covering nothing rather than quietly half-working. The runtime, wrap and safe.protect are unaffected — this is the startup flag only.
ESM or CommonJS, either one. The package ships both builds: import resolves the ESM entry, require('@useanvil/sdk') a real CommonJS one. anvil protect writes the binding in the form the file it is editing actually loads under, decided by Node's and TypeScript's own rules rather than a guess — which matters because CommonJS is still Node's default, and an import written into a CommonJS script is a hard SyntaxError. TypeScript resolves the root types under any moduleResolution. The subpaths — @useanvil/sdk/init, /policy-export, /integrations/, /sinks/ — are declared only in exports, so reaching their types needs moduleResolution: "bundler", "node16" or "nodenext"; on the older "node" setting they surface as cannot find module on an otherwise correct install.
#Python, Go, Ruby, Java — not supported yet
There is no Anvil SDK for Python, Go, Ruby, Java, C#, PHP, or Rust. Nothing to pip install, no module to go get, no codemod to run, no editor support. A risky call written in one of those languages is protected by nothing here.
anvil protect tells you this itself, rather than failing obscurely. Run it in a non-JavaScript project and it reads the manifests around it — pyproject.toml, requirements.txt, go.mod, Gemfile, pom.xml, composer.json, Cargo.toml, a .csproj — names the language it found, and stops, with the same answer this page gives. Then it offers the two things that are useful from there: the address to register the language, and a way to point it at another folder, for the common case where the JavaScript is elsewhere in the same repo.
The agent integrations are JavaScript too. @useanvil/sdk/integrations/langchain binds @langchain/core and /integrations/vercel-ai binds ai — both the JavaScript packages. LangChain for Python is a different package and they do not touch it, so the integrations list is not a way in either.
We're not going to hand you a date we can't keep. What decides the order is who asks — see Tell us which language you need.
#What isn't language-specific
Roughly half of Anvil never reads your source code at all:
- the control plane that resolves each action's mode and returns the verdict,
- the dashboard, Policy Studio, and the decision log,
- spend caps, human approvals, receipts, and the audit chain.
All of it speaks HTTP — POST /v1/guard, POST /v1/complete, GET /v1/modes — and knows nothing about the language on the other end. What's JavaScript-only is the edge: the runtime, the codemod that rewrites your call, the risky-call detector, and the editor wiring. That split is why a second language is a port rather than a rewrite.
One rule breaks that split: custom-code rules are TypeScript, and they run in your process rather than on the plane. Every other rule primitive is evaluated server-side.
#If part of your stack is JavaScript
A common shape: a Node or Next.js service in front of a Python worker. Wrap the call your JavaScript makes — including the request into that worker — and it behaves like any other action: deduped on a key you choose, held for approval when a rule says so, recorded in the decision log.
Be precise about what that buys. Anvil governs that hop. Whatever the Python service then does on its own — a second charge, a retry inside its own loop, a payout on a schedule — Anvil never sees and never stops. Partial coverage you can name is worth having. A wrap you believe covers more than it does is worth less than none.
#Tell us which language you need
Email henry@anvilcontrol.ai with the language, and — if you can spare the line — the call you'd wrap first: a Stripe charge, a boto3 delete, an agent tool call.
We count them. Python is the only language with a build plan written behind it, and it gets built when the asking is real — not before. No date, and no promise yours is next. You'll get a reply from the person who read it.