Get Started
Get Started
Install the CLI, wire up your editor, give your agent the skill, and write your first sidecar on one real change. Trellis is useful one file at a time — you do not have to convert a codebase to begin.
What’s in the box
Trellis is a .trellis sidecar format plus a single Go binary that turns those
sidecars into working tooling. Today that binary gives you:
- A dependency graph over what every unit
Provides:andConsumes:, with queries for dependents, blast radius, and orphaned contracts. - A linter — ten rules plus drift detection, with an override mechanism for the cases you’ve consciously accepted.
- A language server (
trellis lsp) that powers diagnostics-as-you-type, hover, and jump-to-definition in your editor. - Policy packs that enforce architectural rules (
layer_dependencies,stability_tiers) across the graph. - An agent skill that makes your AI assistant read the sidecar before it touches the code.
You don’t need all of it on day one. The fastest useful path is: install the CLI, turn on editor support, write one sidecar, and use it during one real change.
Install the CLI
The toolchain is a Go application (Go 1.23+). Build it from source and put it on
your $PATH:
git clone https://github.com/norlinga/trellis.git
cd trellis
go build -o ./trellis ./cmd/trellis
sudo install -m 0755 ./trellis /usr/local/bin/trellis # or any $PATH dir
trellis --help
If you’d rather let Go fetch and install it directly:
go install github.com/norlinga/trellis/cmd/trellis@latest
The binary is one command with a few subcommands. The ones you’ll reach for most:
trellis graph build . # discover sidecars; summarize the graph + unresolved consumes
trellis lint . # run all rules over every sidecar under this path
trellis lsp # speak the Language Server protocol over stdio (editors use this)
Graph queries take sidecar paths — the .trellis file, not the source
file:
trellis graph deps app/services/create_subscription.rb.trellis # what this unit depends on
trellis graph dependents app/services/create_subscription.rb.trellis # who depends on it
trellis graph orphans . # Provides: with no consumer
Run trellis <command> --help for the full surface, and see the
GitHub repository for the spec and
release notes.
Set up your editor
Every editor integration just spawns trellis lsp over stdio, so the only
prerequisite is the trellis binary on $PATH. Once connected you get
diagnostics as you type, hover (a Consumes: handle shows the
provider’s feature, summary, and source file), and jump-to-definition (F12
on a Consumes: handle jumps to the Provides: that owns it).
Cross-file hover and jump-to-definition only resolve when you open the folder, not a single file — the server indexes the workspace at startup.
Neovim
Requires Neovim 0.10+ and nvim-lspconfig. Drop the project’s
trellis.lua
into your runtime (e.g. ~/.config/nvim/lua/trellis.lua) and load it:
require("trellis").setup()
That registers *.trellis as filetype trellis and attaches trellis lsp
automatically. Open a sidecar and diagnostics appear inline; :LspInfo should
list the client as attached.
For tree-sitter-grade highlighting, install the grammar from
tree-sitter-trellis via
nvim-treesitter — the editors/neovim/README.md in the repo has the
install_info snippet.
VS Code / Cursor
The repo ships a client extension under editors/vscode/ (Cursor consumes VS
Code extensions natively, so the same .vsix works in both). Build and
sideload it:
cd editors/vscode
npm install
npm run compile
npx @vscode/vsce package
code --install-extension trellis-vscode-0.1.1.vsix
You get TextMate syntax highlighting, the LSP client (diagnostics in the
Problems panel and inline), hover, and go-to-definition. Point the
trellis.executable setting at an absolute path if trellis isn’t on the
$PATH VS Code launched with.
Give your agent the skill
The agent skill is a short behavioral document that shapes how your AI assistant works in Trellis-aware code. It enforces the workflow gates: search for an existing unit before creating a new one, read the sidecar before modifying a file, and surface invariant or scope violations before writing code.
Add
TRELLIS_SKILL.md
to your project. For Claude Code, place it under .claude/ or reference it from
CLAUDE.md; for other agents, drop it wherever that agent collects skills or
rules (.cursor/rules/, a generic .agents/ directory, etc.). It’s
deliberately short — its job isn’t to explain Trellis, it’s to give the agent a
checklist it runs before every meaningful action.
Start with one unit
You do not need to sidecar an entire codebase before Trellis pays off. A single
.trellis file next to a single source file already helps a reviewer — or an
agent — understand what that unit is for before touching it.
Pick a unit that already has a recognizable job: a service object, a class with a narrow responsibility, a module with a stable public function, a worker with a clear contract. Don’t start with the most chaotic file in the system; Trellis teaches best when the first example is coherent.
Before you create a new unit, check whether something like it already exists.
Build the graph and look for a Provides: handle that already covers the
behavior:
trellis graph build .
If a plausible match turns up, extend that unit instead of duplicating it. If
nothing matches, create the source file and its sidecar together. The sidecar
lives next to the source with .trellis appended:
app/services/create_subscription.rb
app/services/create_subscription.rb.trellis
Write the sidecar
Write the sidecar first, and keep it small and honest. The goal isn’t to restate the implementation — it’s to capture intent, boundaries, and the constraints that must survive a rewrite.
@owner: BillingTeam
@stability: stable
@since: 2026-05-27
@reviewed: 2026-05-27
Feature: Create Subscription
"Creates a user's subscription and charges the initial payment method."
Provides:
- Subscription.create(user, plan_id) -> Subscription | raises PaymentError
- Event: subscription.created
Consumes:
- PaymentGateway.charge(token, amount) -> ChargeResult
- UserRecord (must respond to: id, email, payment_token)
Invariants:
- A user MUST NOT have two active subscriptions for the same plan
- Charges SHALL be idempotent on (user_id, plan_id, idempotency_key)
OutOfScope:
- Refunds (handled by RefundService)
- Plan upgrades (handled by ChangeSubscriptionPlan)
Scenario (happy-path): Successful subscription creation
Given a user with a valid payment token
When subscription creation is requested for a plan
Then a Subscription record is created
And the payment gateway is charged
Scenario (negative): Declined card
Given a user with a declined payment method
When subscription creation is requested
Then it MUST raise PaymentError
And no Subscription record is createdThat snippet is highlighted by the same TextMate grammar that ships in the
editor extension — not faked for the page. Capitalized RFC 2119 words (MUST,
MUST NOT, SHALL, SHOULD, MAY) are load-bearing in invariants and
scenario steps. The first structured token of each Provides: / Consumes:
entry is its handle — the stable graph identity. Keep handles exact and
free of implementation locations; if you want to anchor one to a line or label,
use @source("line:42-68") or @source("label:CHARGE").
Keep four questions in mind as you write:
- What does this unit provide to the rest of the system?
- What does it consume or rely on?
- What must remain true even if the implementation changes (its invariants)?
- What does not belong here?
Use it during a real change
The sidecar isn’t done when the file exists. It’s done when it changes how the work gets done. Take one real task and use the sidecar before editing code:
- Read the sidecar in full.
- Check whether the change belongs inside the unit’s stated scope.
- If it touches an
Invariant, decide explicitly whether you’re preserving or changing it. - If it adds a dependency, update
Consumes:. - If it alters the contract or boundaries, update the sidecar in the same pull
request — and bump
@reviewed:.
Then lint the sidecar you touched (lint takes the sidecar path):
trellis lint app/services/create_subscription.rb.trellis
This is the moment that matters. Trellis earns its place only if it affects decisions before code is written.
What good looks like
Your first experiment succeeded if it produced any of these:
- the agent extended an existing unit instead of creating a duplicate
- a reviewer caught intent drift that would have been easy to miss in code alone
- the sidecar revealed that a requested change was actually out of scope
- a test plan got clearer because the invariants were explicit
- the unit’s dependencies became easier to reason about
The win is not ceremony. It’s better targeting and better restraint.
What to avoid
Common failure modes on a first attempt:
- writing implementation notes instead of intent
- documenting every private detail
- inventing invariants that aren’t actually enforced
- leaving
OutOfScope:empty when the boundary matters - treating the sidecar as finished once created, even after the code changed
A good sidecar is concise, reviewable, and slightly abstracted from the source. If it just paraphrases the code line by line, it isn’t doing its job.
Roll out gradually
If the first unit proves useful, expand by subsystem, not all at once:
- Add sidecars to a few high-value units in one subsystem.
- Require agents to read those sidecars before modifying those files.
- Review code and sidecar diffs together.
- Run
trellis lintin CI. - Watch for duplicate features, weak boundaries, and stale intent.
- Only later add policy packs
(
layer_dependencies,stability_tiers) to enforce architecture across the graph.
The adoption path is intentionally file-by-file.
Where things stand
The format and on-disk artifacts — sidecar grammar, policy file shape, diagnostic codes — are v0.1 stable. The CLI (graph + lint), the language server, the policy packs, the tree-sitter grammar, and the agent skill are all shipping today. Pre-v1, rule thresholds and lint calibration will keep moving with real-world feedback, so pin a known-good build for CI. The current status table lives in the repository README.
Next reading
- The whitepaper for the full argument and tooling model.
- The FAQ for the strongest objections and the honest responses.
- The glossary for precise definitions of
Provides,Consumes,Invariants, andOutOfScope. - The GitHub repository for the spec, the editor integrations, and release announcements.