Command line
Create or wire an app, add plugins and files, generate, check and migrate.
Two tools cover the whole lifecycle. npm create @bitakit/app (or pnpm create, yarn create, bunx @bitakit/create-app) creates a new project; npx bitakit works inside a project with any package manager. Apps made by the generator already have @bitakit/cli as a dev dependency; elsewhere add it as a dev dependency.
The command groups below are independent examples; use a new plugin name when scaffolding a complete feature. Use a matching 0.2 package set, or the local checkout workflow. Only the reference tables use <placeholders> to describe what a command accepts.
| You want to | Run |
|---|---|
| Start a new app | npm create @bitakit/app@latest my-app |
| Add BitaKit to an app you already have | npx @bitakit/cli init |
| Add a feature to your app | npx bitakit add plugin notes |
| Add one file to a feature | npx bitakit add action notes/archive |
| Write the generated files | npx bitakit generate |
| Find problems | npx bitakit doctor |
| Update BitaKit | Update BitaKit |
| Check that a page renders | npx bitakit check-page /notes |
Create a new app
npm create @bitakit/app@latest my-appThe generator asks which framework and extras you want, creates my-app and installs everything with the package manager you started it with. It never overwrites an existing project or file. Switches answer the questions up front; with npm they follow a --, as in the examples below:
| Switch | What it does |
|---|---|
--framework <name> | next or tanstack (TanStack Start is experimental) |
--features <list> | Comma-separated extras: shell (navigation frame, layouts), preferences (settings pages), quick-search (⌘K), or none |
--sample | Adds the Todo sample: todos and an activity plugin that extends it; --no-sample leaves it out |
--yes | Use the defaults for everything you did not set, without asking |
--no-install | Write the files but do not install the dependencies |
--package-manager | npm, pnpm, yarn or bun: install with this one instead of the one that started the generator |
--dry-run | Print what would be created, and whether in an existing folder, and change nothing |
--plugin | Create a standalone plugin package with a playground app instead of an app |
A minimal Next.js app, created without any questions:
npm create @bitakit/app@latest my-app -- --framework next --features none --yesAn app with the navigation frame, ⌘K search and the Todo sample:
npm create @bitakit/app@latest my-app -- --features shell,quick-search --sampleA reusable plugin package with a playground app. Its package and playground form an npm workspace, so it always installs with npm:
npm create @bitakit/app@latest my-plugin -- --pluginCreate in the current folder
A coding agent opens a folder before anything exists. Pass . so the app, its AGENTS.md and the agent skill land in that folder rather than in a subfolder the session does not see:
npm create @bitakit/app@latest . -- --yesThe folder may hold only version control, editor and agent files: .git, .gitignore, .gitattributes, .editorconfig, .DS_Store, Thumbs.db, .idea, .vscode, .agents, .claude, .codex, .cursor, AGENTS.md, CLAUDE.md, LICENSE, skills-lock.json. Anything else stops the command with a list of the unexpected entries. The package name comes from the folder name. Your files stay: AGENTS.md gains the framework and BitaKit rules once, CLAUDE.md gains the @AGENTS.md import, .gitignore gains the lines it lacks ahead of your own, so your patterns still win, agent folders are merged entry by entry and an existing skill folder is kept whole. Start a new agent session afterwards so it loads the new rules and skill. --plugin accepts . the same way.
Add BitaKit to an existing app
npx @bitakit/cli initRun it in the root of an existing Next.js or TanStack Start project. It wires the app so plugins are discovered and mounted:
| It writes or changes | Why |
|---|---|
bitakit.config.ts | Discovery settings for your app |
next.config or vite.config | Runs discovery with your build (withBitaKit or bitakit()) |
| The root layout | Mounts <BitaKitProvider> around your pages |
| A catch-all route | Renders plugin pages with <PluginPage /> |
.gitignore | Ignores the generated src/bitakit.gen.* files |
AGENTS.md, CLAUDE.md | Tell coding assistants where each task goes (one screen) |
.agents/skills/bitakit-app-development/ | The app-development agent skill for Codex and most other agents |
.claude/skills/bitakit-app-development/ | The same skill for Claude Code (/bitakit-app-development) |
init prints what it wrote (+ new, ~ changed) and what it skipped. A skill folder that already exists in either place is preserved unless you ask for an update (below). A file that already has the wiring is left alone, so running it twice is safe. It does not install packages: it lists the missing ones (@bitakit/core, @bitakit/discovery, @bitakit/ui, the adapter for your framework, and @bitakit/cli as a dev dependency for the bitakit command). Install them, then run npx bitakit generate and npx bitakit doctor.
Update BitaKit
Keep every @bitakit/* package on one release line: 0.2.x is one line, 0.3.x the next. Only packages whose shipped content changed get a patch release, so patch versions may differ within a line (for example @bitakit/cli 0.2.3 with @bitakit/core 0.2.2). Doctor accepts that and reports packages on different lines as an error.
Within a release line
The generated package.json uses caret ranges (^0.2.2), so npm update installs the newest patches of the line. Name the @bitakit/* packages your package.json lists; plain npm update would update every other dependency too:
npm update @bitakit/core @bitakit/ui @bitakit/next @bitakit/app-preferences @bitakit/shell @bitakit/quick-search @bitakit/cli @bitakit/discoveryWith pnpm use pnpm update, with Yarn yarn upgrade, with Bun bun update, each with the same package names. package.json keeps its ranges and the lockfile records the new versions. npm outdated shows which packages have a newer version. Then refresh the agent files and check the project:
npx bitakit init --update-agent-files
npx bitakit doctorTo a new release line
npm update never leaves the line its range allows. Install every @bitakit/* package at the new line in one command, here 0.3; packages you already have keep their place in dependencies or devDependencies:
npm install @bitakit/core@0.3 @bitakit/ui@0.3 @bitakit/next@0.3 @bitakit/app-preferences@0.3 @bitakit/shell@0.3 @bitakit/quick-search@0.3 @bitakit/cli@0.3 @bitakit/discovery@0.3Do not move one package alone, for example with npm install --save-dev @bitakit/cli@latest: once a new line is published, that leaves the CLI on it and the rest behind, and doctor reports mixed versions with the command that installs one release for all of them. Follow the upgrade guide of the new line when it has one (Upgrade from 0.1 covers 0.1 to 0.2), then run:
npx bitakit init --update-agent-files
npx bitakit doctor
npm run typecheckKeep agent files current
After updating the BitaKit packages, refresh the agent files:
npx bitakit init --update-agent-files| Found | What happens |
|---|---|
| A missing skill copy | Installed |
| A copy equal to this version's skill | Reported as up to date |
| An unedited copy from an older version | The whole folder is replaced; reported as updated from <old> |
| A copy you edited | Kept; delete its folder and run again to take the new version |
The BitaKit block in AGENTS.md | Replaced with the current rules; text outside the block is kept |
The installed SKILL.md records the version and a checksum of its files in its frontmatter metadata, which is how init tells an unedited copy from an edited one. Keep your own rules above or below the BitaKit block in AGENTS.md; the block belongs to BitaKit. npx bitakit doctor warns when a copy is missing or older than the installed CLI, when the two copies differ, or when the block differs from the current rules.
Add a feature or a file
A feature is a plugin. This creates src/plugins/notes/ with a page at /notes and, when Shell is installed, the one-line Action that puts it in the navigation:
npx bitakit add plugin notes--example writes a complete feature instead (the service notes.list in services/list.ts, typed events, Actions and a page); --minimal writes only that service, its events and one Action.
All three modes include an AGENTS.md inside the plugin with its starter purpose, actual files, public IDs and checks. A CLAUDE.md beside it contains only @AGENTS.md. Keep the plugin's own descriptions and contracts in that local guide and update them with the code; init --update-agent-files does not replace it.
To grow the plugin, add one file at a time. A missing plugin folder is created by its first file. These two give it an archive action and a page at /notes/archive:
npx bitakit add action notes/archive
npx bitakit add page notes/archiveAdd Settings and an optional custom page to that plugin:
npx bitakit add settings notes
npx bitakit add settings-page notesThe --example and --minimal templates already declare events; do not add that file twice. add events <plugin> is for a plugin that does not have events.ts. Discovery connects new files. The path decides the ID or route, so notes/team/invite (or notes/team.invite) creates actions/team/invite.ts with the ID notes.team.invite. Existing files are never overwritten. Inside a plugin package, give only the name.
npx bitakit add <kind> <plugin>/<name> supports these kinds:
| Kind | Name argument | File it creates | What you get |
|---|---|---|---|
action | <plugin>/<name> | actions/<name>.ts | Action <plugin>.<name> |
service | <plugin>/<name> | services/<name>.ts | services.<plugin>.<name> |
page | <plugin>/<name> | ui/pages/<name>.tsx | The route /<plugin>/<name> |
slot-definition | <plugin>/<name> | slots/<name>.ts | An owned slot contract |
settings-page | <plugin> | ui/settings/page.tsx | Custom content using the existing settings fields |
slot | <plugin>/<slot> | ui/slots/<slot>.tsx | A component in a layout slot such as app-bar.end |
dialog | <plugin>/<name> | ui/dialogs/<name>.tsx | A component an action opens with dialog |
provider | <plugin>/<name> | ui/providers/<name>.tsx | A React provider wrapped around the app |
interceptor | <plugin>/<name> | interceptors/<name>.ts | Logic that runs around actions or service calls |
config | <plugin>/<name> | configs/<name>.ts | app.config.<plugin>.<name> |
events | <plugin> | events.ts | Typed events <plugin>.<event> |
settings | <plugin> | settings.ts | User settings and a generated settings page |
layout | <family>[/<variant>] | src/layouts/<family>[/<variant>].tsx, or a plugin's ui/layouts/ with --plugin | A candidate for layout.<family>; pages opt in with export const layout |
test | <plugin> | tests/<plugin>.test.ts | A headless test at the app root that mounts the plugin |
In an app, add test writes a headless test for an existing plugin at the app root:
npx bitakit add test notestests/notes.test.ts mounts src/plugins/notes with mountPlugin, checks that the plugin starts, then stops it. When the plugin places Actions in shell.* slots, the file includes a stand-in for Shell. The command then prints what the app still needs to run the test, as commands: the missing dev dependencies, "type": "module" and a test script. It never changes package.json. Extend the file with the behavior you want to keep, as Testing plugins shows.
Generate, check and migrate
After changing plugins, regenerate the typed files and check the project:
npx bitakit generate
npx bitakit doctorYou rarely run generate yourself: the framework adapters run it during dev and build. Use it in scripts and type checks.
| Command | What it does | Useful switch |
|---|---|---|
npx bitakit generate | Writes src/bitakit.gen.* from your plugin folders | --watch keeps regenerating |
npx bitakit doctor | Reports wiring problems with a fix for each; exit code 1 when something is wrong | --json for CI |
npx bitakit info | Lists every plugin with the IDs you type: Actions, services, page URLs, events, settings and slots | --json |
npx bitakit slots | Lists every slot you can fill, including those of installed packages, with its owner, what it accepts, what your files already put there and, for replaceable parts, which candidate renders | --json |
npx bitakit migrate | Rewrites a 0.1 project to the 0.2 layout and API spellings: setup { scope }, placement slot, attach({ slot }), Foundation* → BitaKit* (also in root config files), and Core names imported from @bitakit/ui move to @bitakit/core | --dry-run only lists the changes |
Moving from 0.1? Upgrade from 0.1 walks through migrate and the few steps it leaves to you.
doctor checks package versions, provider wiring, ignored generated files, pages and links no route reaches, colliding service names, requires entries that name nothing, plugin dependency cycles, slot files that target no layout, missing package styles and agent files that are out of sync.
Check a page without a browser
Plugin pages and slots render only in the browser, so an HTTP 200 proves nothing. While the dev server runs, check-page opens a page in headless Chromium and reports what rendered and every error. It is meant for coding agents and CI jobs that have no browser:
npx bitakit check-page /notesA path resolves against --base-url (default http://localhost:3000); a full http:// URL works too. The command waits for the network to go idle and for the BitaKit runtime to finish starting, then reports:
| Field | What it tells you |
|---|---|
| Status, final URL, title | The HTTP status of the page and where redirects ended |
| Headings, main text | The h1–h3 headings and a short excerpt of <main>, as rendered after startup |
| Runtime | ready, failed, starting (not ready before the timeout) or not found (no BitaKit provider) |
| BitaKit errors | The [bitakit] console errors: startup failures, for example a plugin turned off in development, and other runtime errors |
| Console errors, page errors, warnings | What the browser console and uncaught exceptions showed |
| Failed requests | Same-origin requests that answered 400 or above, or did not complete |
| Switch | What it does |
|---|---|
--json | Prints the report as { "version": 1, ... } |
--screenshot <file> | Also saves a full-page PNG |
--timeout <ms> | Time for loading and runtime startup together (default 30000) |
--base-url <url> | Where a path is resolved |
The exit code is 1 when any error was seen (warnings do not count) and 0 otherwise. An unknown path still answers 200 with the "Page not found" state of the catch-all route, so read the headings as well as the exit code.
check-page uses the Playwright that your project installs (playwright or @playwright/test) and never installs anything itself. Without it, the command exits with 2 and prints the commands to run:
npm install --save-dev playwrightnpx playwright install chromiumOn Linux (containers, CI) install Chromium with its system libraries:
npx playwright install --with-deps chromium. A browser that cannot start also exits with 2.
The runtime state comes from <html data-bitakit-runtime>, which @bitakit/ui sets after hydration (starting, then ready or failed); browser tests can wait for the same attribute.
Build a plugin package
Inside a package created with --plugin:
npx bitakit buildIt type-checks, compiles the sources and writes dist/plugin.js; --check only type-checks. The package's package.json declares bitakit: { plugin: './plugin' }, so apps that install it discover the plugin automatically. Discovery explains what the generator reads and Plugins what the files contain.
Inspect and migrate slot placement
npx bitakit info --jsonThe version-1 snapshot has static.plugins and live: null: the CLI inspects source files,
not a running application. Each declaration carries the ID it declares (notes.add, /notes,
notes.added), read from the file without running it; a file it cannot read statically keeps
id: null and resolution: "file". See runtime inspection.
To find where something can go, list the slots:
npx bitakit slotsIt groups every slot by owner (your plugins, then installed packages such as Shell and App
Preferences) and prints one line per slot: its ID, what it accepts (actions, component or
data) and how many contributions your files add. npx bitakit slots --json prints
{ version: 1, slots, unresolved, unknownTargets }; each slot has owner, plugin, accepts,
policy, payload and payloadKeys, the declaring source file of a local slot, and its
contributions: ui/slots components and Actions whose slots list names it. unknownTargets
lists contributions to a slot nobody declares, such as a misspelled name; they render nowhere.
Like info, it reads files without running them. A value the files do not state literally is
null, for example the payload of a package slot, and packages attach their own contributions at
runtime.
To migrate old navigation group placement, choose the target explicitly:
npx bitakit migrate --navigation-slot shell.navigation --dry-runReview the preview, then remove --dry-run to apply. The migration preserves logical groups
and skips ambiguous spread objects. Doctor warns about literal navigation-group Actions without
slots when Shell is installed. The migration does not infer a destination for arbitrary groups.