Inkan
↑↓ move↵ open
GitHub

CLI · ADR

0002: Scaffold with init and npm create

Date

Context#

A tool that needs “only Markdown and one config file” still has a first five minutes: a config with the right import, a project folder with a _project.yml, one record that shows the format, npm scripts, a .gitignore, and a CI workflow so the site is published from day one. Writing these by hand from the README is slow and error-prone, and a decision log often starts inside an existing repository that already has a package.json.

Decision#

inkan init [dir] copies a starter repository from the package and wires up package.json. It never overwrites a file that already exists, so it is safe to run inside an existing repository. npm create @tilaven/inkan is a thin wrapper, published as create-inkan, that runs the same init in a new folder.

The starter is complete: it builds and deploys without edits. Everything in it is a plain file you can change or delete afterwards.

How to use it#

A new repository#

Terminal window
npm create @tilaven/inkan@latest my-decisions
cd my-decisions
npm install
npm run dev

npm create @tilaven/inkan [dir] resolves the @tilaven/inkan package it depends on and runs inkan init <dir>. When you give no folder name it uses decisions-site. After init you still run npm install yourself; the output ends with the exact next commands.

An existing repository#

Terminal window
npm install -D @tilaven/inkan
npx inkan init

Without an argument init targets the current folder (or --root). With npx inkan init docs the files land in docs/, which is how this site is laid out. Run the CLI from that folder afterwards, or pass --root docs.

What init creates#

FilePurpose
inkan.config.tsdefineConfig with title, tagline, url and repo to fill in.
decisions/_authors.ymlOne example author (jane.doe), to show the format.
decisions/platform/_project.ymlA first project named Platform with icon, description and owner.
decisions/platform/adr/0001-record-architecture-decisions.mdA first ADR with a Mermaid diagram, so the site is not empty.
AGENTS.mdInstructions for coding agents: where records live, how to create one, what statuses mean.
.github/workflows/decisions.ymlBuilds every pull request and publishes main to GitHub Pages.
.gitlab-ci.ymlBuilds merge requests and publishes the default branch to GitLab Pages.
Dockerfile, nginx.conf, .dockerignoreTwo-stage image: build with Node, serve dist/ with nginx.
.gitignorenode_modules/ and dist/.
package.jsonCreated, or updated in place (see below).

The dotfiles are stored in the package as _gitignore and _dockerignore and renamed on copy, because npm drops .gitignore from published packages. init prints every file it added with a + and marks package.json with ~.

How package.json is handled#

If there is no package.json, init creates one:

package.json
{
"name": "my-decisions",
"private": true,
"type": "module",
"scripts": {
"dev": "inkan dev",
"build": "inkan build",
"preview": "inkan preview",
"new": "inkan new"
},
"devDependencies": {
"@tilaven/inkan": "^0.1.0"
}
}

If one exists, init only adds to it:

  • The four scripts are added. Scripts you already have, including ones with the same names, are kept as they are.
  • "type": "module" is set only when type is missing. The config file is an ES module, so a repository that uses CommonJS keeps .ts for the config and is otherwise unaffected.
  • @tilaven/inkan is added to devDependencies at the installed version, unless it is already in dependencies.

Nothing else in the file is touched, and key order of your existing fields is preserved.

Existing files are never replaced#

init skips any file that already exists at the destination and keeps going. Running it twice is harmless. This also means a second init does not refresh an old workflow file: delete it first if you want the current one.

After init#

  1. Set title, url and repo in inkan.config.ts. repo enables the edit and “New ADR” buttons; url is used in feeds and llms.txt.
  2. Rename the platform folder or add your own projects. A folder with records is enough; _project.yml adds the display name.
  3. Push. The GitHub workflow needs Pages set to “GitHub Actions” as the source; the GitLab pipeline publishes to Pages on the default branch. Both set BASE_PATH=/<repository name> for project pages; remove that line for a custom domain. See GitHub and GitLab Pages.
  4. Optional: docker build -t decisions . for a self-hosted image. See Docker and nginx.

Note

The CI files and the Dockerfile use Node 22 and run npm install or npm ci. The Dockerfile expects a package-lock.json, so commit the lockfile that npm install created.

Consequences#

  • One command gives a repository that builds and deploys. New users see a working site before reading any documentation.
  • Safe in existing repositories: nothing is overwritten and package.json is extended, not replaced.
  • The starter is a snapshot. Files it created are yours from then on; updates to the package’s starter do not propagate to them, which is intended for CI files you will edit anyway.
  • npm create @tilaven/inkan pins the @tilaven/inkan version it was published with. Use @latest to get the current one.
  • The starter ships files for every target (GitHub, GitLab, Docker). Delete the ones you do not use.

History 1

  1. ImplementedInkan maintainers9e5e535 commit diff