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

bash
npx 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.

bash
npm 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:

PromptDefaultDescription
Project nameMy CMSDisplay name for your CMS
Git base branchmainDefault branch for PRs and content
Use pointer branch?NoSeparate branch for cms/pointers/ pointer files
Pointer branch namecms/publish-pointerOnly if pointer branch is enabled

Files created:

FilePurpose
cms/octocms.config.tsCMS schema with a demo post collection
src/app/cms/layout.tsxAdmin layout (re-exports AdminLayout + metadata from octocms/admin)
src/app/cms/[[...path]]/page.tsxAdmin catch-all (re-exports AdminApp from octocms/admin)
src/app/cms/error.tsxAdmin error boundary (re-exports AdminError from octocms/admin/error)
app/api/octocms/auth/[action]/route.tsGitHub OAuth handler (login, callback, session, logout)
app/api/octocms/agent/route.tsChat agent SSE endpoint
app/api/octocms/search/route.tsPublic search API for SearchBox
app/api/agent/proposals/accept/route.tsThin re-export of acceptProposalRoute from octocms/agent (chat-agent Phase 4)
app/api/agent/proposals/reject/route.tsThin re-export of rejectProposalRoute from octocms/agent (chat-agent Phase 4)
cms/content/post/post-001.jsonDemo post entry
cms/content/post/post-001.body.mdDemo post markdown body
cms/__generated__/Empty directory for generated types
public/media/Empty directory for uploaded images

Files modified:

FileChange
next.config.tsCreated as thin withOctoCMS() wrapper
tsconfig.jsonAdded 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.ts must not already exist (run octocms update instead)
  • package.json must 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.

bash
npm run octocms dev
npm run octocms dev -- --port 4000    # Custom port

Options:

FlagDefaultDescription
--port <n>3000Port for the dev server

What it does:

  1. Spawns next dev -p <port> as a child process with inherited stdio
  2. Watches cms/octocms.config.ts with fs.watch (300ms debounce)
  3. On config change, runs scripts/generate-types.ts via jiti
  4. 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.ts must exist
  • node_modules/.bin/next must 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.

bash
npm run octocms types:gen

Generated files:

FileContents
cms/__generated__/types.ts*Fields and *Entry interfaces, AnyEntry union, EntryMap
cms/__generated__/enums.tsCollectionName const, COLLECTION_NAMES array, select option enums, FieldFormat const
cms/__generated__/content.d.tsRaw*Fields and Raw*Entry interfaces (on-disk types before query() processing)
cms/__generated__/index.tsBarrel 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 COLLECTIONS exists in config.collections
  • Each collection has at least one field
  • Field names are valid TypeScript identifiers
  • Slug fields have a valid slugSource or exactly one entryTitle field
  • 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).

bash
npx octocms embeddings:gen

Preconditions:

  • @huggingface/transformers installed (optional peer dep). The CLI surfaces a clear error if it's missing.

Output file:

FileContents
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 — runs octocms 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.

bash
npm run octocms validate

What it checks:

CheckDescription
JSON validityFiles must be valid JSON
sys structuresys.id and sys.type must be present
sys.type matchMust match the collection directory name
fields structurefields must be an object
Required fieldsNon-empty when required: true in schema
String fieldsMust be strings (or string arrays for list: true)
Boolean fieldsMust be "true" or "false"
Number fieldsMust be numbers or null; respects min/max
Datetime fieldsMust be valid ISO 8601 strings or null
Select fieldsValues must match configured options
Reference fieldsKeys must point to existing entry files
Companion filesRequired .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.

bash
npm run octocms update

Files checked/updated:

FileExpected content
src/app/cms/layout.tsxRe-exports AdminLayout + metadata from octocms/admin
src/app/cms/[[...path]]/page.tsxRe-exports AdminApp from octocms/admin
src/app/cms/error.tsxRe-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.

bash
npm 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 JSON
  • cms/__generated__/agent-docs/collections.md — collection list, companion paths, URL mapping
  • cms/__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.

bash
npm run octocms agent-docs

What it does:

  1. Looks for AGENTS.md in the project root
  2. If missing, creates it with a default template including the OctoCMS agent docs section
  3. If present but missing the OctoCMS section (identified by <!-- octocms:agent-docs --> marker), appends it
  4. 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 edit cms/schema.json safely

Project docs (auto-generated from cms/schema.json):

  • cms/__generated__/agent-docs/schema.md — per-collection field definitions and example JSON
  • cms/__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#

FlagDescription
--help, -hShow help (global or per-command)
--version, -vShow version number
bash
npm 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.