Enforcing Taubyte Constraints
When to use
- Final review pass before
tau push / git push
- Auditing a session's actions ("did I cover all the hard rules?")
- Reviewing a teammate's PR against a Taubyte project
- Onboarding a new agent / engineer to the project
How to use this skill
Each rule is a one-liner. The link points to the skill that explains and enforces the rule. Read the rule list top-to-bottom; if any rule is unclear or violated, jump to the linked skill before continuing.
Architecture & sources of truth
- GitHub is the single source of truth. Clouds (remote and Dream) build and serve from what's pushed; never bypass git. → understanding-taubyte-architecture
- Config repo is
tau-managed. Don't hand-edit config/... YAML; mutations go through tau new / tau edit / tau delete. → editing-taubyte-resources
- Domains are CLI-managed always. Never
vim config/domains/<x>.yaml; use tau new domain / tau edit domain / tau delete domain. → creating-taubyte-resources
Naming & validation
- Project name = snake_case. Dashes break
tau validate config with invalid variable name. → bootstrapping-taubyte-projects
config/config.yaml must have a real notification.email. Empty values fail config-compile with mail: no address. → bootstrapping-taubyte-projects
- Forbidden flag: never pass
--generated-fqdn-prefix / --g-prefix to tau new domain. Use --generated-fqdn alone or --fqdn <controlled>. → creating-taubyte-resources
- Database
--min < --max. --min 1 --max 1 fails. → creating-taubyte-resources
- One function per
(path, method). Never comma-separated methods; split into separate function resources. → authoring-taubyte-function-types
Context hygiene
- Verify
tau --json current before any mutation (push, delete, inject, tau new resource). The Project field must equal the on-disk project. → selecting-taubyte-context
- After
tau new project, immediately re-run tau select project --name <same> then verify. Selection drift after new project is the usual cause of "wrong project" pushes. → bootstrapping-taubyte-projects
- Clear application after app-scoped work:
tau clear application before returning to project-level resources. → selecting-taubyte-context
Code authoring rules
- Function root layout (Go):
empty.go and go.mod at the function root. Never create a lib/ subdirectory; never hand-author main.go. Corollary: careless tau build can still generate those paths as root-owned junk — never commit them; delete, git rm --cached, and .gitignore before push. → writing-taubyte-functions, verifying-taubyte-functions
- Package name is NOT
main. Use lib (or any other name). → writing-taubyte-functions
//export <name> must equal execution.call in the function YAML. → authoring-taubyte-function-types
- HTTP handler order:
Headers().Set → Write(body) → Return(status), in that order. Returning before writing yields empty/broken responses. → writing-taubyte-functions
- YAML matcher ↔ Go literal must match exactly, including any leading
/:
databases/<x>.yaml match ↔ database.New("<match>")
storages/<x>.yaml match ↔ storage.New("<match>")
messaging/<x>.yaml channel.match ↔ function trigger.channel ↔ pubsubnode.Channel("<match>")
→ writing-taubyte-functions
Build & runtime config
- Env vars live in
.taubyte/build.sh only as export NAME=value, never in .taubyte/config.yaml. → configuring-taubyte-build-runtime
- Websites must write to
/out. Use the stack's real output directory; don't assume Vite (dist/) on a CRA repo (build/). → building-taubyte-websites
.taubyte/build.sh must be non-empty and executable. Empty scripts "build successfully" while producing nothing. → configuring-taubyte-build-runtime
Push & build triggers
--message is required when --defaults is set. Every tau push invocation in non-interactive mode must include -m "<msg>". → pushing-taubyte-projects
- Push order: project config first → wait for config build success → then code/website/library. → pushing-taubyte-projects
- Don't bypass a failing
tau push project with raw git push for the project's config/code repos. Website/library repos may use raw git as a fallback when tau push website|library is unavailable. → pushing-taubyte-projects
Dream-local rules
- First-run bootstrap:
dream inject push-all once on a fresh project before push-specific becomes reliable. → triggering-dream-builds
push-specific requires long flags + universe last to avoid Required flags "repository-id, repository-fullname" not set. → triggering-dream-builds
- Register website/library repos with the local repository service after
tau import website|library (PUT /repository/github/<repo_id>); otherwise push-specific won't trigger builds for them. → registering-dream-repositories
dream inject is Dream-only. Never run it against a remote cloud — webhooks handle that side. → deploying-to-remote-clouds
26.1. Dream requires a real git HEAD in each injected repo. Empty-branch repos (no commits) can make inject fail with getting HEAD ... reference not found. → triggering-dream-builds
Remote-cloud rules
- Project-id alignment:
config/config.yaml id: must equal the cloud's canonical project id, or every push fails with project ids not equal. → deploying-to-remote-clouds
- Generate domains only while
Cloud Type: remote (or the right Dream universe). The generated TLD is per-cloud. → deploying-to-remote-clouds
- Use
--type https (not http) for remote functions. Remote gateways expect TLS. → authoring-taubyte-function-types
- Remote website/library builds require registration + clean hooks. If remote builds are silent:
tau import website|library <name> on that cloud, ensure a single GitHub webhook (dedupe if needed), then push a commit and verify via job logs. → deploying-to-remote-clouds, pushing-taubyte-projects
Platform / shell
- Git Bash on Windows: prefix path-like flags with
MSYS_NO_PATHCONV=1 to avoid path mangling on --paths, --protocol, etc. → creating-taubyte-resources
- Inline function disk path must match the active builder. An extra
applications/ segment (or the inverse) makes builds fail with .taubyte not found under the path the job reports. Align code/.../functions/<fn>/ to that path before changing anything else. → creating-taubyte-resources
- PUT may not route like GET/DELETE even when YAML declares PUT — the edge can return
no HTTP match for method PUT while other methods work; logs may be incomplete. Prefer a dedicated POST route (e.g. /api/resource/update) as a separate function until routing is confirmed. → authoring-taubyte-function-types
- Keep scaffold
empty.go (and matching FILENAME in build.sh) unless you have an image-verified recipe — renaming to lib.go / changing the entry file without full alignment breaks TinyGo and can drop artifact.wasm. → configuring-taubyte-build-runtime, writing-taubyte-functions
- Website
.taubyte/build.sh is executable shell only — never paste HTML or other markup into it. A merged file breaks the script; replace with a minimal mkdir -p /out + copy pattern. → building-taubyte-websites
- Remote / public cloud: never ship
*.default.localtau FQDNs — the config compiler uses public DNS (1.1.1.1-class); Dream hostnames fail TXT checks. Delete + recreate domains via tau with a remote-suitable --fqdn. → deploying-to-remote-clouds, editing-taubyte-resources
- Remote:
GET / broken but /api/... OK means the website repo artifact is missing — tau push website <site> + verify AssetCid on that repo’s build job, not further function debugging by default. → pushing-taubyte-projects, deploying-to-remote-clouds, building-taubyte-websites
tau pull → already up-to-date + non-zero exit is often a CLI quirk — confirm with git fetch/git status before treating it as failure. → pushing-taubyte-projects
- Sibling dirs (
tau_notes vs tau_it) + global tau selection: tau --json current → Project must equal the config/config.yaml name: in the tree you cd’d into. → selecting-taubyte-context
Pre-push checklist (copy into the session)
Pre-push audit:
- [ ] tau --json current shows expected Cloud + Cloud Type + Project (rule 9)
- [ ] No raw YAML edits in config/ this session (rules 2, 3)
- [ ] Project name + matchers + channels are snake_case where required (rules 4, 16)
- [ ] If Go function: empty.go at root, package != main, //export matches call (rules 12, 13, 14)
- [ ] HTTP handlers: headers -> write -> Return(status) (rule 15)
- [ ] Env vars only in .taubyte/build.sh (rule 17); /out for websites (rule 18)
- [ ] tau push has -m "<message>" (rule 20)
- [ ] Push order: config first, then code/website/library (rule 21)
- [ ] Dream: bootstrap with push-all done, push-specific uses long flags + universe last (rules 23, 24)
- [ ] Remote: id alignment OK, no dream inject (rules 26, 27)
- [ ] If remote/Dream complained about `.taubyte` path: function dir matches log (rule 32); website build.sh is pure shell (rule 35)
- [ ] Remote: no lingering `localtau` domains in config when target is public FQDN (rule 36); if static page 500: website build + AssetCid verified (rule 37); `tau pull` quirks checked with git (rule 38); `tau` Project matches directory `config.yaml name` (rule 39)
Related skills
understanding-taubyte-architecture — why these rules exist
troubleshooting-taubyte-issues (if added later) — what to do when one is violated
- The skill linked next to each rule above is the canonical owner for the rule's deep coverage
1---2name: enforcing-taubyte-constraints3description: Numbered catalog of the non-negotiable Taubyte rules — naming, push ordering, domain CLI-management, matcher consistency, function layout, build/runtime env placement, and Dream vs remote build triggers — with one-line statements and cross-links to the skill that owns each rule's deep coverage. Use as a final pre-push checklist, when reviewing a teammate's change, or when you need a single audit point that touches every "must / never" rule across the collection.4---56# Enforcing Taubyte Constraints78## When to use910- Final review pass before `tau push` / `git push`11- Auditing a session's actions ("did I cover all the hard rules?")12- Reviewing a teammate's PR against a Taubyte project13- Onboarding a new agent / engineer to the project1415## How to use this skill1617Each rule is a one-liner. The link points to the skill that explains and enforces the rule. Read the rule list top-to-bottom; if any rule is unclear or violated, jump to the linked skill before continuing.1819## Architecture & sources of truth20211. **GitHub is the single source of truth.** Clouds (remote and Dream) build and serve from what's pushed; never bypass git. → [understanding-taubyte-architecture](../understanding-taubyte-architecture/SKILL.md)222. **Config repo is `tau`-managed.** Don't hand-edit `config/...` YAML; mutations go through `tau new` / `tau edit` / `tau delete`. → [editing-taubyte-resources](../editing-taubyte-resources/SKILL.md)233. **Domains are CLI-managed always.** Never `vim config/domains/<x>.yaml`; use `tau new domain` / `tau edit domain` / `tau delete domain`. → [creating-taubyte-resources](../creating-taubyte-resources/SKILL.md)2425## Naming & validation26274. **Project name = snake_case.** Dashes break `tau validate config` with `invalid variable name`. → [bootstrapping-taubyte-projects](../bootstrapping-taubyte-projects/SKILL.md)285. **`config/config.yaml` must have a real `notification.email`.** Empty values fail config-compile with `mail: no address`. → [bootstrapping-taubyte-projects](../bootstrapping-taubyte-projects/SKILL.md)296. **Forbidden flag**: never pass `--generated-fqdn-prefix` / `--g-prefix` to `tau new domain`. Use `--generated-fqdn` alone or `--fqdn <controlled>`. → [creating-taubyte-resources](../creating-taubyte-resources/SKILL.md)307. **Database `--min < --max`.** `--min 1 --max 1` fails. → [creating-taubyte-resources](../creating-taubyte-resources/SKILL.md)318. **One function per `(path, method)`.** Never comma-separated methods; split into separate function resources. → [authoring-taubyte-function-types](../authoring-taubyte-function-types/SKILL.md)3233## Context hygiene34359. **Verify `tau --json current` before any mutation** (push, delete, inject, `tau new` resource). The `Project` field must equal the on-disk project. → [selecting-taubyte-context](../selecting-taubyte-context/SKILL.md)3610. **After `tau new project`, immediately re-run `tau select project --name <same>` then verify.** Selection drift after `new project` is the usual cause of "wrong project" pushes. → [bootstrapping-taubyte-projects](../bootstrapping-taubyte-projects/SKILL.md)3711. **Clear application after app-scoped work**: `tau clear application` before returning to project-level resources. → [selecting-taubyte-context](../selecting-taubyte-context/SKILL.md)3839## Code authoring rules404112. **Function root layout (Go)**: `empty.go` and `go.mod` at the function root. **Never** create a `lib/` subdirectory; never hand-author `main.go`. **Corollary:** careless **`tau build`** can still **generate** those paths as root-owned junk — **never commit them**; delete, `git rm --cached`, and `.gitignore` before push. → [writing-taubyte-functions](../writing-taubyte-functions/SKILL.md), [verifying-taubyte-functions](../verifying-taubyte-functions/SKILL.md)4213. **Package name is NOT `main`.** Use `lib` (or any other name). → [writing-taubyte-functions](../writing-taubyte-functions/SKILL.md)4314. **`//export <name>` must equal `execution.call`** in the function YAML. → [authoring-taubyte-function-types](../authoring-taubyte-function-types/SKILL.md)4415. **HTTP handler order**: `Headers().Set` → `Write(body)` → `Return(status)`, in that order. Returning before writing yields empty/broken responses. → [writing-taubyte-functions](../writing-taubyte-functions/SKILL.md)4516. **YAML matcher ↔ Go literal must match exactly**, including any leading `/`:46 - `databases/<x>.yaml` `match` ↔ `database.New("<match>")`47 - `storages/<x>.yaml` `match` ↔ `storage.New("<match>")`48 - `messaging/<x>.yaml` `channel.match` ↔ function `trigger.channel` ↔ `pubsubnode.Channel("<match>")`49 → [writing-taubyte-functions](../writing-taubyte-functions/SKILL.md)5051## Build & runtime config525317. **Env vars live in `.taubyte/build.sh` only** as `export NAME=value`, never in `.taubyte/config.yaml`. → [configuring-taubyte-build-runtime](../configuring-taubyte-build-runtime/SKILL.md)5418. **Websites must write to `/out`.** Use the stack's real output directory; don't assume Vite (`dist/`) on a CRA repo (`build/`). → [building-taubyte-websites](../building-taubyte-websites/SKILL.md)5519. **`.taubyte/build.sh` must be non-empty and executable.** Empty scripts "build successfully" while producing nothing. → [configuring-taubyte-build-runtime](../configuring-taubyte-build-runtime/SKILL.md)5657## Push & build triggers585920. **`--message` is required when `--defaults` is set.** Every `tau push` invocation in non-interactive mode must include `-m "<msg>"`. → [pushing-taubyte-projects](../pushing-taubyte-projects/SKILL.md)6021. **Push order**: project config first → wait for config build success → then code/website/library. → [pushing-taubyte-projects](../pushing-taubyte-projects/SKILL.md)6122. **Don't bypass a failing `tau push project` with raw `git push`** for the project's config/code repos. Website/library repos may use raw git as a fallback when `tau push website|library` is unavailable. → [pushing-taubyte-projects](../pushing-taubyte-projects/SKILL.md)6263## Dream-local rules646523. **First-run bootstrap**: `dream inject push-all` once on a fresh project before `push-specific` becomes reliable. → [triggering-dream-builds](../triggering-dream-builds/SKILL.md)6624. **`push-specific` requires long flags + universe last** to avoid `Required flags "repository-id, repository-fullname" not set`. → [triggering-dream-builds](../triggering-dream-builds/SKILL.md)6725. **Register website/library repos with the local repository service** after `tau import website|library` (PUT `/repository/github/<repo_id>`); otherwise `push-specific` won't trigger builds for them. → [registering-dream-repositories](../registering-dream-repositories/SKILL.md)6826. **`dream inject` is Dream-only.** Never run it against a remote cloud — webhooks handle that side. → [deploying-to-remote-clouds](../deploying-to-remote-clouds/SKILL.md)6926.1. **Dream requires a real git HEAD in each injected repo.** Empty-branch repos (no commits) can make inject fail with `getting HEAD ... reference not found`. → [triggering-dream-builds](../triggering-dream-builds/SKILL.md)7071## Remote-cloud rules727327. **Project-id alignment**: `config/config.yaml` `id:` must equal the cloud's canonical project id, or every push fails with `project ids not equal`. → [deploying-to-remote-clouds](../deploying-to-remote-clouds/SKILL.md)7428. **Generate domains only while `Cloud Type: remote`** (or the right Dream universe). The generated TLD is per-cloud. → [deploying-to-remote-clouds](../deploying-to-remote-clouds/SKILL.md)7529. **Use `--type https` (not `http`) for remote functions.** Remote gateways expect TLS. → [authoring-taubyte-function-types](../authoring-taubyte-function-types/SKILL.md)7630. **Remote website/library builds require registration + clean hooks.** If remote builds are silent: `tau import website|library <name>` on that cloud, ensure a single GitHub webhook (dedupe if needed), then push a commit and verify via job logs. → [deploying-to-remote-clouds](../deploying-to-remote-clouds/SKILL.md), [pushing-taubyte-projects](../pushing-taubyte-projects/SKILL.md)7778## Platform / shell798031. **Git Bash on Windows**: prefix path-like flags with `MSYS_NO_PATHCONV=1` to avoid path mangling on `--paths`, `--protocol`, etc. → [creating-taubyte-resources](../creating-taubyte-resources/SKILL.md)8132. **Inline function disk path must match the active builder.** An extra `applications/` segment (or the inverse) makes builds fail with **`.taubyte` not found** under the path the job reports. Align `code/.../functions/<fn>/` to that path before changing anything else. → [creating-taubyte-resources](../creating-taubyte-resources/SKILL.md)8233. **PUT may not route like GET/DELETE** even when YAML declares PUT — the edge can return **`no HTTP match for method PUT`** while other methods work; logs may be incomplete. Prefer a **dedicated POST route** (e.g. `/api/resource/update`) as a separate function until routing is confirmed. → [authoring-taubyte-function-types](../authoring-taubyte-function-types/SKILL.md)8334. **Keep scaffold `empty.go`** (and matching `FILENAME` in `build.sh`) unless you have an image-verified recipe — renaming to `lib.go` / changing the entry file without full alignment breaks TinyGo and can drop **`artifact.wasm`**. → [configuring-taubyte-build-runtime](../configuring-taubyte-build-runtime/SKILL.md), [writing-taubyte-functions](../writing-taubyte-functions/SKILL.md)8435. **Website `.taubyte/build.sh` is executable shell only** — never paste HTML or other markup into it. A merged file breaks the script; replace with a minimal `mkdir -p /out` + copy pattern. → [building-taubyte-websites](../building-taubyte-websites/SKILL.md)8536. **Remote / public cloud: never ship `*.default.localtau` FQDNs** — the config compiler uses public DNS (`1.1.1.1`-class); Dream hostnames fail TXT checks. Delete + recreate domains via **`tau`** with a remote-suitable **`--fqdn`**. → [deploying-to-remote-clouds](../deploying-to-remote-clouds/SKILL.md), [editing-taubyte-resources](../editing-taubyte-resources/SKILL.md)8637. **Remote: `GET /` broken but `/api/...` OK** means the **website** repo artifact is missing — **`tau push website <site>`** + verify **`AssetCid`** on that repo’s build job, not further function debugging by default. → [pushing-taubyte-projects](../pushing-taubyte-projects/SKILL.md), [deploying-to-remote-clouds](../deploying-to-remote-clouds/SKILL.md), [building-taubyte-websites](../building-taubyte-websites/SKILL.md)8738. **`tau pull` → `already up-to-date` + non-zero exit** is often a CLI quirk — confirm with **`git fetch`/`git status`** before treating it as failure. → [pushing-taubyte-projects](../pushing-taubyte-projects/SKILL.md)8839. **Sibling dirs (`tau_notes` vs `tau_it`) + global `tau` selection**: **`tau --json current` → `Project`** must equal the **`config/config.yaml` `name:`** in the tree you `cd`’d into. → [selecting-taubyte-context](../selecting-taubyte-context/SKILL.md)8990## Pre-push checklist (copy into the session)9192```93Pre-push audit:94- [ ] tau --json current shows expected Cloud + Cloud Type + Project (rule 9)95- [ ] No raw YAML edits in config/ this session (rules 2, 3)96- [ ] Project name + matchers + channels are snake_case where required (rules 4, 16)97- [ ] If Go function: empty.go at root, package != main, //export matches call (rules 12, 13, 14)98- [ ] HTTP handlers: headers -> write -> Return(status) (rule 15)99- [ ] Env vars only in .taubyte/build.sh (rule 17); /out for websites (rule 18)100- [ ] tau push has -m "<message>" (rule 20)101- [ ] Push order: config first, then code/website/library (rule 21)102- [ ] Dream: bootstrap with push-all done, push-specific uses long flags + universe last (rules 23, 24)103- [ ] Remote: id alignment OK, no dream inject (rules 26, 27)104- [ ] If remote/Dream complained about `.taubyte` path: function dir matches log (rule 32); website build.sh is pure shell (rule 35)105- [ ] Remote: no lingering `localtau` domains in config when target is public FQDN (rule 36); if static page 500: website build + AssetCid verified (rule 37); `tau pull` quirks checked with git (rule 38); `tau` Project matches directory `config.yaml name` (rule 39)106```107108## Related skills109110- `understanding-taubyte-architecture` — why these rules exist111- `troubleshooting-taubyte-issues` (if added later) — what to do when one is violated112- The skill linked next to each rule above is the canonical owner for the rule's deep coverage