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.
Greentic stacks a few layers. Each step in this guide moves you one layer up:
.gtpack.gtbundlelocal) that holds deployments and their settings..gtbundle from a demo packUses 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
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.
--execute is required. Without it the command only prints a preview and writes nothing.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.
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.)
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.
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).
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).
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.
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.
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.
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.
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.)
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.
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 .
/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.: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.init and add app-pack only preview unless you pass --execute.$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..gtbundle, then stage a new revision and traffic set to it. Revisions are immutable, so each change is a new one — clean rollback path.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.