Contributing

In-repo development

Run the Trellis server, console, and NATS from the source tree for local development.

This guide walks through running the Trellis server, console, and supporting services directly from the source tree. By the end you will have a local development environment equivalent to the Server Setup guides, but running processes natively instead of in containers.

What you need

  • Git
  • Deno (v2+)
  • a Rust toolchain (rustup)
  • podman (for the NATS container only)
  • systemctl --user with Quadlet support
  • an OAuth application (GitHub) for local development

1. Clone the repository

git clone https://github.com/qlever-llc/trellis.git
cd trellis

2. Install dependencies

Install the Deno workspace dependencies:

cd js
deno install
cd ..

Build the Trellis CLI from source:

cd rust
cargo build -p trellis-cli
cd ..

The commands below use the installed trellis CLI directly.

trellis --version

3. Set up NATS

NATS still runs in a container even for in-repo development. Follow the Prepare NATS guide to get a running NATS server.

Create a workspace directory for NATS state outside the repo:

mkdir -p ~/trellis/{config,keys,nsc,nkeys}
chmod 700 ~/trellis/keys ~/trellis/nsc ~/trellis/nkeys

Complete all of the steps in the Prepare NATS guide using ~/trellis as your workspace root. When you are done you should have NATS running on 127.0.0.1:4222.

4. Generate the Trellis session key

trellis keygen \
  --out ~/trellis/keys/trellis.seed \
  --pubout ~/trellis/keys/trellis.pub

5. Build SDKs from contracts

The service and generated SDK packages depend on contract build artifacts. Generate them before running anything:

deno task -c js/deno.json build:sdk

6. Collect the NATS values

If you still have the shell variables from the NATS guide, skip this step.

cd ~/trellis

NATS_AUTH_ISSUER_NKEY=$(./nsc.sh describe account -n AUTH --field sub | tr -d '"')
NATS_AUTH_TARGET_NKEY=$(./nsc.sh describe account -n TRELLIS --field sub | tr -d '"')
XKEY_PUB=$(./nsc.sh describe account -n AUTH -J | grep '"xkey"' | tr -d ' ",' | cut -d: -f2)

Read the signing seeds:

NATS_AUTH_ISSUER_SIGNING_SEED=$(cat ~/trellis/keys/auth-issuer-signing.nk)
NATS_AUTH_TARGET_SIGNING_SEED=$(cat ~/trellis/keys/trellis-target-signing.nk)
NATS_AUTH_SXKEY_SEED=$(cat ~/trellis/nkeys/keys/X/${XKEY_PUB:1:2}/${XKEY_PUB}.nk)

7. Configure the auth runtime

Copy the example Trellis config in the source tree:

cd /path/to/trellis
cp js/services/trellis/config.example.jsonc js/services/trellis/config.jsonc

Edit js/services/trellis/config.jsonc and fill in the values. When running from source, relative paths are resolved from js/services/trellis/.

{
  "web": {
    "origins": ["http://localhost:5173"],
    "publicOrigin": "http://localhost:3000"
  },
  "nats": {
    "servers": "localhost",
    "trellis": {
      "credsPath": "/home/<you>/trellis/nkeys/creds/Trellis/TRELLIS/trellis.creds"
    },
    "auth": {
      "credsPath": "/home/<you>/trellis/nkeys/creds/Trellis/AUTH/trellis.creds"
    },
    "sentinelCredsPath": "/home/<you>/trellis/nkeys/creds/Trellis/AUTH/sentinel.creds",
    "authCallout": {
      "issuer": {
        "nkey": "<value from step 6>",
        "signingSeedFile": ".local/secrets/auth-issuer-signing.seed"
      },
      "target": {
        "nkey": "<value from step 6>",
        "signingSeedFile": ".local/secrets/auth-target-signing.seed"
      },
      "sxSeedFile": ".local/secrets/auth-sx.seed"
    }
  },
  "sessionKeySeedFile": ".local/secrets/session-key.seed",
  "client": {
    "natsServers": ["ws://localhost:8080"]
  },
  "oauth": {
    "redirectBase": "http://localhost:3000/auth/callback",
    "alwaysShowProviderChooser": true,
    "providers": {
      "github": {
        "type": "github",
        "clientId": "<your GitHub OAuth app client ID>",
        "clientSecretFile": ".local/secrets/github-client-secret"
      }
    }
  }
}

client.natsServers is the websocket endpoint list the auth service returns to browser clients after /auth/bind, so apps can discover the correct realtime connection settings from the instance they signed into.

Then start the runtime with the config path override:

TRELLIS_CONFIG=./config.jsonc deno task -c js/services/trellis/deno.json dev

8. Bootstrap NATS buckets

trellis bootstrap nats \
  --servers 127.0.0.1 \
  --trellis-creds ~/trellis/nkeys/creds/Trellis/TRELLIS/trellis.creds \
  --auth-creds ~/trellis/nkeys/creds/Trellis/AUTH/trellis.creds

9. Start the Trellis runtime

cd js/services/trellis
deno task dev

The runtime starts on http://localhost:3000 with file watching enabled. Code changes under js/ will trigger an automatic restart.

Test it:

curl -i http://localhost:3000/auth/login/github

An HTTP 400 is expected — it confirms the runtime is serving.

10. Start the console app

In a second terminal:

cd js/apps/trellis
cp .env.example .env
deno task dev

The console starts on http://localhost:5173 with Vite HMR.

11. Create the first admin

Before logging into the console, bootstrap the GitHub account that will become the first administrator:

trellis bootstrap admin \
  --servers 127.0.0.1 \
  --creds ~/trellis/nkeys/creds/Trellis/AUTH/trellis.creds \
  --origin github \
  --id github:YOUR_GITHUB_USER_ID

This seeds the user projection with the default console access set: admin, trellis.catalog.read, and trellis.contract.read.

12. Log in with the CLI

trellis --nats-servers 127.0.0.1 auth login \
  --auth-url http://localhost:3000 \
  --provider github

13. Verify

curl http://127.0.0.1:8222/healthz
curl -i http://localhost:3000/auth/login/github
curl -I http://localhost:5173/
trellis auth status

Open http://localhost:5173 in your browser and complete the OAuth login with that same GitHub account.

Development workflow

  • Runtime changes — edit files under js/services/trellis/ or js/packages/. The deno task dev watcher restarts the process automatically.
  • Console changes — edit files under js/apps/trellis/. Vite HMR applies changes in-place.
  • Contract changes — run deno task -c js/deno.json build:sdk to regenerate SDKs, then restart the affected service.
  • CLI changes — run cargo build -p trellis-cli in the rust/ directory, then re-run trellis ... commands from the repo root.
  • Type checking — run deno task -c js/deno.json check to type-check the full JS workspace.
  • Tests — run deno task -c js/deno.json test:contracts or deno task -c js/deno.json test:auth.