Lay out a project
Goal: structure a multi-file project with source and tests, and build it.
A project is a directory containing a bynk.toml manifest and your .bynk
files. The conventional layout keeps source and tests in sibling trees:
my-project/├── bynk.toml├── src/│ ├── counters.bynk # context counters│ └── quantities.bynk # commons quantities└── tests/ ├── counters.bynk # suite counters └── quantities.bynk # suite quantitiesThis is convention, not a rule. Test-ness is structural — a suite block is
a test wherever it lives — so you can put tests beside the code they exercise, or
even in the same file:
// src/quantities.bynk — an atomic file: the commons and its tests togethercommons quantities { fn double(n: Int) -> Int { n + n }}
suite quantities { case "doubles" { expect double(3) == 6 }}When you build, the suite is stripped — never type-checked for the build,
never emitted to the deployable — while bynkc test compiles and runs it. There
is no .test.bynk suffix: every file is just .bynk, and the suite keyword is
what marks a test.
The manifest
Section titled “The manifest”bynk.toml names the project. Layout config is optional:
[project]name = "my-project"version = "0.1.0"
[paths]# Both keys are optional. `include` defaults to the conventional roots that# exist (`src`, and `tests` when present), or the project root itself — so a# conventional or a flat project needs no `[paths]` at all.exclude = ["vendor"] # skip subtrees (monorepo, vendored, generated .bynk)See the bynk.toml reference for every key. The tool always
skips its own out/ and node_modules/ caches and dot-directories.
Path identity
Section titled “Path identity”A source unit’s path must match its qualified name. A file declaring
context counters must be counters.bynk; one declaring context commerce.orders
must be commerce/orders.bynk (under an include root). A suite has no such
requirement — it names its target, so it is legal in any file.
Source mismatches are reported as
bynk.project.inconsistent_commons_name.
Build and test
Section titled “Build and test”bynkc compile . --output out # compile the project (suites stripped)bynkc test . # compile and run the testsbynkc check . # type-check onlyWorkspaces
Section titled “Workspaces”A workspace groups several projects in one repository. Its root holds a
bynk.toml with a [workspace] table naming its members, and nothing
else of a project’s: no [project] or [package], and no sources.
shop/├── bynk.toml # [workspace] members = ["packages/*", "apps/shop"]├── apps/│ └── shop/│ ├── bynk.toml # [project] name = "shop"│ └── src/└── packages/ ├── money/ │ ├── bynk.toml # [package] name = "acme/money" │ └── src/ └── fx/ ├── bynk.toml └── src/[workspace]members = ["packages/*", "apps/shop"]exclude = ["packages/scratch"]Each member is an ordinary project with its own bynk.toml. A member is any
directory a members pattern matches (* matches within one directory
level) that no exclude pattern matches. A project nested under the root that
no pattern lists isn’t a member. A workspace whose patterns match no member is
an error.
Which commands run where.
- At the root,
bynk check,bynk fmt .andbynk testrun over every member in path order. Every member runs even when an earlier one fails, and the command fails if any member does.bynk checkandbynk testhead each member’s report with its path (── packages/money ──).bynk check --format shortadds no headers, and its paths are relative to the root, so each line still opens in an editor.bynk fmtnames files relative to the root.bynk test --format json,--outputand--againsteach belong to one project, so they are refused at the root.bynk devandbynk deployrun one project, and refuse at the root: run them inside a member.
- Inside a member, every command behaves exactly as in a standalone
project. Deploy state (
bynk.deploy.lock) stays per member.
A workspace root may also hold [registries], which then apply to every
member; a member’s own [registries] is refused, and so is a member’s own
[workspace]. A workspace has no name and doesn’t appear in any package’s
identity: it is a build grouping only.