chant init
Scaffold a new chant project with the standard directory structure and configuration files.
Synopsis
Section titled “Synopsis”chant init <path> --lexicon <name> [flags]chant init <path> --from <repo>@<ref>[#<member>] [--param <name>=<value>]... [--force]chant init <path> --from <dir>[#<member>] [--param <name>=<value>]... [--force]| Flag | Description |
|---|---|
-d, --lexicon <name> | Select lexicon (required) |
-t, --template <name> | Init template (e.g. node-pipeline, docker-build). Also writes the lineage lock |
--from <repo>@<ref>[#<member>] | Copy a template repository instead of a lexicon’s templates (see below) |
--from <dir>[#<member>] | Copy a template directory on disk (see From a directory) |
--param <name>=<value> | With --from, set a parameter the template declares. Repeatable (see Template parameters) |
--force | Overwrite existing files |
Description
Section titled “Description”chant init creates a new project at the specified path. It writes the directory layout, the TypeScript and lint configuration, and a sample resource file.
Generated files
Section titled “Generated files”| File | Purpose |
|---|---|
src/ sample resources | Starter resource definitions |
chant.config.ts | Project configuration (lexicons, strict lint preset) |
tsconfig.json | TypeScript compiler options |
package.json | Dependencies |
.gitignore | Ignores generated files |
With --force into a directory that already has a chant.config.ts or chant.config.json, init reads that config’s lexicons to check whether the lexicon is declared by path. If it is, package.json gets no dependency for it and the summary says where it loads from. The config is read without running it; when its lexicons cannot be read that way, init prints a note and treats the lexicon as a package. See Commands that read chant.config.ts without running it.
chant init my-infra --lexicon awscd my-infrachant build
# Overwrite existing fileschant init my-infra --lexicon aws --forceLineage
Section titled “Lineage”With --template, init also writes .chant/workspace.lock.json. The lock records the template (lexicon:<lexicon>/<template>), the lexicon package and chant versions that rendered it, and the hash of every file init wrote, so a later upgrade can tell which files you have edited. The Lineage Lock page describes the format.
Without --template, chant init writes no lock.
From a template repository
Section titled “From a template repository”--from copies a template repository at a ref into the target directory and records where it came from:
chant init my-service --from acme/starter@v1.4.0#servicechant init my-service --from https://git.example.com/acme/starter.git@mainchant init my-service --from ../starter@4624a0b6ca83bf3a2776b2d29d269e989d8b560f| Part | Meaning |
|---|---|
<repo> | A git URL, git@host:path, a local repository path, or owner/name for a GitHub repository |
<ref> | A tag, branch or commit. Required |
#<member> | Copy only this directory of the repository. Its contents land at the project root |
chant fetches the one commit with git fetch --depth 1, the only network step in chant init, listed on the network egress page. It copies every tracked file under the chosen directory, keeping the executable bit, and skips submodules, symbolic links and the template’s own lineage lock with a warning. It then writes .chant/workspace.lock.json with the commit and tree as the content address.
The template brings its own chant.config.ts and lexicons, so --from cannot be combined with --lexicon or --template. A non-empty directory needs --force, and files that already exist are kept and left out of the lineage. A directory that already has a lock is refused. --from does not install dependencies.
From a directory
Section titled “From a directory”When the template is already on disk and its repository cannot be reached, --from takes the directory instead. A host that bundles a template as plain files, without .git, instantiates it this way:
chant init my-app --from /opt/studio/tool#template --param name=billingchant init my-app --from ../starter#servicechant reads --from as a directory when it has no @ and names a directory on disk. A directory whose name contains @ is still a directory when it exists, since what is on disk wins. Anything else is read as <repo>@<ref>, and a value with no @ that names no directory is refused. #<member> picks a directory inside it, as in the git form.
Inside a git checkout, chant copies the files git would commit and leaves out what .gitignore ignores. Untracked files are copied too. Outside one, or when git is not installed, it copies every file. Either way it skips symbolic links, node_modules, .git and the template’s own lineage lock, and keeps the executable bit. Parameters work the same way, so the same directory gives the same files as the git form of the same tree. This form reaches no network.
The lock’s source has type dir, with the directory and member, and its address is the digest of the copied files alone, with no commit or tree. An absolute path is recorded as given, and a relative one is recorded relative to the project. A directory has no history, so chant workspace upgrade can only rebuild the merge base while that directory still holds the files the project was made from.
Template parameters
Section titled “Template parameters”A template can declare parameters in a chant.template.json at its root, with the files each one is substituted into (see Template manifest for the format). --param sets one and can be repeated. This names the reference workspace’s app:
chant init ws --from INTENTIUS/chant@<tag>#reference-workspace --param name="Untitled app"In each listed file, {{chant:name}} becomes Untitled app. Parameters that --param does not set take their defaults. The text up to the first = is the name, and giving one name twice is refused. chant also refuses a name the template does not declare, and its message lists the names the template does declare. A declared parameter with no value and no default is refused, and so is a value that does not match the parameter’s pattern. Nothing is written until every value checks.
The values used, defaults included, are recorded under parameters in .chant/workspace.lock.json. chant workspace upgrade substitutes the same values into the template’s newer version and into the merge base, so a file that carries a value upgrades like any other. A template without a manifest takes no --param.
A decision record in the template may pin one of the substituted files by hash (see asset pins). Init re-pins it to the file as the copy has it, so the pin holds in the copy, and lists the record under repinned in the lock. A pin that did not hold in the template is left as it was.
Template manifest
Section titled “Template manifest”The manifest sits at the root of the directory a project is made from, which is the repository root or the #<member> directory. chant reads it as JSON and runs no template code to find it. Like .chant/migrations/, the manifest is template metadata. It is not copied into the project, and the lock does not list it. The reference workspace declares one parameter in reference-workspace/chant.template.json.
{ "parameters": { "name": { "type": "string", "default": "Reference app", "pattern": "^[A-Za-z0-9][A-Za-z0-9 ._-]*$", "description": "The app's display name: the home page's title and heading, and the screen spec's" } }, "files": ["app/src/server.mjs", "design/screens/home.json", "design/screens/home.svg"]}| Field | Meaning |
|---|---|
parameters | The declared parameters, keyed by name. A name is a letter or _ followed by letters, digits or _. |
parameters.<name>.type | "string", the only type so far. |
parameters.<name>.default | Optional. The value used when --param does not set one. A parameter with no default must be given at init. |
parameters.<name>.pattern | Optional. A regular expression every value must match, the default included. Values are inserted as written, so a pattern is how a template keeps a value from breaking the file around it, for example a quote inside a JSON string. |
parameters.<name>.hostBound | Optional. Marks a value that differs per host, such as the domain a hosted service serves the app on. The value goes into parameters like any other, and the lock’s hostBound lists the files that carry it, so chant workspace export can switch it and import can switch it back (#2552). |
parameters.<name>.description | Optional. For people reading the manifest. |
files | The paths, relative to the manifest’s directory, whose placeholders are substituted. Each must be a file in the template. Files not listed are copied byte for byte. |
$comment | Optional. Ignored. |
Any other key is refused.
A listed file marks each place a value goes with {{chant:<name>}}. The chant: prefix keeps the placeholder apart from the syntax a template file may already hold. TypeScript template literals (${x}) and workflow expressions (${{ x }}) are left alone, and so is Handlebars or Mustache ({{x}}). In the reference workspace, app/src/server.mjs holds export const APP_NAME = "{{chant:name}}";.
There is no escape syntax. A file that needs the literal text {{chant: can be left out of files. A placeholder naming an undeclared parameter is an error in the template, reported at init. Substitution is one pass, so a value that looks like a placeholder is inserted as written.
When the template’s newer version declares a parameter the lock does not have, chant workspace upgrade uses its default and records it. If that parameter has no default, the upgrade is refused. A recorded parameter the newer version no longer declares is dropped from the lock.
Lexicon scaffold mode
Section titled “Lexicon scaffold mode”To scaffold a new lexicon plugin project (for lexicon authors), use:
chant init lexicon <name> [path] [--force]This creates a lexicon plugin project with a stub for every required lifecycle method. See init lexicon.
# Scaffold a new lexiconchant init lexicon k8s
# Scaffold at a custom pathchant init lexicon gcp ./my-gcp-lexiconExit Codes
Section titled “Exit Codes”| Code | Meaning |
|---|---|
| 0 | Project created successfully |
| 1 | Error (target path is not empty or could not be created) |