Rules for working in this repo
Binding, for developers and agents alike: other repos build on this one. These are this repo’s own; the rules every repo shares are in Rules for every repo.
| Rule | Why |
|---|---|
Every command is charter’s (cmd/charter; in this repo go tool charter <command>), a project’s from its charter.toml and the repo’s from the top’s. The only npm script is npm’s prepare (charter-lib built), and a project has none: examples/examples_test.go fails otherwise. A command is listed once, in internal/cli/repo (Commands), which charter help and docs/charter/README.md are written from, and a test holds it equal to what cmd/charter runs | One way to run each thing, the same everywhere, Windows included |
A project is self-contained, set up by its charter.toml: in this repo only a Go twin reaches out, to run its TypeScript twin’s test/, which new -go copies in | charter new copies an example and it works on its own |
After changing a contract, charter spec. The Go and the TypeScript contract of an API change together | charter ci twins fails otherwise |
What ships to Workers builds with TinyGo, checked under workerd. The Go library and its Worker glue worker/ change together | go test cannot see TinyGo’s gaps; the two ship as one module |
Pins in one place each: the tools in mise.toml, TinyGo, wasm-opt, sqlc and workerd among them (charter runs them through mise, so mise installs them and Renovate moves them, and a new repo’s mise.toml starts from them: internal/pins/repo.toml, equal to mise.toml, a test); packages in go.mod (esbuild among them) and package.json (ranges; the lockfiles, committed, are exact); and in charter, what it writes or fetches when it needs it: Fern’s generators, Rust, uv and Python’s checkers in internal/fern; actionlint in the top’s charter.toml, the job runner’s actions in charter-ci.yml. TinyGo’s runtime patches are in internal/cli/build, beside the build that applies them, and fail it, saying so, when the pinned TinyGo no longer has what they change. An app gets TinyGo and wasm-opt from charter, never its own pin: internal/pins/mise.toml, equal to charter’s mise.toml (a test), which charter tasks writes into it as .config/mise/conf.d/charter.toml | A build is the same everywhere |
Every file charter writes into a repo says so in its first lines: Written by `charter <command>` and don't edit, or Started by `charter <command>` and yours to edit (Any repo) | A reader of that repo can tell what is charter’s |
| A workaround also gets a row in Upstream issues | What it waits for, and what to do then, in one table |
| After a deploy, the live test passes against it | Some bugs exist only on Cloudflare |
| Only verified results go into the docs: what ran, where, when. Performance numbers only in Benchmarks | A reader acts on it; a copied number goes stale |
A release is go tool charter release X.Y.Z (how) | It runs the check before it tags, and never waits for GitHub |
Working in a checkout
- Local checks pick free ports, so worktrees and agents can run at once. Give a server you start by hand its own
PORT, and stop it. - Heavy:
charter sdk(Docker), the Go builds (TinyGo, reused from charter’s cache when the sources are the same),test/soak.ts(redeploys).