BitaKit

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 toRun
Start a new appnpm create @bitakit/app@latest my-app
Add BitaKit to an app you already havenpx @bitakit/cli init
Add a feature to your appnpx bitakit add plugin notes
Add one file to a featurenpx bitakit add action notes/archive
Write the generated filesnpx bitakit generate
Find problemsnpx bitakit doctor
Update BitaKitUpdate BitaKit
Check that a page rendersnpx bitakit check-page /notes

Create a new app

npm create @bitakit/app@latest my-app

The 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:

SwitchWhat 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
--sampleAdds the Todo sample: todos and an activity plugin that extends it; --no-sample leaves it out
--yesUse the defaults for everything you did not set, without asking
--no-installWrite the files but do not install the dependencies
--package-managernpm, pnpm, yarn or bun: install with this one instead of the one that started the generator
--dry-runPrint what would be created, and whether in an existing folder, and change nothing
--pluginCreate 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 --yes

An app with the navigation frame, ⌘K search and the Todo sample:

npm create @bitakit/app@latest my-app -- --features shell,quick-search --sample

A 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 -- --plugin

Create 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 . -- --yes

The 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 init

Run 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 changesWhy
bitakit.config.tsDiscovery settings for your app
next.config or vite.configRuns discovery with your build (withBitaKit or bitakit())
The root layoutMounts <BitaKitProvider> around your pages
A catch-all routeRenders plugin pages with <PluginPage />
.gitignoreIgnores the generated src/bitakit.gen.* files
AGENTS.md, CLAUDE.mdTell 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/discovery

With 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 doctor

To 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.3

Do 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 typecheck

Keep agent files current

After updating the BitaKit packages, refresh the agent files:

npx bitakit init --update-agent-files
FoundWhat happens
A missing skill copyInstalled
A copy equal to this version's skillReported as up to date
An unedited copy from an older versionThe whole folder is replaced; reported as updated from <old>
A copy you editedKept; delete its folder and run again to take the new version
The BitaKit block in AGENTS.mdReplaced 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/archive

Add Settings and an optional custom page to that plugin:

npx bitakit add settings notes
npx bitakit add settings-page notes

The --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:

KindName argumentFile it createsWhat you get
action<plugin>/<name>actions/<name>.tsAction <plugin>.<name>
service<plugin>/<name>services/<name>.tsservices.<plugin>.<name>
page<plugin>/<name>ui/pages/<name>.tsxThe route /<plugin>/<name>
slot-definition<plugin>/<name>slots/<name>.tsAn owned slot contract
settings-page<plugin>ui/settings/page.tsxCustom content using the existing settings fields
slot<plugin>/<slot>ui/slots/<slot>.tsxA component in a layout slot such as app-bar.end
dialog<plugin>/<name>ui/dialogs/<name>.tsxA component an action opens with dialog
provider<plugin>/<name>ui/providers/<name>.tsxA React provider wrapped around the app
interceptor<plugin>/<name>interceptors/<name>.tsLogic that runs around actions or service calls
config<plugin>/<name>configs/<name>.tsapp.config.<plugin>.<name>
events<plugin>events.tsTyped events <plugin>.<event>
settings<plugin>settings.tsUser settings and a generated settings page
layout<family>[/<variant>]src/layouts/<family>[/<variant>].tsx, or a plugin's ui/layouts/ with --pluginA candidate for layout.<family>; pages opt in with export const layout
test<plugin>tests/<plugin>.test.tsA 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 notes

tests/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 doctor

You rarely run generate yourself: the framework adapters run it during dev and build. Use it in scripts and type checks.

CommandWhat it doesUseful switch
npx bitakit generateWrites src/bitakit.gen.* from your plugin folders--watch keeps regenerating
npx bitakit doctorReports wiring problems with a fix for each; exit code 1 when something is wrong--json for CI
npx bitakit infoLists every plugin with the IDs you type: Actions, services, page URLs, events, settings and slots--json
npx bitakit slotsLists 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 migrateRewrites 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 /notes

A 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:

FieldWhat it tells you
Status, final URL, titleThe HTTP status of the page and where redirects ended
Headings, main textThe h1–h3 headings and a short excerpt of <main>, as rendered after startup
Runtimeready, failed, starting (not ready before the timeout) or not found (no BitaKit provider)
BitaKit errorsThe [bitakit] console errors: startup failures, for example a plugin turned off in development, and other runtime errors
Console errors, page errors, warningsWhat the browser console and uncaught exceptions showed
Failed requestsSame-origin requests that answered 400 or above, or did not complete
SwitchWhat it does
--jsonPrints 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 playwright
npx playwright install chromium

On 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 build

It 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 --json

The 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 slots

It 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-run

Review 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.

On this page