Show navigationHide navigation
OctoCMS CLI
Command-line tools for managing an OctoCMS project. The CLI lives at octocms/cli/ and is the bin entry for the octocms/cms npm package.
Running the CLI#
During development (before npm publish):
bash# Via npm script (recommended) npm run octocms <command> [options] # Examples npm run octocms init npm run octocms validate npm run octocms types:gen npm run octocms embeddings:gen npm run octocms dev npm run octocms update npm run octocms agent-docs
After npm publish (future):
bashnpx octocms <command> [options]
Commands#
octocms init#
Initialize OctoCMS in an existing Next.js project. Creates the schema file, admin route files, demo content, and updates next.config.ts and tsconfig.json.
bashnpm run octocms init npm run octocms init -- --yes # Accept all defaults (non-interactive) npm run octocms init -- -y # Shorthand
init only scaffolds files — it doesn't touch your package.json. The "Next steps" output prints the exact npm install octocms@<version> <required peer deps> command you need to run before npm run dev. Copy-paste it (swap npm install for your package manager's add command if you use pnpm / yarn / bun).
Interactive prompts:
| Prompt | Default | Description |
|---|---|---|
| Project name | My CMS | Display name for your CMS |
| Git base branch | main | Default branch for PRs and content |
| Use pointer branch? | No | Separate branch for cms/pointers/ pointer files |
| Pointer branch name | cms/publish-pointer | Only if pointer branch is enabled |
Files created:
| File | Purpose |
|---|---|
cms/octocms.config.ts | CMS schema with a demo post collection |
src/app/cms/layout.tsx | Admin layout (re-exports AdminLayout + metadata from octocms/admin) |
src/app/cms/[[...path]]/page.tsx | Admin catch-all (re-exports AdminApp from octocms/admin) |
src/app/cms/error.tsx | Admin error boundary (re-exports AdminError from octocms/admin/error) |
app/api/octocms/auth/[action]/route.ts | GitHub OAuth handler (login, callback, session, logout) |
app/api/octocms/agent/route.ts | Chat agent SSE endpoint |
app/api/octocms/search/route.ts | Public search API for SearchBox |
app/api/agent/proposals/accept/route.ts | Thin re-export of acceptProposalRoute from octocms/agent (chat-agent Phase 4) |
app/api/agent/proposals/reject/route.ts | Thin re-export of rejectProposalRoute from octocms/agent (chat-agent Phase 4) |
cms/content/post/post-001.json | Demo post entry |
cms/content/post/post-001.body.md | Demo post markdown body |
cms/__generated__/ | Empty directory for generated types |
public/media/ | Empty directory for uploaded images |
Files modified:
| File | Change |
|---|---|
next.config.ts | Created as thin withOctoCMS() wrapper |
tsconfig.json | Added octocms/* path aliases |
Example output:
OctoCMS — Initialize a new project ? Project name (My CMS): My Blog ? Git base branch (main): main ? Use a separate published pointer branch? (y/N): n Creating files... ✓ cms/octocms.config.ts ✓ app/cms/layout.tsx ✓ app/cms/[[...path]]/page.tsx ✓ app/cms/error.tsx ✓ cms/content/post/post-001.json ✓ cms/content/post/post-001.body.md Updating configuration... ✓ cms/octocms.config.ts — OctoCMS schema ✓ next.config.ts — Next.js wrapper ✓ tsconfig.json — added octocms/* path aliases Next steps: 1. Add GitHub App credentials to .env.local (see README.md) 2. Run: npm run octocms types:gen 3. Run: npm run dev 4. Visit: http://localhost:3000/cms
Preconditions:
cms/octocms.config.tsmust not already exist (runoctocms updateinstead)package.jsonmust exist in the current directory
octocms dev#
Start the Next.js development server and watch cms/octocms.config.ts for changes. When the config file is modified, types are automatically regenerated.
bashnpm run octocms dev npm run octocms dev -- --port 4000 # Custom port
Options:
| Flag | Default | Description |
|---|---|---|
--port <n> | 3000 | Port for the dev server |
What it does:
- Spawns
next dev -p <port>as a child process with inherited stdio - Watches
cms/octocms.config.tswithfs.watch(300ms debounce) - On config change, runs
scripts/generate-types.tsvia jiti - Forwards SIGINT/SIGTERM to the child process
Example output:
OctoCMS — Development server Starting Next.js dev server on port 3000... Watching cms/octocms.config.ts for changes... ▲ Next.js 16.2.2 - Local: http://localhost:3000 ... ↻ Config changed — regenerating types... ✓ Types regenerated
Preconditions:
cms/octocms.config.tsmust existnode_modules/.bin/nextmust be available
octocms types:gen#
Generate TypeScript types from cms/octocms.config.ts. Produces the files in cms/__generated__/ that power type-safe queries and autocomplete.
bashnpm run octocms types:gen
Generated files:
| File | Contents |
|---|---|
cms/__generated__/types.ts | *Fields and *Entry interfaces, AnyEntry union, EntryMap |
cms/__generated__/enums.ts | CollectionName const, COLLECTION_NAMES array, select option enums, FieldFormat const |
cms/__generated__/content.d.ts | Raw*Fields and Raw*Entry interfaces (on-disk types before query() processing) |
cms/__generated__/index.ts | Barrel re-export of types.ts and enums.ts |
Example output:
OctoCMS — Generate types Validating config... ✓ 6 collections validated Generating types... ✓ cms/__generated__/types.ts ✓ cms/__generated__/enums.ts ✓ cms/__generated__/content.d.ts ✓ cms/__generated__/index.ts
Validation checks (before generating):
- Every collection in
COLLECTIONSexists inconfig.collections - Each collection has at least one field
- Field names are valid TypeScript identifiers
- Slug fields have a valid
slugSourceor exactly oneentryTitlefield - Select options have unique values and valid defaults
- Reference fields point to existing collections
- Conditional branches have unique keys and valid nested fields
Exit code: 1 if config validation fails, 0 on success.
octocms embeddings:gen#
Generate cms/__generated__/embeddings.json, the retrieval index used by the chat agent only — public site search, the admin CommandK palette, and the MediaManager search input do not use embeddings (see the Search-vs-Embeddings table in docs/chat-agent.md). Walks every content entry, embeds new or changed entries via @huggingface/transformers (Xenova/bge-small-en-v1.5, 384 dims), and writes the merged store. Re-running on unchanged content is a fast no-op (sha256 hash skip per entry).
bashnpx octocms embeddings:gen
Preconditions:
@huggingface/transformersinstalled (optional peer dep). The CLI surfaces a clear error if it's missing.
Output file:
| File | Contents |
|---|---|
cms/__generated__/embeddings.json | { model, dim, entries: { [path]: { hash, vec } } } — base64-encoded Float32Array per entry, sorted keys for stable diffs |
Example output:
OctoCMS — Generate embeddings Validating config... ✓ 6 collections validated Discovering entries... ✓ 10 entries Loading existing store (if any)... ✓ 10 existing vectors Embedding entries (model loads on first run; ~3–10s cold)... ↻ 1 / 10 ↻ 5 / 10 ↻ 10 / 10 ✓ cms/__generated__/embeddings.json (10 vectors, dim=384)
When to run:
- Once after enabling the chat agent for the first time.
- After a bulk content import outside the CMS UI.
- In CI as a drift check (
embeddings:check— runsoctocms embeddings:gen && git diff --exit-code -- cms/__generated__/embeddings.json).
Day-to-day edits in the CMS update the store automatically as part of the same Git commit, so most users only run this manually after enabling the feature.
See docs/chat-agent.md for the full pipeline overview.
octocms validate#
Validate all content entries (cms/content/**/*.json) against the CMS schema. Checks structure, field types, required fields, select values, reference targets, and companion files.
bashnpm run octocms validate
What it checks:
| Check | Description |
|---|---|
| JSON validity | Files must be valid JSON |
sys structure | sys.id and sys.type must be present |
sys.type match | Must match the collection directory name |
fields structure | fields must be an object |
| Required fields | Non-empty when required: true in schema |
| String fields | Must be strings (or string arrays for list: true) |
| Boolean fields | Must be "true" or "false" |
| Number fields | Must be numbers or null; respects min/max |
| Datetime fields | Must be valid ISO 8601 strings or null |
| Select fields | Values must match configured options |
| Reference fields | Keys must point to existing entry files |
| Companion files | Required .md/.mdx files must exist for markdown/richtext |
Example output (all valid):
OctoCMS — Validate content Validating 6 collections... ✓ post — 2 entries ✓ item — 3 entries ✓ homePage — 1 entry ✓ blog — 1 entry ✓ author — 2 entries ✓ role — 2 entries ✓ All 11 entries valid.
Example output (with errors):
OctoCMS — Validate content Validating 6 collections... ✗ post — 2 entries, 1 with errors ✓ item — 3 entries ... ✗ post/post-456.json • title: Required field "Title" is empty • publishedAt: Invalid datetime format ✗ 2 errors found.
Exit code: 1 if any errors found, 0 if all entries valid.
octocms update#
Regenerate admin route files in src/app/cms/. Useful after upgrading octocms to a new version that may have changed the admin route structure.
bashnpm run octocms update
Files checked/updated:
| File | Expected content |
|---|---|
src/app/cms/layout.tsx | Re-exports AdminLayout + metadata from octocms/admin |
src/app/cms/[[...path]]/page.tsx | Re-exports AdminApp from octocms/admin |
src/app/cms/error.tsx | Re-exports AdminError from octocms/admin/error (client component) |
app/api/agent/proposals/accept/route.ts (or src/app/...) | Thin re-export of acceptProposalRoute from octocms/agent. Created if missing, never overwritten if you've customised it. |
app/api/agent/proposals/reject/route.ts (or src/app/...) | Thin re-export of rejectProposalRoute from octocms/agent. Same skip-if-customised behaviour. |
Auto-migration from the legacy deep-import catch-all. When [[...path]]/page.tsx matches export { AdminApp as default } from 'octocms/admin/AdminApp' byte-for-byte, it's rewritten to import from the octocms/admin barrel. Same for layout.tsx if it uses the deep import. Customised files are preserved.
The migration is idempotent — re-running on an already-migrated tree is a no-op.
Example output (after deep-import → barrel migration):
OctoCMS — Update admin routes Using src/app/ as the Next.js root. ↻ src/app/cms/layout.tsx — updated (legacy → barrel import) ↻ src/app/cms/[[...path]]/page.tsx — updated (legacy → barrel import) ↻ src/app/cms/error.tsx — created Admin routes have been updated.
npm run agent-docs:gen#
Regenerate project-specific AI agent docs in cms/__generated__/agent-docs/ from cms/schema.json. Use this after schema changes when you only need fresh context for the chat agent or a local LLM — without regenerating TypeScript types.
bashnpm run agent-docs:gen npm run agent-docs:check # fail if agent-docs drift (part of npm run checks)
Files written:
cms/__generated__/agent-docs/schema.md— per-collection field definitions and example JSONcms/__generated__/agent-docs/collections.md— collection list, companion paths, URL mappingcms/__generated__/agent-docs/index.md— project index linking package + project docs
npm run types:gen writes the same agent-doc files along with cms/__generated__/*.ts. The visual schema editor commits all of them atomically on save.
octocms agent-docs#
Inject AI agent documentation links into AGENTS.md. Creates the file if it doesn't exist, appends the OctoCMS section if missing, or replaces an existing section when the marker is already present.
bashnpm run octocms agent-docs
What it does:
- Looks for
AGENTS.mdin the project root - If missing, creates it with a default template including the OctoCMS agent docs section
- If present but missing the OctoCMS section (identified by
<!-- octocms:agent-docs -->marker), appends it - If the section already exists, replaces it with the current doc paths
Section injected:
The command adds a section pointing AI agents to two doc layers:
Package docs (content-agnostic):
octocms/docs/overview.md— generic content management (CRUD, entry shape, status values)octocms/docs/editing-schema.md— how to editcms/schema.jsonsafely
Project docs (auto-generated from cms/schema.json):
cms/__generated__/agent-docs/schema.md— per-collection field definitions and example JSONcms/__generated__/agent-docs/collections.md— collection list and URL mapping
Example output (file created):
OctoCMS — Agent documentation ✓ AGENTS.md — created with OctoCMS agent docs section Package docs: octocms/docs/overview.md, octocms/docs/editing-schema.md Project docs: cms/__generated__/agent-docs/ (regenerate with npm run agent-docs:gen)
Example output (section appended):
OctoCMS — Agent documentation ↻ AGENTS.md — appended OctoCMS agent docs section Package docs: octocms/docs/overview.md, octocms/docs/editing-schema.md Project docs: cms/__generated__/agent-docs/ (regenerate with npm run agent-docs:gen)
Example output (section updated):
OctoCMS — Agent documentation ↻ AGENTS.md — updated OctoCMS agent docs section Package docs: octocms/docs/overview.md, octocms/docs/editing-schema.md Project docs: cms/__generated__/agent-docs/ (regenerate with npm run agent-docs:gen)
Global Options#
| Flag | Description |
|---|---|
--help, -h | Show help (global or per-command) |
--version, -v | Show version number |
bashnpm run octocms -- --help npm run octocms -- --version npm run octocms init -- --help
Architecture#
File structure#
octocms/cli/ index.ts # CLI entry point — argv parser + command dispatcher index.test.ts # Argument parser tests commands/ init.ts # octocms init init.test.ts dev.ts # octocms dev dev.test.ts typesGen.ts # octocms types:gen typesGen.test.ts validate.ts # octocms validate validate.test.ts update.ts # octocms update update.test.ts agentDocs.ts # octocms agent-docs agentDocs.test.ts lib/ logger.ts # ANSI-colored CLI output helpers project.ts # resolveProjectRoot(), loadProjectConfig() project.test.ts codegen.ts # Type generation functions (shared with scripts/) codegen.test.ts validateConfig.ts # Schema config validation (shared with scripts/) validateConfig.test.ts contentValidator.ts # Content entry validation for `octocms validate` contentValidator.test.ts templates.ts # File templates for init/update commands templates.test.ts
Shared code#
The codegen and config validation functions are shared between the CLI and the existing npm scripts:
octocms/cli/lib/codegen.ts— type generator functions (generateTypes,generateEnums, etc.)octocms/cli/lib/validateConfig.ts— schema config validation (validateConfig)
Both scripts/generate-types.ts and scripts/generate-docs.ts import from these modules. This ensures the CLI and scripts always use the same logic.
Config loading#
The CLI resolves the project root by walking up from process.cwd() until it finds a next.config.ts containing withOctoCMS. For commands that need the config object (like types:gen and validate), it uses jiti to dynamically load cms/octocms.config.ts with path alias resolution.
npm package integration#
The octocms/package.json declares:
json{ "bin": { "octocms": "./dist/cli/index.js" } }
When octocms/cms is published and installed via npm, users will be able to run npx octocms <command> directly.