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 just created so a partially scaffolded layout does
not survive a validation error.