CLI
The octane command line: wire Octane into a project, diagnose the configuration mistakes that fail quietly, install bindings, decode runtime errors, and give your coding agent the Octane tools.
Install
pnpm add -D @octanejs/cliOr run it without installing anything:
pnpm dlx @octanejs/cli doctorEvery command takes the same global options: --json, --cwd <dir>, --yes,
--dry-run, --no-color, --verbose, and --help.
octane doctor
Octane compiles ahead of time, so a misconfiguration usually degrades instead of
erroring. doctor runs 20 checks over exactly the cases where that happens:
octane doctor
dependencies
✖ Single Octane runtime 2 copies of octane are installed
Hooks and context are keyed per runtime instance, so a second copy breaks
them without raising an error. Deduplicate before debugging anything else.
✔ Vite peer range vite 8.1.5 satisfies ^8.0.16
typescript
✖ JSX import source jsxImportSource is not set
⚠ Typecheck script typecheck runs plain tsc
✖ No wildcard .tsrx declaration declare module '*.tsrx' found in 1 file(s)
3 failing · 1 warning · 11 passing
`octane doctor --fix` can repair 2 findings.What it looks for, in the order it reports:
- environment — Node 22 or newer, and a package manager it can read.
- dependencies — that
octaneresolves, that there is only one copy of it, that your Vite satisfies Octane's peer range, that every installed@octanejs/*binding agrees with your runtime version, and that@tsrx/typescript-pluginis present once you have.tsrxfiles. - bundler — that exactly one Octane plugin is registered, distinguishing the
client-only
octane/compiler/vitefrom the full@octanejs/vite-plugin, and reporting both being wired at once. - typescript —
jsxImportSource: "octane", the TSRX language-service plugin, a sanemoduleResolution, a typecheck script that runstsrx-tscrather than plaintsc, and no wildcard.tsrxmodule declaration. - config — that
octane.config.tsloads, that every route entry resolves to a real file with no duplicate paths, and that a configured deployment adapter is installed. - source — the JSX pragma on
.tsxfiles that import Octane,forwardRefimported fromoctane(it does not exist), andReactNodewhereOctaneNodebelongs.
Fixing what it finds
octane doctor --fix--fix only touches findings whose repair is unambiguous: setting
jsxImportSource, registering the TSRX plugin, and rewriting a tsc typecheck
script to tsrx-tsc. It edits files as text splices, so the comments and
formatting in your tsconfig.json survive. Everything else prints the exact
change to make rather than guessing at it.
Add --dry-run to see what it would do, --yes to skip the confirmation, and
--only <id> or --category <name> to narrow the run:
octane doctor --category typescript
octane doctor --only deps.octane-duplicates --only ts.jsx-import-sourceoctane analyze
Where doctor checks how the project is wired, analyze checks the code. It
compiles every .tsrx through the project's own octane and reports what the
compiler found, so the output is exactly what a build would warn about, and new
compiler diagnostics appear here without a CLI change.
octane analyze
src/Form.tsrx
⚠ 12:43 `onChange` on <input type="text"> is a native commit event in Octane …
OCTANE_NATIVE_TEXT_ONCHANGE
suggestion: use `onInput` at 12:43--code <CODE> narrows to one diagnostic, --strict fails the run on warnings
as well as errors, and a file that will not parse is reported as an error
without stopping the rest of the run.
octane init
Adds Octane to a project you already have: the bundler plugin, the TypeScript
settings .tsrx needs, the scripts, and the dependencies.
octane init --mode spa # client-only app
octane init --mode fullstack # routing, SSR, and a production buildspa wires octane/compiler/vite. fullstack wires @octanejs/vite-plugin
and scaffolds an octane.config.ts with one route, plus the entry component it
points at.
It never overwrites a script you already defined, and it will not rewrite an
existing bundler config: an arbitrary vite.config.ts cannot be edited
reliably, so init prints the exact import and plugin line to add instead. Run
it on a clean tree, or pass --force, so git diff stays a usable review of
what it wrote.
Bindings and errors
octane add takes either a binding name or the React package it ports, installs
it through your package manager, and prints the surface that binding supports
plus its known divergences from upstream:
octane add react-hook-form
@octanejs/hook-form (ports react-hook-form)
Complete port of react-hook-form 7.81.0 …
Differs from upstream:
- register() returns onInput (octane's native per-keystroke event)
instead of React's synthetic onChange …When nothing ports the package, it says so rather than installing something
adjacent. octane bindings [query] browses the whole catalog, and
--divergences includes each entry's caveats.
octane explain decodes a runtime error. It takes a bare code, a docs URL, or
the entire minified message a production build prints — arguments included, so
you get the full development text back:
octane explain 'Minified Octane error #3; visit https://octanejs.dev/errors/3?args[]=%7Bfoo%3A%201%7D'octane mcp
Registers the Octane MCP server with your coding agent, so it can reach the Octane skills, the bindings catalog, and the React-to-Octane bridging tools.
octane mcp add # pick from the agents it finds
octane mcp add claude --scope project
octane mcp status
octane mcp remove cursorClaude Code, Codex, Cursor, and VS Code are supported. Where the client ships
its own CLI, that CLI does the writing, because it owns its config schema;
otherwise the config file is read, merged, backed up, and rewritten, treating a
missing or unparseable file as empty rather than failing on it. --scope user
is the default; --scope project writes into the project so the whole team
picks it up. Run inside an Octane checkout, it also sets OCTANE_REPO_ROOT.
Agents and CI
Every command is fully drivable by flags and emits a single JSON document under
--json, so a script, a CI job, and an agent all use the same path a human
does:
octane doctor --jsonPrompts only ever fill in missing input, and only in a real terminal. In a
pipe or under CI, a missing answer is a usage error naming the flag that would
have supplied it, never a hang.
Exit codes are fixed:
| Code | Meaning |
|---|---|
0 | Success |
1 | The command ran and failed |
2 | Usage error: unknown flag, missing input |
3 | doctor found error-severity problems |
octane info prints the environment and project details worth pasting into a
bug report.