Create any Link Loom project — a landing page, a webapp (client or admin), a backend monolith or a microservice — from generators with fixed standards. Built first for AI agents (a machine contract, JSON output, stable exit codes), with a real interactive terminal UI for people.
npx @link-loom/cli| Project type | Command | Status |
|---|---|---|
| Backend monolith | create service --shape monolith |
available |
| Microservice | create service --shape microservice |
available |
| Webapp (client / admin) | create webapp --variant client|admin, then add entity for each CRUD |
available |
| Landing page (Astro) | create landing, then add page, add section, add blog-post |
available |
| StoneOS app | — | planned |
Agent mode is the default without a TTY, and also with --json, CI or LINK_LOOM_MODE=agent. It never prompts.
npx @link-loom/cli describe --json # what the CLI can do, exit codes, error codes
npx @link-loom/cli schema service --json # JSON Schema of a generator's input
npx @link-loom/cli create service --name billing-svc --shape microservice --dry-run --json
npx @link-loom/cli create service --input service.json --json
npx @link-loom/cli create webapp --name "Acme Workspace" --variant client --json
npx @link-loom/cli add entity --domain inventory --entity product --fields name:text:required,price:number --json
npx @link-loom/cli create landing --name Acme --description "The operations center for your business." --json
npx @link-loom/cli add section --page home --kind faq --items-en "Is it free?|Yes, for small teams." --yes --jsonInside a project (the folder with loom.json), add, brand, services and images act on it. A command that would
change existing files answers E_CONFIRMATION_REQUIRED with the plan until it gets --yes.
With --json, stdout carries exactly one document:
{
"schemaVersion": 1,
"ok": true,
"command": "create service",
"dryRun": false,
"project": {},
"input": {},
"plan": { "create": [], "modify": [], "delete": [] },
"warnings": [],
"errors": [],
"next": []
}| Exit code | Meaning |
|---|---|
| 0 | success (including a dry run) |
| 1 | runtime failure (E_IO, E_FETCH, E_INSTALL) |
| 2 | usage or validation (E_USAGE, E_VALIDATION with the missing fields) |
| 3 | precondition or conflict (E_TARGET_EXISTS, E_NOT_AVAILABLE, E_EDIT_SHAPE…) |
| 4 | quality gate failed |
| 130 | interrupted |
create, update and migrate apply install dependencies, which takes one to three minutes. While they run they
report their progress on stderr, so stdout keeps its single document. With --json it is one JSON event per line:
{"event":"progress","command":"create webapp","step":"render","progress":0,"total":100,"message":"Preparing the template"}
{"event":"progress","command":"create webapp","step":"write","progress":2,"total":100,"message":"Writing the files"}
{"event":"progress","command":"create webapp","step":"install","progress":27,"total":100,"message":"Installing dependencies: working out which packages it needs (400 found)","phase":"resolving","found":400}
{"event":"progress","command":"create webapp","step":"install","progress":72,"total":100,"message":"Installing dependencies: 512/1203 packages in place","phase":"installing","done":512,"packages":1203}
{"event":"progress","command":"create webapp","step":"done","progress":100,"total":100,"message":"Done"}| Field | Meaning |
|---|---|
step |
create: render, write, install · update: write, install, verify · migrate apply: write, install, finish; then done |
progress |
the whole run, 0 to 100; it only grows |
phase |
install only: resolving (npm is working out the tree, found packages so far) or installing (done of packages in place) |
message |
the same line a person reads |
Without --json the same progress is a readable line every 10% (› 72% Installing dependencies: 512/1203 packages in place). A dry run reports nothing. describe --json publishes this contract under progress.
An agent does not have to sit through the install. Create with --no-install (install: false over MCP), which
answers in seconds with the project written, then install in the background and keep working on the code:
npx @link-loom/cli create webapp --name "Acme Workspace" --variant client --no-install --json
(cd acme-workspace && npm install > npm-install.log 2>&1 &) # or the agent's own background shell
cd acme-workspace
npx @link-loom/cli add entity --domain inventory --entity product --fields name:text:required --yes --jsonWithout the install, the next of a create lists npm install right after the cd. Generators only write files, so
add … works before node_modules exists (add feature adds dependencies: run it before installing, or install
again after it). Until the install ends, call the CLI as npx @link-loom/cli: the project's own npx link-loom
arrives with its dependencies. What needs them (npm run verify, check, the build, the tests) waits for the install
to finish. update --no-install and migrate apply --no-install work the same way: run npm install, then what their
next says.
link-loom mcp serves the same commands as a Model Context Protocol server over
stdio. Every generated project connects it in .mcp.json; to create projects from an agent, add it once yourself:
{ "mcpServers": { "link-loom": { "command": "npx", "args": ["-y", "@link-loom/cli", "mcp"] } } }| Where the server runs | Tools |
|---|---|
| outside a project | describe, schema, check, and create_landing, create_webapp, create_service |
| inside a project | describe, schema, check, add_<generator> for its collection, and brand in a webapp |
A tool's input is its generator's JSON Schema plus dryRun, and yes (to change existing files) or install (on a
create). Each call runs the same dispatcher as --json: the result is the same document, as text and as
structuredContent, and isError is true when the exit code is not 0.
A tools/call that carries params._meta.progressToken gets notifications/progress while it runs, built from the
events above:
{
"jsonrpc": "2.0",
"method": "notifications/progress",
"params": {
"progressToken": "create-1",
"progress": 72,
"total": 100,
"message": "Installing dependencies: 512/1203 packages in place"
}
}The result is what marks the end of a call: a client may drop the last notification (100, Done) when it arrives
together with the result. Most MCP clients wait for the result of a call, so a create with the install holds the agent
for those minutes even with progress. Prefer install: false and the background install above when the agent has more to do.
npx @link-loom/cli in a terminal opens the home: the woven Link Loom logo, Loomi, and "What do you want to create?".
Every flow shows the plan before writing anything, shows the install as a bar with its percentage (Ctrl+C stops it
and says how to remove or finish the half-made folder) and ends with the equivalent command for an agent. The UI follows
the terminal language (English or Spanish) and stays static with --no-animation, NO_COLOR, CI or a narrow terminal.
| Package | Role |
|---|---|
@link-loom/cli |
The runner: TUI, agent mode, commands |
@link-loom/devkit |
The engine: virtual tree, plans, atomic apply, templates, structural edits, validation |
@link-loom/node-generators |
Backend generators |
@link-loom/react-generators |
React generators and the loom-react agent skill |
@link-loom/astro-generators |
Landing page generators |
@link-loom/migrate |
Temporary: moves existing webapps onto the standard (link-loom migrate) |
Generators follow the collection contract in docs/collections.md.
npm install
npm test # Jest, every package
npm run lint
node packages/cli/bin/link-loom.js describeAll packages share one version. npm run version-patch bumps every package, commits, tags v<version> and pushes the
tag; GitHub Actions then publishes to npm with trusted publishing (no token). Prerelease versions go to the next tag.
A release also moves the @link-loom/cli range that generated projects get to the new version; node scripts/release.mjs patch --no-push does all of it but the push. npm run version-tag tags the version already in
package.json on the current commit, without bumping or pushing (for a version committed without its tag);
git push origin v<version> then publishes it.
Apache-2.0. What the generators write into your project is yours: use, change and license the generated files under any terms you choose, with no attribution required.