arkor init
Scaffolds src/arkor/index.ts, src/arkor/trainer.ts, arkor.config.ts, and a starter package.json in the current directory. Use this when you want to add Arkor to an existing repo (the Quickstart scaffolding flow runs the same scaffolder one directory up).
Synopsis
Options
| Flag | Description |
|---|---|
-y, --yes | Accept defaults instead of prompting (project name from the directory name, template triage). |
--name <name> | Project name. Defaults to the current directory’s name (arkor-project if the path has no basename, e.g. /). The value is sanitised before it lands in package.json. |
--template <id> | Starter template. Options: triage, translate, redaction. Unknown ids throw before any filesystem work. |
--skip-install | Skip running the package manager’s install step after scaffolding. |
--use-npm | Force npm as the package manager. |
--use-pnpm | Force pnpm as the package manager. |
--use-yarn | Force yarn as the package manager. |
--use-bun | Force bun as the package manager. Known limitation on Windows: arkor init --use-bun populates node_modules but does not produce bun.lock, so the initial commit will not include a lockfile. Running bun install directly and using create-arkor --use-bun are not affected. |
--git | Initialise a git repo and create an initial commit, without asking. |
--skip-git | Skip git init silently. |
--allow-builds | Opt esbuild’s postinstall script into running on pnpm install. pnpm-only (yarn / npm / bun ignore the workspace yaml). Default: deny. See Postinstall scripts (pnpm 11+) below. |
--agents-md | Write AGENTS.md and CLAUDE.md to brief AI coding agents that arkor post-dates their training data. Default. |
--no-agents-md | Skip generating AGENTS.md / CLAUDE.md. An existing user-authored AGENTS.md is always preserved; the arkor-managed block (delimited by <!-- BEGIN:arkor-agent-rules --> / <!-- END:arkor-agent-rules -->) is appended on first run and replaced in place on re-scaffold. |
--git and --skip-git are mutually exclusive; passing both throws. The same goes for --agents-md and --no-agents-md.
Behavior
Default flow
By default, the command is partly interactive: it prompts for a project name, a starter template, and (when not in a git repo) whether to rungit init, and only then starts the package manager’s install step (no confirmation prompt) unless --skip-install is set. The git init confirmation is surfaced before install so you can answer every prompt upfront and walk away while install runs unattended; the actual git init + initial commit still execute after install so the generated lockfile lands in the initial commit. If no package manager can be resolved (no --use-* flag and detection from npm_config_user_agent fails), the install step is skipped and the outro prints a manual install hint.
Postinstall scripts (pnpm 11+)
When the chosen package manager is pnpm (explicitly via--use-pnpm, detected as pnpm from npm_config_user_agent such as pnpm arkor init, or implicitly because pm detection didn’t resolve and the target is a fresh empty directory), the scaffold writes a small pnpm-workspace.yaml alongside package.json:
--use-npm/--use-yarn/--use-bunis set (those toolchains don’t read it).- The target directory already contains files and no
--use-*flag is set (we don’t drop workspace-level config into someone else’s project on a guess). - An ancestor directory already has a
pnpm-workspace.yaml(the parent monorepo workspace governs; creating a nested one here would shadow it and breakworkspace:*resolution above).
pnpm-workspace.yaml already exists at the target AND pnpm is plausible (the same --use-pnpm / UA-detected pnpm / unresolved-detection conditions that gate fresh creation above; --use-npm / --use-yarn / --use-bun runs leave any existing file untouched), the scaffold patches it: it appends esbuild: false (or esbuild: true if --allow-builds is set) to the existing top-level allowBuilds: block (or creates one) without touching unrelated keys, and bows out as a no-op for the allowBuilds decision when esbuild is already pinned (allow or deny) or when the file uses the global scalar form allowBuilds: false / allowBuilds: true. Note that an allowBuilds-no-op run can still modify the file in one other way: a top-level packages: key is backfilled as packages: [] if missing, since pnpm 9 errors with “packages field missing or empty” against a pnpm-workspace.yaml that has no packages: declaration. The allowBuilds.esbuild decision is what’s preserved; the file itself may pick up that one structural key.
pnpm 11 changed the default for postinstall scripts to “deny unless explicitly approved”, and exits with ERR_PNPM_IGNORED_BUILDS (code 1) when an unapproved script is encountered. esbuild ships such a script (node install.js, which verifies/downloads the platform-specific binary), so a vanilla pnpm install against a freshly scaffolded project would otherwise fail.
The scaffolded allowBuilds: { esbuild: false } is an explicit deny: pnpm sees a decision and silently skips the script instead of erroring. esbuild itself still works, because pnpm already installs @esbuild/<platform> as an optionalDependency. yarn / npm / bun all ignore pnpm-workspace.yaml, so the file is inert under those package managers.
If you genuinely need esbuild’s postinstall to run (rare; usually a broken installer or unusual platform), pass --allow-builds:
true in pnpm-workspace.yaml after the fact. The flag is only consulted on runs that actually emit or patch pnpm-workspace.yaml, so passing it under --use-npm / --use-yarn / --use-bun is a no-op (those runs don’t touch the file at all). Re-run arkor init --use-pnpm --allow-builds later if you switch to pnpm.
Templates
| Template | Task | Output shape |
|---|---|---|
triage | Support triage | { category, urgency, summary, nextAction } |
translate | 9-language translation | { translation, detectedLanguage } |
redaction | PII redaction | { redactedText, redactedCount, tags } |
gemma-4-E4B-it) with a curated public dataset on HuggingFace.
Package manager detection
When no--use-* flag is passed, the CLI inspects npm_config_user_agent to detect the package manager that invoked it (this is the standard mechanism corepack uses, so pnpm dlx, yarn dlx, bunx, etc. all work).
If detection fails and no flag is passed, the install step is skipped and the outro prints a manual install hint.
Git policy
arkor init decides whether to run git init + initial commit by walking these rules in order:
- If the current directory is already inside a git repo, skip (and log it).
- If
--skip-gitis passed, skip. - If
--gitor-yis passed, run without asking. - In an interactive shell, prompt (default: yes).
- In a non-interactive shell with no flag, skip.
<pm> install), but git init execution still runs after install so the lockfile generated by the package manager is part of the initial commit. If commit signing fails (e.g. GPG agent isn’t running), the CLI falls back to an unsigned commit and warns; you can re-sign with git commit --amend -S later.
CI / non-interactive shells
Whenprocess.stdout is not a TTY, or CI is set in the environment, arkor init is non-interactive: prompts skip with their default values and never block waiting for input. To get a deterministic scaffold from CI:
--yes accepts the project-name and template defaults (the directory’s basename and triage), --use-pnpm (or the matching --use-<pm>) short-circuits package-manager detection, and --skip-git opts out of git init. Pass --skip-install as well if your CI image already has node_modules/.
If you forget --yes in a non-interactive shell, the command still completes (prompts use their defaults) but the experience is silent and easy to miss in logs. Prefer the explicit form above.
Claude Code (CLAUDECODE=1) strict mode
Claude Code spawns child processes with CLAUDECODE=1, and it cannot answer interactive prompts. To prevent the agent from silently scaffolding with hidden defaults, arkor init flips into a strict mode under this env var: a curated set of flags becomes required (see the list below), and a missing one produces a stderr message listing the suggested re-invocation rather than running. Project name is intentionally not required here in the common case: arkor init derives it from basename(cwd), which is the same value the interactive prompt would have suggested. The strict-mode validator still asks for --name <name> in two narrow cases that would otherwise silently fall back to the generic arkor-project slug, namely (a) when --name was passed but its value has no ASCII letter or digit (e.g. --name "!!!") and (b) when --name was omitted and the current directory’s basename has no ASCII letter or digit either (e.g. running arkor init from /tmp/!!!/). The package-manager flag is required even though it isn’t strictly a prompt, so the agent picks --use-* vs. --skip-install deliberately rather than relying on npm_config_user_agent detection.
Required flags (or pass -y/--yes to opt back into “accept all defaults”):
--template <triage|translate|redaction>--git(recommended; matches the interactive default) or--skip-git- A package-manager flag:
--use-npm/--use-pnpm/--use-yarn/--use-bun, or--skip-install --agents-md(recommended, especially under CLAUDECODE) or--no-agents-md
1 and no scaffold work happens before the early exit, so the directory stays pristine. The same rule applies to create-arkor (Quickstart documents the create-arkor specifics, including the additional [dir] / --name requirement to make the project name an explicit decision).
Errors
| Message | What it means | Fix |
|---|---|---|
Pick one of --git / --skip-git, not both. | Both git flags were passed. | Pass at most one. |
Unknown template "<id>". Available: triage, translate, redaction | --template value did not match any registered template id. | Use one of the listed ids. |
Commit signing failed: created an unsigned commit. | git init succeeded but the initial commit could not be GPG-signed. | Re-sign with git commit --amend -S once your signing setup is fixed. The repo is otherwise fine. |
Examples
Interactive:What gets written
The scaffolder touches up to ten paths: six unconditional plus two AGENTS.md-related plus two conditional package-manager configs. None of them overwrites existing user content:| Path | Behavior |
|---|---|
src/arkor/index.ts | Created with createArkor({ trainer }) if missing. Kept untouched if the file already exists. |
src/arkor/trainer.ts | Created with the chosen template’s createTrainer({...}) if missing. Kept untouched if it exists. |
arkor.config.ts | Created as a placeholder export if missing. Kept untouched if it exists. See Project structure. |
README.md | Created with a starter README if missing. Kept untouched if it exists. |
.gitignore | Created with node_modules/, dist/, .arkor/ if missing. Patched by appending .arkor/ if the file exists but does not already list it. Ok (no change) if .arkor/ is already there. |
package.json | Created with name / private / type: "module" / starter dev+build+start scripts / devDependencies.arkor if missing. Patched to add any of those scripts that are absent and to add arkor under devDependencies if absent; existing values (e.g. a custom dev script) are not overwritten. Ok (no change) if everything is already in place. |
AGENTS.md | Created with the arkor-managed block if missing (default; skip with --no-agents-md). If the file exists, the arkor-managed block (delimited by <!-- BEGIN:arkor-agent-rules --> / <!-- END:arkor-agent-rules -->) is patched in place (appended on first run, replaced inline on re-scaffold), and any user content outside the markers is preserved. Ok (no change) if the canonical block is already present and up-to-date. Kept with a warning, instead of patched, when the file contains more than one canonical managed block: auto-picking either copy is unsafe, so the scaffolder leaves the file alone and asks you to dedupe before the next re-scaffold. |
CLAUDE.md | Created with @AGENTS.md (the Claude Code import directive) if missing (default; skip with --no-agents-md). Kept untouched if the file already exists, so a project-specific CLAUDE.md is never overwritten. Skipped with a warning when AGENTS.md was kept due to duplicate managed blocks: creating the @AGENTS.md shim in that state would auto-import the unresolved duplicate rules into Claude Code’s context. The next re-scaffold creates the file once you dedupe AGENTS.md. |
pnpm-workspace.yaml | Conditional. See Postinstall scripts (pnpm 11+) for the full conditions. Created with packages: [] + allowBuilds.esbuild: false (or : true with --allow-builds) when pnpm is plausible AND no ancestor already declares one. Patched when the file already exists AND pnpm is plausible: appends esbuild: <bool> to allowBuilds: only if esbuild isn’t already pinned. Skipped for explicit --use-npm / --use-yarn / --use-bun and inside pnpm monorepo subdirs. |
.yarnrc.yml | Conditional. See packages/cli-internal/src/scaffold.ts for the full layered yarn-config policy. Created with nodeLinker: node-modules on fresh scaffolds where yarn is plausible (--use-yarn, UA-detected yarn, or no --use-* flag with UA detection failing). Kept untouched if it exists; non-default nodeLinker: produces a conflict warning, missing nodeLinker: surfaces a yarn-berry caveat. Skipped for explicit non-yarn pms and for --use-yarn against an existing non-empty dir without a positive yarn-berry signal. |
action (created / kept / patched / ok / skipped) per path so you can see exactly what changed.
Editing your AGENTS.md alongside the managed block
The arkor-managed block is identified by the BEGIN / END markers plus a signature first line (# arkor is newer than your training data). The detector requires all three on their own lines, so inline marker mentions inside backticks are safe, but a fenced code block whose body literally contains the markers and that signature heading on their own lines will look identical to a real managed block. To avoid having a re-scaffold misidentify and overwrite a documentation example you wrote yourself, follow these conventions when editing AGENTS.md:
- Quote markers inline with backticks, e.g.
`<!-- BEGIN:arkor-agent-rules -->`, rather than putting them on their own lines outside the real managed block. - If you must show the markers as a verbatim block (for example when documenting the spec for other tooling), change at least one character of the signature line in your example (e.g.
# arkor is newer than YOUR training data) so the detector does not match it. - The scaffolder also refuses to patch (and emits a warning) when it finds two or more signature-matching blocks in the file. If you see that warning, dedupe the file: typically that means deleting the older, hand-edited copy of the canonical block and letting the re-scaffold update the surviving one in place.
See also
- Quickstart for the greenfield scaffolding flow
- Project structure for what each generated file is for
arkor devfor the next step after init