Project Anatomy
A Loom project has a small, predictable layout. Once you know the four directories, you know where everything lives.
my-app/
├── loom.yaml ← project config (read by every command)
├── threads/ ← your Thread YAML files (you edit these)
├── custom/ ← ejected / hand-written Go (you edit these)
├── .loom/ ← generated artefacts (don't edit; regenerated by loom weave)
└── README.md
loom.yaml
The single source of truth for project-level settings. Auto-generated by loom new:
project: my-app
module: github.com/your-org/my-app
threads_dir: threads
output_dir: .loom
loom_version: 0.1.0
| Key | Purpose |
|---|---|
project |
Display name; used as the OrbWeaver Project record name |
module |
Go module path; used in import statements in generated Go |
threads_dir |
Where loom check / loom weave look for Thread YAML |
output_dir |
Where generated artefacts land |
loom_version |
Reference; loom report includes it in build reports |
CLI commands walk parent directories until they find a loom.yaml, so you can run them from any subdirectory.
threads/
One YAML file per model. The filename is conventionally lowercase-hyphenated:
threads/
├── customer.yaml
├── invoice.yaml
└── invoice-item.yaml
Filenames don't influence anything semantically — Loom reads the model: field inside each file. Naming files after their model just makes them easy to find.
custom/
Empty until you eject something. After loom eject Customer, this is what you see:
custom/
├── models/customer.go
├── handlers/customer.go
├── handlers/customer_test.go
└── routes/customer.go
Files moved here have their "Generated by Loom" header stripped — they're yours now. You're responsible for keeping them in sync with the Thread definition (Loom won't regenerate over them; that's the point).
.loom/
Re-creatable artefacts. Each weaver writes into its own subdirectory:
.loom/
├── sql/ loom stitch consumes this
├── go/{models,handlers,routes}/ loom serve does NOT consume; reference
├── svelte/src/routes/<table>/ for users running a SvelteKit frontend
├── htmx/ for users serving HTMX partials
├── pending-reports/ staging for loom sync
└── posted-reports/ archive of synced reports
Treat .loom/sql/, .loom/go/, .loom/svelte/, .loom/htmx/ like build output — gitignored, regenerated. Treat .loom/pending-reports/ and .loom/posted-reports/ as the build log — keep them in version control.
What's not in the project
- Loom itself. The CLI is a global binary, installed once per machine.
- Database. Connection comes from
DATABASE_URL; no local file likedev.db. - Frontend tooling. If you run the SvelteKit output, you set up
package.json/pnpmseparately under.loom/svelte/.
This separation keeps your repo small. The biggest thing in a typical project is threads/ — pure YAML, never more than a few KB per model.