IngotError
UpdatedThe rule behind this error is on the Ingots page.
An ingot is an Alloy extension. It ships as an executable beside an ingot.toml, and the compiler and the language server start it once and keep it alive. Over a framed pipe, one request per file, an ingot can:
Name one in alloy.toml. A path is relative to the root; a repo is a GitHub release that unpacks into .alloy/ingots/<name>/<version>/:
[ingots] tailwind = "ingots/tailwind" logger = { repo = "someone/logger-ingot" } # the latest release sorter = { repo = "someone/sorter-ingot", version = "0.2.0" } # this release, for good [ingot.tailwind] # the ingot's own options, over the defaults its manifest declares sort_classes = true
Install and update. version is ^ when the key is absent, which means the latest release, resolved once when the ingot is installed. A version, 1.2.3 or v1.2.3, pins that release and never moves.
alloy ingot install # fetch every ingot the project declares and does not have alloy ingot install logger # fetch that one alloy ingot update # re-resolve every `^` to the latest release and fetch it alloy ingot update logger # that one; a pinned version is left alone, and says so
A build fetches nothing. An ingot that is not in the store is a report that names alloy ingot install, so no build reaches the network on its own.
.alloy/ingots.lock records what is installed: the repo, the release, and what alloy.toml asked for. It holds no paths, so it reads the same on Windows and on unix. Keep it in version control and every machine builds against the same releases until an update runs; .alloy/.gitignore keeps the store itself out. The asset in a release is <name>-ingot-<target>.zip, then <name>-ingot.zip; an asset key names another. The targets are linux-x64, linux-arm64, macos-x64, macos-arm64, and windows-x64. curl, wget, or PowerShell does the download, whichever the machine has.
The manifest names the ingot, the protocol revision, the hooks the host may send, the options with their defaults, and the lints with their levels:
name = "tailwind" api = 1 hooks = ["transform", "lint", "hover", "complete"] run = "first" # the pass its transform runs in: first, last, or a number kinds = ["alx"] # the file kinds it wants; unset means all [options] sort_classes = false [lints.unknown_class] default = "warn" summary = "a class no utility defines" [props] ClassName = { doc = "the utility list", insert = "ClassName=\"$1\"" }
[props] names the props the ingot reads on a markup tag; the editor completes them on any tag of a file kind the ingot wants, and a bare string is the prop's doc.
A completion reply may ask for the editor's own markup list. merge adds that list after the ingot's items, hide_roblox leaves the Roblox classes, properties, and events out of it, and class completes an attribute slot as that Roblox class, for a tag the ingot rewrites into one. Init names every ingot the project loads, in ingots, so one ingot can work with another.
An ingot's lint is <ingot>/<lint> in [lint], and the ingot's name is a group, so allow = ["tailwind"] silences all of them. An option written as { default = false, doc = "..." } carries its text into the editor: alloy build writes the project's schema, .alloy/alloy.schema.json, with every ingot's options and lint names, and the #:schema line at the top of alloy.toml makes the editor complete them. alloy lint --list shows them under the ingot; alloy doc tailwind/unknown_class explains one.
Write one in Rust with the alloy-ingot crate: implement Handler, call serve. alloy ingot new <name> writes the project, alloy ingot info <dir> prints what a manifest declares, and alloy ingot run <dir> <file> pushes one file through it with the options of the nearest alloy.toml. It reports each edit the host refuses, such as one that adds a line, since that breaks the map, and exits with 1. An edit is a byte span and its text; the host applies every edit of one reply at once, so no edit sees another's output. Stdout carries the frames, so an ingot writes its logs to stderr; text on stdout stops it. An ingot that hangs or crashes costs one request: the host reports the loss and starts it again for the next request. After three hangs it stays down until a reload.
The design follows larvae's native worms. Nothing is embedded: no interpreter, no wasm.
