cabin new and cabin init
cabin new and cabin init generate a minimal single-package project layout: a cabin.toml, a
src/ tree, a public header tree (library scaffolds only), and a .gitignore. Both commands share
the same scaffold logic, so the generated bytes match exactly for the same kind / name pair.
cabin new <path>creates a new directory at<path>and fills it with the scaffold.<path>must not already exist.cabin initinitializes the current directory. The directory may already contain user files; the scaffold never overwrites them.
The default scaffold kind is a binary package (an executable target). Pass --lib to
generate a library package (a library target) instead. --bin and --lib are mutually
exclusive; passing both produces a clear error and no filesystem mutation.
Binary scaffold (default)
<dest>/
cabin.toml
src/
main.cc
.gitignore
The manifest declares a single executable target named after the package:
[package]
name = "hello"
version = "0.1.0"
[target.hello]
type = "executable"
sources = ["src/main.cc"]
src/main.cc is a minimal int main that prints a greeting and returns zero. An existing
src/main.cc is preserved unchanged so re-running cabin init over a partially scaffolded project
never clobbers user code.
Library scaffold (--lib)
<dest>/
cabin.toml
include/
<package>/
<package>.hpp
src/
<package>.cc
.gitignore
The manifest declares a single library target with a public include/ directory:
[package]
name = "greeter"
version = "0.1.0"
[target.greeter]
type = "library"
sources = ["src/greeter.cc"]
include-dirs = ["include"]
The generated header (include/<package>/<package>.hpp) and the implementation source
(src/<package>.cc) define a minimal add(int, int) function inside a namespace derived from the
package name. Hyphens in the package name are mapped to underscores when forming the C++ namespace
identifier (so hello-world becomes namespace hello_world); the on-disk file paths keep the
original package name.
Existing header / source files at those paths are preserved unchanged.
.gitignore
Both cabin new and cabin init create a .gitignore at the destination when one does not already
exist. An existing .gitignore is preserved verbatim - Cabin never appends to it or rewrites it.
The generated file ignores Cabin’s default build-output directories:
/build/
/dist/
cabin.lock is intentionally not ignored. Cabin recommends committing the lockfile so
collaborators and CI converge on the same resolution; see lockfile.md.
Package name
When --name is omitted, the package name is derived from the final path component (cabin new path/to/hello-world produces hello-world). If that component is empty, contains characters
outside the allowed alphabet (ASCII letters, digits, _, -), or starts with a ., Cabin falls
back to the literal name cabin-package.
Pass --name <name> to override the derived name. Names containing whitespace or unsupported
characters are rejected with a clear error.
Errors
cabin new and cabin init produce actionable diagnostics for:
--binused together with--lib;- an invalid package name (empty, whitespace, or characters outside the allowed alphabet);
- a destination that already exists (for
cabin new- the message suggestscabin initfor that case); - a parent directory that does not exist (for
cabin new); - a pre-existing
cabin.toml(rejected; nothing is overwritten).
When validation fails, cabin new removes the destination directory it created so a partially
scaffolded layout does not survive a validation error.