How it works · templates
Environment templates
An environment template — a template, for short — is an environment kept by your account, under a name, in two kinds of version:
- a saved environment,
name@s3 - The whole environment as it was: its setup, the scripts,
projects/with dependencies and git history, and its data. For keeping, for moving to another box, for handing to someone in your account. Only your account sees it. - a published version,
name@r2 - Published from a saved environment, with only what was committed: no git history, no personal data, no
.env. Scanned, and installed fresh before it is kept. What can be shared.
A template is not a recipe or a Dockerfile: it is a copy of an environment's directory. Installing one copies it back, which is why it takes seconds. Anything you can get running as an environment, you can keep, without learning a format.
Your box holds running environments and nothing else. Templates belong to your account, and survive any box. How environments and templates work has what happens underneath.
Your templates
list_templates shows everything you can install: the starter kits, your own templates, and your organizations' (as org/name), each with its newest published version and saved environment. On the dashboard, Templates shows the same, with every version.
Saved environments
You
Save catan as next-starter.
Claude
Asks what kind it is, says what will be kept — the projects, that its personal data and database come along, that only your account will see it — and that catan pauses for a moment, then save_environment.
Bettik
Saved environment next-starter@s1 saved from "catan", a kit. It includes its personal data (data/) and its git history. Only you can see it; it cannot be shared outside. To share it, publish it: publish_template.
One step. The environment is checked first and refused with reasons if it is not ready (a start that is not executable, a secret declared that nothing uses). Then its whole directory is kept and becomes the next saved environment of its name: next-starter@s1, then @s2. Saved environments never change once made, and every box of yours can install one.
Where it goes: org/name puts it in that family's or organization's templates (any you belong to, from any box); with no name, it is the next saved environment of the template the environment was installed from; otherwise it goes to the account that owns the box.
A saved environment is also how to free a box: save an environment, remove it, and install it again when you want it back.
Publishing a version
You
Publish next-starter.
publish_template makes a published version of the template from a saved environment. The box the environment was saved on packs the committed files; only those go on to a throwaway GitHub Actions runner, which scans them and installs them fresh:
- It takes only what was chosen: each repository under
projects/at its last commit (git archive, so no history and nothing uncommitted), the environment's own files, and any root directorybettik.jsonnames in"release": {"include": [...]}. - It leaves out the personal data
bettik.jsondeclares ("data": ["data/"]),.env, the passwords Bettik made,node_modules, and anything else, and says what it left out. - It stops if the scan finds an env file, a Claude sign-in, a private key, something shaped like a token, git history, or a project without its lockfile — naming the file and line, never the value. A version that stops is not kept anywhere.
- It is installed fresh in a throwaway environment, on a runner that holds no one's keys, and must answer (at
app.healthinbettik.json,/by default) before it is kept.
Published versions are numbered on their own: next-starter@r1, @r2. publish_status says how one is going and why one stopped. Each records the saved environment it came from, the commit of each project, and the commits since the version before, which only your account sees.
A published version carries no dependencies: installing it runs seed, and the environment's update builds them from the committed lockfile, so it installs the same next month.
Kind
Every template has a kind, chosen when its first saved environment is made. One question decides it: what does someone do with it first?
app- People use it. A tracker, a shop, a tool for the team.
game- People play it.
kit- People build on it. A starting point with the setup done:
node22-postgres17is one. content- People read it, watch it, or load it as data.
other exists for the template none of those fit, and needs a sentence saying why. Reach for it rarely: almost everything is one of the four. A template kept before kinds existed shows no kind yet.
Starter kits
Two templates of kind kit ship with Bettik. Work starts by installing one as an environment.
empty- An app container running Debian, and nothing else. For when the setup itself is the work: edit
compose.yamluntil it is the one you need — Python 2.7, Postgres 12, whatever it is — and go from there. node22-postgres17emptywith Postgres 17 in the compose file, aDATABASE_URLin.env, and aseedthat knowscreate-next-appandgit clonewhen you ask. An example, not a different kind of thing.
Installing
install_environment next-starter makes a new environment from its newest published version, or its newest saved environment when it has none; install_environment next-starter@r2 from that version, @s3 from that saved environment; install_environment org/name from an organization's. Environments has the rest.
A big template takes minutes to download the first time. To have it waiting on a box before anyone needs it, fetch_template org/name fetches it there without installing it: nothing runs and no memory is used, and a later install_environment of it takes seconds. It answers at once and fetches in the background; ask again to see whether it is there. A team can put it in the prompt it gives each new box: fetch hemlane/dev-stack, set these env vars.
Where an environment came from
Every environment records what it was installed from — next-starter@r2, a saved environment, a starter kit, a clone of another environment — and every saved environment records its parent, every published version its saved environment. list_templates and environment_status show it. A chain, never a lattice: one origin each, no merges. What changed between versions is your git inside projects/, not Bettik's concern.
Making one that works
A template is only as reproducible as its seed. The one rule: whatever you did by hand that a fresh copy would also need, put in seed or update. Cloned a repository — the git clone line goes in seed. Created a schema — the migration goes in seed, and its re-run in update. Changed the setup — that is already compose.yaml.
A saved environment's data comes along as it was, secrets included, and that is handled: an environment installed from a saved environment runs seed with the old secrets as OLD_* beside its fresh ones, so the seed can rotate what it knows how to — the shipped one rotates the Postgres password — and then update brings it current. The template's secrets reach no new install.
Sharing by link
On a template's page under Templates, share with a link gives it an address, /t/<you>/<name> on www. Anyone with that address can see the page and install its newest published version with install_environment "<you>/<name>", or @r2 for one in particular. Saved environments are never reachable by the link: they hold your data and history. Nothing lists it; they need the link. Make private takes the page down again. An organization's templates are shared by its admins.
A published version holds only what was committed, scanned for keys and tokens. The scan cannot tell an address or a phone number in an ordinary file from any other text: what you commit is what you share.
What someone installs is theirs from then on. Your later versions reach them only when they install again, and deleting yours does not take theirs away.
That is where sharing ends: a published version is shared by its link, and there is no listing it for everyone.
/bettik-try: a repository as an environment
You
/bettik-try https://github.com/umami-software/umami
The try skill on the box turns a repository into a running environment: install empty, clone, read what the repository says about itself in order of how much it tells — devcontainer, compose file, Dockerfile, version pins, .env.example, scripts, README last — write the five files, build, seed, read the logs, fix, report what was inferred versus guessed and how long until the address answers. Published, that environment is the answer to "how do I run this" for everyone after.
Removing
delete_template next-starter@s2 removes one saved environment; delete_template next-starter removes the whole template, every version included. Running environments installed from it are unaffected: each carries its own copy of everything. Confirm with Claude first; it asks.