Now write the code that actually runs the service. Both paths authenticate a service instance, present contract evidence, resolve deployment bindings, and connect to NATS.

Open main.ts, which was created by deno init, and replace it with:

import { TrellisService } from "@qlever-llc/trellis/service/deno";
import { ordersService } from "./contracts/orders_service.ts";

const service = await TrellisService.connect({
  trellisUrl: Deno.env.get("TRELLIS_URL")!,
  contract: ordersService,
  name: "orders-service",
  sessionKeySeed: Deno.env.get("ORDERS_SERVICE_SESSION_KEY_SEED")!,
});

const app = service.with({
  clock: () => new Date(),
  id: () => crypto.randomUUID(),
  log: console,
});

console.log("Connected to Trellis!");

Node.js users: Import from @qlever-llc/trellis/service/node and replace Deno.env.get(...) with process.env.

TrellisService.connect(...) does a lot of heavy lifting. It authenticates your service session, verifies that the presented contract evidence fits the enabled deployment authority, fetches transport details, and hands back a service object with the deployment’s persisted resource bindings already resolved.

The contract can be active before this instance connects. If deployment authority does not cover the contract boundary yet, bootstrap creates or reuses a pending authority update and waits while retrying. Required dependencies whose only known manifests are stale and incompatible are tracked as blockers until current evidence is uploaded.

Those resolved bindings are Trellis runtime internals. Use the returned service.kv, service.store, and service.jobs handles; do not call Trellis.Bindings.Get, construct TrellisService or StoreHandle, or pass binding/resource payloads into Trellis constructors.

Use service.with(deps) for application-owned dependencies you want available in handlers, such as repositories, clocks, loggers, or local projections. The returned app wrapper injects those dependencies as args.deps in RPC, feed, operation, job, and event listener handlers. It does not replace Trellis runtime resources or contract uses dependencies; keep service for lifecycle and resolved resource handles.

Before we can run this, we need to create a deployment, provision a service instance, and accept any deployment authority plan created from the contract boundary.

Every Trellis service authenticates with a unique instance key. trellis svc <id> provision prints the private seed for that instance; treat it like a private key and never commit it to source control.

trellis svc orders-service create
trellis svc orders-service apply --source .
trellis svc orders-service provision

Before starting the service, submit the service contract boundary and review the resulting deployment authority change in Console. Open Admin → Services, select orders-service, and use the pending authority accept/reject controls if bootstrap or trellis svc orders-service apply --source . created a request. During local development you can also start first and accept the pending authority update that bootstrap creates; acceptance schedules reconciliation before runtime access becomes available.

Now run your service:

TRELLIS_URL=http://localhost:3000 \
ORDERS_SERVICE_SESSION_KEY_SEED=<seed-from-provision> \
deno run --allow-net --allow-env main.ts

You should see a connected log line. The service does not do anything yet, but it is alive on the network. Let’s change that.