lloyAlloy on GitHub
alloy init
Docs

alloy init

Updated

Writes alloy.toml in the working folder, and one Luau configuration.

neither file       writes .config.luau: strict mode and alloy = "./build/alloy"
.config.luau       adds the mode and the alias to it, only where they are absent
.luaurc            adds them to it, and writes no .config.luau

The edit keeps every other key and every comment, so a file you wrote stays as you wrote it. With both files present, .config.luau is the one edited, as Luau reads it first. alloy init fails when alloy.toml is already there.

The @alloy alias names the runtime the build writes to the output root. Emitted code requires it by that alias only when [emit] std_require says so; the default is a relative path, or the runtime's instance path when the DataModel tree holds the file (alloy doc mount).

A new project needs no project file to build. Add a default.project.json, or a [mount] table, when the sources have to land somewhere in the DataModel.

The wizard

alloy init in a terminal opens the wizard. A script, a pipe and a CI job have no terminal to answer with, so they read the files above and never wait for a key. --non-interactive forces the plain path and wins over every other flag, so a script that passes it reads one thing. -i or --interactive asks for the wizard where one is not opened for you. The wizard needs a terminal and color: with NO_COLOR set, or with stdin on a pipe, it refuses and names the plain path, since a prompt that no one can answer is a hang.

The first question is one confirm:

Use the recommended setup?  (Y/n)

Yes asks nothing else. It writes a game, ember, lest, the temper preset, strict mode, and an AGENTS.md, and the report names every one of those, so nothing is guessed at. It assumes a game because that is the common case on Roblox, and the last line of the report says how to make a package instead. alloy init --yes, or -y, writes the same setup with no prompt at all, and needs no terminal, for a bootstrap script.

No opens the seven questions below, each one already on the recommended answer, so no means "let me change some of it" and enter alone walks the same setup:

What is this project?        game: src/client, src/server, src/shared, the
                             matching [mount] entries, sourcemap on, a .gitignore
                             package: src alone, no mounts, sourcemap and
                             source_of_truth off
Project name?                [project] name; the folder's name is the default
Package manager?             ember writes ember.toml; pesde and wally write
                             their own, so alloy writes none; none writes nothing
Test runner?                 [test] lest. With none, `alloy test` still writes a
                             spec per @test and no runner runs them
Style preset?                the [fmt] and [lint] tables
Strict mode for every file?  languagemode in .config.luau
Agent guide?                 AGENTS.md, CLAUDE.md, both, or none: a file that
                             explains Alloy to a coding agent

Nothing is written until the last question is answered, so ctrl-c or esc at any prompt leaves the folder exactly as it was. Alloy runs no package manager and depends on none: the closing line names the one command to run next.

The agent guide

The guide tells a coding agent what Alloy is, the layout alloy.toml sets, and the commands to run. It holds the rules of alloy doc style word for word, so the guide and the article cannot drift. It ends with the two ways to look a topic up: alloy doc <topic>, and alloy mcp with the line that registers it, claude mcp add alloy -- alloy mcp. A guide that is already in the folder stays as it is, and the report says so.

The style presets

Three ship with Alloy, named for what heat does to metal. temper is the one preselected.

anneal   soft. The formatter's own layout, [lint] recommended and strict both
         off, and correctness denied. For a port or a spike
temper   balanced. What alloy init writes: the [fmt] defaults written out, and
         [lint] recommended and strict both on
forge    hard. column_width 80, force-double quotes, sorted requires by kind,
         expanded imports, aligned struct fields, method call chains; strict on,
         naming on, and both documentation lints on

Your own presets

A preset is a TOML file holding a [fmt] table, a [lint] table, or both, and nothing else. The file name is the name the wizard shows. Two folders are read:

~/.alloy/presets/*.toml      yours, beside the toolchain alloy self install writes
.alloy/presets/*.toml        the project's own, for a team to commit

A file that takes a built-in name replaces that preset, so a team can redefine temper and still see one entry in the list. A file that does not parse, or that writes another table such as [build], is not listed: the wizard splices the text into alloy.toml, and a second [build] there would not read.

alloy.tomlalloy.toml
# ~/.alloy/presets/house.toml
[fmt]
recommended = true
column_width = 72
indent_type = "tabs"

[lint]
recommended = true
strict = false

[lint.rules]
naming = "warn"

alloy doc fmt lists every [fmt] key and alloy doc lint every [lint] key, so a preset can only hold what those two tables hold.