Greenticlocal deploymentfish shell

Run a real demo bundle locally

Build a .gtbundle from a demo pack, then serve it with the new environment / deployment / revision model — explained step by step.

There are two halves. Part A packages a reusable pack into a shippable bundle. Part B deploys that bundle into a local environment and serves it over HTTP. Every command below is written for the fish shell.

First, the mental model

Greentic stacks a few layers. Each step in this guide moves you one layer up:

Component
one WASM skill
Pack .gtpack
components + flows
Bundle .gtbundle
packs + access config
Deployment
bundle bound to a tenant
Revision
one frozen version
Serve
gtc start

Part A — Build a .gtbundle from a demo pack

Uses the greentic-bundle-dev tool. We turn one demo pack (quickstart.gtpack, which ships a real adaptive-card component) into a deployable bundle.

# Pick the pack and a workspace folder
set PACK /home/vampik/greenticai/greentic-demo/demos/quickstart.gtpack
set WORK /tmp/bundlebuild/quickstart

1Scaffold the bundle workspace

greentic-bundle-dev init $WORK \
    --bundle-name quickstart --bundle-id quickstart-bundle --mode create --execute

Does Creates an empty bundle "project" folder with its config files (bundle.yaml, a default tenant, and an access-policy file).

Why A bundle is more than a pack — it also carries identity (id/name) and a tenant access layer. This builds that skeleton so the next steps have somewhere to write.

Gotcha: --execute is required. Without it the command only prints a preview and writes nothing.

2Put the pack inside the workspace

mkdir -p $WORK/packs
cp $PACK $WORK/packs/quickstart.gtpack

Does Copies the demo pack into the workspace's packs/ folder.

Why The build step scans packs/ and bakes every .gtpack it finds into the final bundle. If the pack isn't here, it won't ship.

3Register the pack as an app-pack

greentic-bundle-dev add app-pack ./packs/quickstart.gtpack --root $WORK --execute

Does Records the pack in bundle.yaml and re-generates the access policy so the tenant is allowed to use it.

Why Tells the bundle "this pack is officially part of me" and wires the permission entry, so the bundle manifest and access rules are consistent. (--execute again, or it just previews.)

4Build the artifact

greentic-bundle-dev build --root $WORK --output /tmp/bundlebuild/quickstart.gtbundle

Does Compresses the workspace (config + packs + access rules) into a single .gtbundle file.

Why This one file is the shippable, content-addressed artifact the runtime consumes. Everything downstream points at it.


Part B — Run it with the new env model

Now we deploy that bundle into a local environment and serve it. Uses gtc-dev.

set -x GREENTIC_ENV local
set BUNDLE /tmp/bundlebuild/quickstart.gtbundle

GREENTIC_ENV picks which environment to use. In fish you set env vars with set -x (the bash VAR=val cmd prefix does not work).

1Create the environment

gtc-dev op env init

Does Creates the local environment and wires its default bindings (secrets, state, sessions, telemetry, deployer).

Why Deployments live inside an environment. This is the home everything else is registered into. Safe to re-run (idempotent).

2Create the operator signing key

gtc-dev op trust-root bootstrap local

Does Generates an operator key for this environment and trusts it.

Why Deployments are signed/authorized. Adding a bundle refuses to proceed without a key, so this must happen once per environment.

3Declare a deployment

echo '{"environment_id":"local","bundle_id":"quickstart-bundle","route_binding":{"hosts":[],"path_prefixes":[],"tenant_selector":{"tenant":"acme","team":"default"}},"revenue_share":[{"party_id":"greentic","basis_points":10000}],"authorization_ref":"auth.json"}' > /tmp/badd.json
set DEP (gtc-dev op bundles add --answers /tmp/badd.json | jq -r '.result.deployment_id')

Does Says "serve bundle quickstart-bundle for tenant acme" and returns a deployment id (saved in $DEP).

Why A deployment binds a bundle to a tenant and a route. Empty hosts/path_prefixes means "match any request" — ideal for local testing. We read the id with jq so the next steps can reference it.

4Stage your bundle into a revision

echo "{\"environment_id\":\"local\",\"deployment_id\":\"$DEP\",\"bundle_path\":\"$BUNDLE\"}" > /tmp/stage.json
set REV (gtc-dev op revisions stage --answers /tmp/stage.json | jq -r '.result.revision_id')

Does Extracts your .gtbundle, pins the exact packs inside it, and creates an immutable revision (saved in $REV).

Why A deployment can have many versions over time. Staging freezes one specific build as a revision so rollouts and rollbacks are deterministic.

5Warm the revision

echo "{\"environment_id\":\"local\",\"revision_id\":\"$REV\"}" > /tmp/warm.json
gtc-dev op revisions warm --answers /tmp/warm.json

Does Moves the revision from staged to ready.

Why Traffic can only be sent to a ready revision. Warming is the gate that confirms it's loadable before it can receive requests.

6Send traffic (and materialize the runtime config)

echo "{\"environment_id\":\"local\",\"deployment_id\":\"$DEP\",\"entries\":[{\"revision_id\":\"$REV\",\"weight_percent\":100}],\"updated_by\":\"operator\",\"idempotency_key\":\"boot-1\",\"authorization_ref\":\"auth.json\"}" > /tmp/traffic.json
gtc-dev op traffic set --answers /tmp/traffic.json

Does Routes 100% of traffic to your revision and writes runtime-config.json for the environment.

Why This is the live switch — "serve this revision now". It also generates the exact file the server reads on start. (Splitting traffic across revisions is how canary/blue-green works.)

7Serve

gtc-dev start

Does Starts the runtime with no bundle argument; it reads runtime-config.json and serves the deployed revision over HTTP (default 127.0.0.1:8080).

Why This is the actual server. It accepts requests, picks the revision per the traffic split, and runs that revision's flow. The "no bundle" form is the whole point of the new model.

Test it (second terminal)

curl -s http://127.0.0.1:8080/healthz
curl -s http://127.0.0.1:8080/ -H 'content-type: application/json' \
     -d '{"text":"hello","user":"u1","session":"s1"}' | jq .
Expected: /healthz returns ok, and the POST returns a Greentic Activity with a renderedCard — the quickstart welcome adaptive card. That means the real WASM flow executed end to end.

Notes & troubleshooting

Port already in use: if :8080 is taken, gtc-dev start picks the next free port — read the "Serving … on http://…" line it prints. Kill stale servers with pkill -f greentic-start, or pin a port with set -x PORT 8080.
Dry-run by default: init and add app-pack only preview unless you pass --execute.
Other demos: swap $PACK for any file in greentic-demo/demos/ — e.g. weatherapi-pack, hr-onboarding, sales-crm, cards-demo. Weather/LLM packs may need secrets configured to fully respond.
Iterating on a pack: rebuild the .gtbundle, then stage a new revision and traffic set to it. Revisions are immutable, so each change is a new one — clean rollback path.
Env var syntax (fish): use set -x GREENTIC_ENV local. The bash-style GREENTIC_ENV=local gtc-dev start prefix does not work in fish; use env GREENTIC_ENV=local gtc-dev start for a one-shot.