diff --git a/.changeset/phase-r1-rules-skills-mcp-parity.md b/.changeset/phase-r1-rules-skills-mcp-parity.md new file mode 100644 index 0000000..59a4b13 --- /dev/null +++ b/.changeset/phase-r1-rules-skills-mcp-parity.md @@ -0,0 +1,86 @@ +--- +"@contentrain/mcp": minor +"@contentrain/rules": minor +"@contentrain/skills": minor +--- + +fix(rules,skills,mcp): align rules/skills catalogs with MCP tool surface + `cr/*` branches, lock with parity tests + +Closes the two P1 drift findings and installs a drift-detection +mechanism so they don't come back: + +1. **Missing `contentrain_merge`** — `@contentrain/rules` public + `MCP_TOOLS` listed 15 tools. `@contentrain/mcp` registers 17 + (including `merge` and the new `doctor`). `@contentrain/skills` + tool reference also jumped from `submit` straight to `bulk`. +2. **Legacy `contentrain/{operation}/...` branch namespace** — + MCP's `buildBranchName()` returns `cr/...` (Phase 7 migration) + and `checkBranchHealth` filters on `cr/`, but essential rules, + review/normalize prompts, and multiple skills still taught the + old prefix. Agents following the shipped guidance would look + for branches that don't exist. + +### `@contentrain/mcp` + +- New public export `TOOL_NAMES: readonly string[]` in + `./tools/annotations`, frozen and derived from `TOOL_ANNOTATIONS`. + Single source of truth — parity tests in sibling packages now + import this instead of hardcoding. +- New `./tools/annotations` subpath export in `package.json`. +- Build script now emits the new subpath. + +### `@contentrain/rules` + +- `MCP_TOOLS` extended to **17 tools** (`contentrain_merge`, + `contentrain_doctor` added in catalog order). +- `essential/contentrain-essentials.md` — tool table gains `doctor` + row; feature-branch pattern rewritten to `cr/{operation}/...`; + health-threshold language mentions `cr/*`. +- `prompts/review-mode.md` — every legacy `contentrain//...` + reference → `cr//...` (pattern + type examples). +- `prompts/normalize-mode.md` — branch pattern table rewritten. +- `shared/workflow-rules.md` — branch pattern spec rewritten. +- `tests/mcp-parity.test.ts` (new) — 4 tests: + - `MCP_TOOLS` ↔ `TOOL_NAMES` exact match + - Essential guardrails mention every MCP tool + - `buildBranchName()` output starts with `cr/` (sampled across scopes) + - Rules docs do not contain the legacy `contentrain//...` + branch prefix (false-positive filter excludes `.contentrain/` paths) +- `package.json` — `@contentrain/mcp: workspace:*` added as devDep + for the parity test. + +### `@contentrain/skills` + +- `skills/contentrain/references/mcp-tools.md` — new sections for + `contentrain_merge` (after submit) and `contentrain_doctor` + (new Doctor Tools subsection). Submit description updated to + `cr/*` branches. +- `skills/contentrain/references/mcp-pipelines.md` + `workflow.md` + — branch-naming spec + examples rewritten to `cr/*`. +- `skills/contentrain-normalize/SKILL.md` + `references/extraction.md` + + `references/reuse.md` — 4 stale `contentrain/normalize/*` + references → `cr/normalize/*`. +- `skills/contentrain-translate/SKILL.md` — translate branch pattern + updated. +- `tests/mcp-parity.test.ts` (new) — 2 tests: + - `references/mcp-tools.md` has an `### ` heading for every + MCP tool + - 7 key skill docs do not contain the legacy branch prefix +- `package.json` — `@contentrain/mcp: workspace:*` devDep. + +### Monorepo + +- `tsconfig.json` paths — `@contentrain/mcp/tools/*` alias added so + TypeScript + vitest resolve the new subpath from source during dev. + +### Verification + +- `oxlint` across rules + skills + mcp/tools → 0 warnings. +- `tsc --noEmit` across rules, skills, mcp → 0 errors. +- `@contentrain/rules` vitest → 16/16 (was 12 — 4 new parity tests). +- `@contentrain/skills` vitest → 85/85 (was 83 — 2 new parity tests). + +### Tool surface + +No MCP tool behaviour changes. The new `TOOL_NAMES` export is +additive; everything else is documentation + tests. diff --git a/.changeset/phase-r2-package-readmes.md b/.changeset/phase-r2-package-readmes.md new file mode 100644 index 0000000..28edcfb --- /dev/null +++ b/.changeset/phase-r2-package-readmes.md @@ -0,0 +1,64 @@ +--- +"@contentrain/types": patch +"@contentrain/mcp": patch +"contentrain": patch +"@contentrain/query": patch +"@contentrain/rules": patch +"@contentrain/skills": patch +--- + +docs: phase R2 — align every package README with current public surface + +Each package README was cross-checked against its `src/` exports, +`package.json` `exports` map, and (for MCP) the `TOOL_ANNOTATIONS` +registry. Every claim in the rewritten READMEs is verified against the +current codebase. + +### `@contentrain/types` +- Adds the provider-contracts section (`RepoProvider`, `RepoReader`, + `RepoWriter`, `ProviderCapabilities`, `Commit`, `Branch`, `FileDiff`, + `MergeResult` with optional `sync?: SyncResult`, `LOCAL_CAPABILITIES`). +- Documents `NormalizePlan*` types, `CONTENTRAIN_BRANCH` constant, + `SECRET_PATTERNS`, `ModelSummary`. +- Keeps the browser-compatible validate/serialize surface described + for Studio integration. + +### `@contentrain/mcp` +- Tool count corrected to **17** (was 13/16 depending on section). + `contentrain_doctor` row added to the annotations table. +- Subpath export list now lists every entry in `package.json`: + `/core/doctor`, `/core/contracts`, `/core/ops`, `/core/overlay-reader`, + `/tools/annotations`. +- `mergeBranch` description notes the `cr/*` branch naming. +- Capability gates section mentions doctor alongside scan/apply. + +### `contentrain` (CLI) +- Global `--debug` flag + `CONTENTRAIN_DEBUG` env var documented. +- New flags table: `--json` on status/doctor/validate/generate/diff/ + describe/scaffold; `--watch` on validate/generate; `--demo` and + `--mcpHttp` / `--authToken` on serve. +- `setup`, `skills`, `merge`, `describe`, `describe-format`, `scaffold` + commands added to the command table. +- Secure-by-default HTTP transport auth described. + +### `@contentrain/query` +- Clarified that `contentrain generate` (CLI) is the recommended entry + point and `contentrain-query generate` is the programmatic path. +- Added TypeScript snippet for the programmatic `generate()` API. + +### `@contentrain/rules` +- `MCP_TOOLS` length corrected to **17** (includes `contentrain_merge` + and `contentrain_doctor`). +- New Parity section that explains how drift is prevented by + `tests/mcp-parity.test.ts`. +- `shared/` directory catalog added (11 rule files, previously + undocumented). +- Context bridge section includes the 4 stack templates. + +### `@contentrain/skills` +- Reference discovery pattern documented (`references/*.md` loaded on + demand, tier table for progressive disclosure). +- New Parity section mirroring the rules package. +- Quick discovery snippet added to Public Exports. + +No code changes — READMEs only. diff --git a/.changeset/phase-r3-docs-site-alignment.md b/.changeset/phase-r3-docs-site-alignment.md new file mode 100644 index 0000000..047e4fd --- /dev/null +++ b/.changeset/phase-r3-docs-site-alignment.md @@ -0,0 +1,75 @@ +--- +"contentrain": patch +--- + +docs(site): phase R3 — align production docs/ site with current codebase + +Every page under `docs/` (the ai.contentrain.io VitePress site) was +audited against the current source by 5 parallel Explore agents (top- +level, packages, reference, guides-infra, guides-content-domain), then +applied sequentially with VitePress build verification. + +### Tool-count corrections + +- `getting-started.md`, `concepts.md`, `packages/mcp.md`, + `packages/cli.md`, `guides/embedding-mcp.md`, + `guides/http-transport.md`, `guides/providers.md`, + `guides/serve-ui.md` — every "16 tools" / "16 Contentrain tools" + reference updated to **17** (includes `contentrain_merge` + the new + `contentrain_doctor`). + +### Branch-naming corrections (post Phase 7) + +- `concepts.md`, `guides/normalize.md` — legacy + `contentrain/{operation}/...` branch prefixes rewritten to `cr/*`. + MCP's `buildBranchName()` emits `cr/` and `checkBranchHealth` filters + on `cr/` — docs must not teach the stale prefix. + +### Major rewrites + +- **`packages/mcp.md`** — full tool table with 17 rows and the new + `contentrain_doctor` in the read section. Capability gates section + mentions doctor alongside scan/apply. Complete subpath-export list + (adds `/core/doctor`, `/core/contracts`, `/core/ops`, + `/core/overlay-reader`, `/tools/annotations`). +- **`packages/cli.md`** — every command expanded with its real flags: + `--json` on status/doctor/validate/generate/diff/describe/scaffold; + `--watch` on validate + generate; `--fix` / `--interactive` on + validate; global `--debug` / `CONTENTRAIN_DEBUG`; new commands + (`merge`, `describe`, `describe-format`, `scaffold`, `setup`, + `skills`). Serve section documents `--demo`, `--mcpHttp`, and the + secure-by-default Bearer-token requirement on non-localhost binds. +- **`packages/types.md`** — new Provider Contract Types section + (`RepoProvider`, `RepoReader`, `RepoWriter`, `ProviderCapabilities`, + `FileChange`, `ApplyPlanInput`, `Commit`, `Branch`, `FileDiff`, + `MergeResult` with `sync?`, `SyncResult`, `CommitAuthor`), plus + `LOCAL_CAPABILITIES` constant. +- **`packages/rules.md`** — MCP_TOOLS length (17) and explicit + include-checks for `contentrain_merge` and `contentrain_doctor`. +- **`reference/providers.md`** — complete capability matrix, merge- + result shape (including `sync?` for LocalProvider), supporting + types, and a minimum-viable custom-provider recipe. +- **`guides/serve-ui.md`** — new sections for every Phase 14b/c/d + capability: `/doctor` and `/format` UI pages, merge preview on + BranchDetail, `meta:changed` / `file-watch:error` / `sync:warning` + / `branch:merge-conflict` / `branch:rejected` WS events, new HTTP + routes (`/api/doctor`, `/api/describe-format`, `/api/preview/merge`, + `/api/capabilities`, `/api/branches/:name/sync-status`), secure-by- + default HTTP MCP auth. + +### Minor + +- `packages/sdk.md` — generation entry point ordering: `contentrain + generate` is now presented as the recommended path; the + programmatic `@contentrain/query/generate` API is documented for + build-tool authors. +- `demo.md` — code snippet gets an explicit `import { singleton } + from '#contentrain'` line for copy-paste clarity. + +### Verified + +- `npx vitepress build` → success in 5.33s, no broken links, no + rendering errors. +- Every claim cross-checked against current source code. + +No code changes — docs only. diff --git a/.changeset/phase-r3b-root-md-alignment.md b/.changeset/phase-r3b-root-md-alignment.md new file mode 100644 index 0000000..dc6297b --- /dev/null +++ b/.changeset/phase-r3b-root-md-alignment.md @@ -0,0 +1,30 @@ +--- +"contentrain": patch +--- + +docs: phase R3b — align root README / CLAUDE / AGENTS with current codebase + +Repo root guidance files updated so they agree with the per-package +READMEs (phase R2) and the docs site (phase R3): + +### README.md +- Architecture diagram: `MCP (16 tools)` → `MCP (17 tools)`. +- Feature bullet: "MCP engine — 16 tools" → "17 tools". +- Packages table: `@contentrain/mcp` row → "17 MCP tools + ...". + +### CLAUDE.md +- Monorepo tree `packages/mcp` comment → `17 MCP tools`. +- npm-packages table → `17 MCP tools`. +- Obsolete "Octokit YOK in MCP" decision rewritten: `@octokit/rest` + and `@gitbeaker/rest` are optional peer dependencies (Phase 5.1 + 8). + +### AGENTS.md +- Essentials bullet: "16 MCP tools with mandatory calling protocols" + → 17. +- Packages table: mcp row → "17 MCP tools — content operations engine". + +### RELEASING.md +- No changes — release flow docs stayed accurate through R1-R3. + +### CONTRIBUTING.md, CLA.md, CODE_OF_CONDUCT.md +- No changes — standards files, no code-specific content. diff --git a/AGENTS.md b/AGENTS.md index d2b3b3e..f2a3dbe 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -48,7 +48,7 @@ Load `packages/rules/essential/contentrain-essentials.md` (~120 lines) for compa - Architecture (MCP = deterministic infra, Agent = intelligence) - Four model kinds (singleton, collection, document, dictionary) - Content format rules (JSON only, canonical serialization) -- 16 MCP tools with mandatory calling protocols +- 17 MCP tools with mandatory calling protocols - Git workflow (dedicated contentrain branch, worktree isolation) - Security boundaries @@ -56,7 +56,7 @@ Load `packages/rules/essential/contentrain-essentials.md` (~120 lines) for compa | Directory | npm | What it does | |-----------|-----|-------------| -| `packages/mcp` | `@contentrain/mcp` | 16 MCP tools — content operations engine | +| `packages/mcp` | `@contentrain/mcp` | 17 MCP tools — content operations engine | | `packages/cli` | `contentrain` | CLI + Serve UI + MCP stdio entrypoint | | `packages/sdk/js` | `@contentrain/query` | Generated TypeScript query SDK | | `packages/types` | `@contentrain/types` | Shared type definitions | diff --git a/CLAUDE.md b/CLAUDE.md index 21a00a5..fb37b56 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -11,7 +11,7 @@ MIT-licensed monorepo for Contentrain's open-source packages: MCP tools, CLI, Ty ``` contentrain-ai/ ├── packages/ -│ ├── mcp/ — 16 MCP tools, stdio + HTTP transports, Local / GitHub / GitLab providers (simple-git + zod + MCP SDK) +│ ├── mcp/ — 17 MCP tools, stdio + HTTP transports, Local / GitHub / GitLab providers (simple-git + zod + MCP SDK) │ ├── cli/ — citty + tsdown (init/serve/validate/normalize/connect) │ ├── types/ — Shared TypeScript types (@contentrain/types) │ ├── rules/ — AI agent quality rules & conventions @@ -72,7 +72,7 @@ When working with Contentrain content operations (models, content, normalize, va - **JSON only** — no YAML - **Git mandatory** — `contentrain init` auto `git init` -- **Octokit YOK in MCP** — MCP = local-first, platform-agnostic. GitHub API = Studio/CLI only +- **Optional remote providers** — MCP is local-first by default (stdio + LocalProvider). `@octokit/rest` (GitHubProvider) and `@gitbeaker/rest` (GitLabProvider) ship as **optional peer dependencies** — installed only when a remote provider is used - **Every write uses worktree + dedicated contentrain branch + update-ref** — model_save and content_save alike - **Collection storage = object-map** — `{ entryId: { fields } }`, sorted by ID - **Canonical serialization** — deterministic JSON output, sorted keys, 2-space indent, trailing newline @@ -90,7 +90,7 @@ When working with Contentrain content operations (models, content, normalize, va | Package | Name | Description | |---|---|---| -| packages/mcp | @contentrain/mcp | 16 MCP tools, stdio + HTTP transports, Local / GitHub / GitLab providers | +| packages/mcp | @contentrain/mcp | 17 MCP tools, stdio + HTTP transports, Local / GitHub / GitLab providers | | packages/cli | contentrain | CLI (npx contentrain) | | packages/types | @contentrain/types | Shared TypeScript types | | packages/rules | @contentrain/rules | AI agent quality rules & conventions | diff --git a/README.md b/README.md index 1f44bfb..b0594af 100644 --- a/README.md +++ b/README.md @@ -94,7 +94,7 @@ This is the strongest entry point into the product: ``` ┌─────────────┐ ┌──────────────────┐ ┌──────────────┐ -│ AI Agent │────▶│ MCP (16 tools) │────▶│ .contentrain/│ +│ AI Agent │────▶│ MCP (17 tools) │────▶│ .contentrain/│ │ (decides) │ │ (enforces) │ │ (stores) │ └─────────────┘ └──────────────────┘ └──────┬───────┘ │ @@ -145,7 +145,7 @@ Works with Nuxt, Next.js, Astro, SvelteKit, Vue, React, Node, Go, Python, Swift, - **Git-native** — every write goes through worktree isolation + review branches - **Normalize flow** — scan codebase for hardcoded strings → extract → create i18n-ready content → patch source files -- **MCP engine** — 16 tools over stdio or HTTP transport, works with Claude Code, Cursor, Windsurf, or any MCP client +- **MCP engine** — 17 tools over stdio or HTTP transport, works with Claude Code, Cursor, Windsurf, or any MCP client - **Provider-agnostic engine** — the same tool surface runs over a local worktree, GitHub, or GitLab (self-hosted included) with zero tool-code changes. HTTP transport available for remote drivers such as Studio. - **Canonical serialization** — sorted keys, deterministic output, clean git diffs, conflict-free parallel edits - **Agent rules & skills** — behavioral policies and step-by-step workflows ship as npm packages @@ -176,7 +176,7 @@ See [`AGENTS.md`](AGENTS.md) for the full skill catalog and agent guidance. | Package | npm | Role | |---|---|---| -| [`@contentrain/mcp`](packages/mcp) | [![npm](https://img.shields.io/npm/v/%40contentrain%2Fmcp)](https://www.npmjs.com/package/@contentrain/mcp) | 16 MCP tools + stdio / HTTP transport + Local / GitHub / GitLab providers | +| [`@contentrain/mcp`](packages/mcp) | [![npm](https://img.shields.io/npm/v/%40contentrain%2Fmcp)](https://www.npmjs.com/package/@contentrain/mcp) | 17 MCP tools + stdio / HTTP transport + Local / GitHub / GitLab providers | | [`contentrain`](packages/cli) | [![npm](https://img.shields.io/npm/v/contentrain)](https://www.npmjs.com/package/contentrain) | CLI + Serve UI + MCP stdio entrypoint | | [`@contentrain/query`](packages/sdk/js) | [![npm](https://img.shields.io/npm/v/%40contentrain%2Fquery)](https://www.npmjs.com/package/@contentrain/query) | Generated TypeScript query SDK | | [`@contentrain/types`](packages/types) | [![npm](https://img.shields.io/npm/v/%40contentrain%2Ftypes)](https://www.npmjs.com/package/@contentrain/types) | Shared type definitions + constants | diff --git a/docs/concepts.md b/docs/concepts.md index 44336bb..6e14488 100644 --- a/docs/concepts.md +++ b/docs/concepts.md @@ -43,9 +43,9 @@ Contentrain AI inverts the traditional CMS workflow: ### 1. MCP (Infrastructure) -16 tools that AI agents call to manage content: +17 tools that AI agents call to manage content: -- **Read:** `contentrain_status`, `contentrain_describe`, `contentrain_describe_format`, `contentrain_content_list` +- **Read:** `contentrain_status`, `contentrain_describe`, `contentrain_describe_format`, `contentrain_doctor`, `contentrain_content_list` - **Project setup:** `contentrain_init`, `contentrain_scaffold` - **Content and schema writes:** `contentrain_model_save`, `contentrain_model_delete`, `contentrain_content_save`, `contentrain_content_delete` - **Normalize:** `contentrain_scan`, `contentrain_apply` @@ -178,10 +178,10 @@ singleton('hero').locale('tr').get() // typed, with query API Every write operation creates a Git commit on a namespaced branch: ``` -contentrain/model/hero-section ← model changes -contentrain/content/blog-post ← content changes -contentrain/normalize/extract/... ← normalize extraction -contentrain/normalize/reuse/... ← source patching +cr/model/hero-section ← model changes +cr/content/blog-post ← content changes +cr/normalize/extract/... ← normalize extraction +cr/normalize/reuse/... ← source patching ``` Branches are auto-merged or held for review depending on your workflow config. diff --git a/docs/demo.md b/docs/demo.md index b10197d..6452186 100644 --- a/docs/demo.md +++ b/docs/demo.md @@ -90,6 +90,8 @@ The agent proposes a dry-run patch, then `contentrain_apply(mode: "reuse")` upda ## After ```tsx +import { singleton } from '#contentrain' + export default function Hero() { const hero = singleton('hero-section').locale('en').get() diff --git a/docs/getting-started.md b/docs/getting-started.md index c6bd28d..afebf39 100644 --- a/docs/getting-started.md +++ b/docs/getting-started.md @@ -215,7 +215,7 @@ All packages are published on npm: | Package | Description | Install | |---|---|---| | [`contentrain`](https://www.npmjs.com/package/contentrain) | CLI (init, serve, generate, validate) | `npx contentrain init` | -| [`@contentrain/mcp`](https://www.npmjs.com/package/@contentrain/mcp) | 16 MCP tools for AI agents | `pnpm add @contentrain/mcp` | +| [`@contentrain/mcp`](https://www.npmjs.com/package/@contentrain/mcp) | 17 MCP tools for AI agents | `pnpm add @contentrain/mcp` | | [`@contentrain/query`](https://www.npmjs.com/package/@contentrain/query) | TypeScript query SDK (optional) | `pnpm add @contentrain/query` | | [`@contentrain/types`](https://www.npmjs.com/package/@contentrain/types) | Shared TypeScript types | `pnpm add @contentrain/types` | | [`@contentrain/rules`](https://www.npmjs.com/package/@contentrain/rules) | AI agent quality rules | `pnpm add @contentrain/rules` | @@ -253,7 +253,7 @@ Want to skip setup? Start from a production-ready template with content models, - [Core Concepts](/concepts) — Models, content kinds, domains, and the governance architecture - [Ecosystem Map](/ecosystem) — How AI packages and Studio fit together -- [MCP Tools](/packages/mcp) — All 16 tools available to your agent +- [MCP Tools](/packages/mcp) — All 17 tools available to your agent - [Normalize Flow](/guides/normalize) — Extract hardcoded strings from existing code - [i18n Workflow](/guides/i18n) — Add languages to your content - [Framework Integration](/guides/frameworks) — Platform-specific setup patterns diff --git a/docs/guides/embedding-mcp.md b/docs/guides/embedding-mcp.md index 09b3b11..d785e28 100644 --- a/docs/guides/embedding-mcp.md +++ b/docs/guides/embedding-mcp.md @@ -15,7 +15,7 @@ Studio (`contentrain.io`) is the canonical consumer; the patterns below describe `@contentrain/mcp` ships three pieces you plug together: 1. **A `RepoProvider`** — Local / GitHub / GitLab (or your own). Wraps whatever git backend you're targeting. -2. **An `McpServer`** — the MCP JSON-RPC surface with all 16 Contentrain tools registered. +2. **An `McpServer`** — the MCP JSON-RPC surface with all 17 Contentrain tools registered. 3. **A transport** — stdio (for IDE agents) or HTTP (for hosted / remote drivers). The three are orthogonal. Mix them freely. @@ -246,7 +246,7 @@ A GitHub Actions job: 4. Drive it with an MCP client 5. Let `contentrain_submit` push the `cr/*` branch -All 16 tools are available because the runner has `LocalProvider`. +All 17 tools are available because the runner has `LocalProvider`. ### Scripted automation diff --git a/docs/guides/http-transport.md b/docs/guides/http-transport.md index 3a77b49..8fa225b 100644 --- a/docs/guides/http-transport.md +++ b/docs/guides/http-transport.md @@ -14,7 +14,7 @@ Typical drivers: - **CI runners** — deterministic content operations as part of a pipeline (scaffold, validate, submit). - **Remote agents** — any MCP client that wants to operate a Contentrain project without a local checkout. -All three tunnel the same 16 tools through the same `RepoProvider` contract. Which backend answers depends on how the server is wired — see [Providers & Transports](/guides/providers) for the capability matrix. +All three tunnel the same 17 tools through the same `RepoProvider` contract. Which backend answers depends on how the server is wired — see [Providers & Transports](/guides/providers) for the capability matrix. ## Starting the HTTP server diff --git a/docs/guides/normalize.md b/docs/guides/normalize.md index 62e954a..72b9b3d 100644 --- a/docs/guides/normalize.md +++ b/docs/guides/normalize.md @@ -37,8 +37,8 @@ These strings are scattered across dozens of files. Translating means grep-and-r | Phase | What happens | Source files modified? | Branch pattern | |---|---|---|---| -| 1. Extract | Strings pulled into `.contentrain/content/` | No | `contentrain/normalize/extract/{ts}` | -| 2. Reuse | Source files patched to reference content | Yes | `contentrain/normalize/reuse/{model}/{ts}` | +| 1. Extract | Strings pulled into `.contentrain/content/` | No | `cr/normalize/extract/{ts}` | +| 2. Reuse | Source files patched to reference content | Yes | `cr/normalize/reuse/{model}/{ts}` | | 3. Translate | Content copied to new locales and translated | No | Standard content branch | ::: tip @@ -246,7 +246,7 @@ After your confirmation: > "Apply the reuse patches" -The agent calls `contentrain_apply(mode: "reuse", ..., dry_run: false)`. This patches source files and creates a `contentrain/normalize/reuse/hero-section/{timestamp}` branch. +The agent calls `contentrain_apply(mode: "reuse", ..., dry_run: false)`. This patches source files and creates a `cr/normalize/reuse/hero-section/{timestamp}` branch. ### Step 5. Validate, submit, and repeat diff --git a/docs/guides/providers.md b/docs/guides/providers.md index dad345e..4fb142a 100644 --- a/docs/guides/providers.md +++ b/docs/guides/providers.md @@ -6,7 +6,7 @@ slug: providers # Providers & Transports -Contentrain MCP runs the same 16 tools over three backends: +Contentrain MCP runs the same 17 tools over three backends: - **LocalProvider** — simple-git + a temporary worktree on your disk. Default for `npx contentrain serve --stdio` and the HTTP transport when driven by the CLI. - **GitHubProvider** — Octokit over the GitHub Git Data + Repos APIs. No clone, no worktree. diff --git a/docs/guides/serve-ui.md b/docs/guides/serve-ui.md index a139a22..6467955 100644 --- a/docs/guides/serve-ui.md +++ b/docs/guides/serve-ui.md @@ -38,7 +38,10 @@ The server starts on `http://localhost:3333` by default. | `--port` | `3333` | Port number | | `--host` | `localhost` | Host address | | `--open=false` | `true` | Prevent auto-opening browser | +| `--demo` | disabled | Temporary demo project (no setup required) | | `--stdio` | disabled | MCP stdio transport for IDE integration (no web UI) | +| `--mcpHttp` | disabled | MCP HTTP transport at `POST /mcp` (secure-by-default Bearer auth) | +| `--authToken` | — | Bearer token required on non-localhost HTTP binds | ### Check if already running @@ -75,10 +78,6 @@ Browse all model definitions: - Content path and locale strategy - Entry count per locale -**Agent prompt hint:** - -> "Create a new collection model for team members with name, role, and avatar fields" - ### Content (`/content`) Browse and inspect content entries: @@ -88,10 +87,6 @@ Browse and inspect content entries: - See metadata (status, source, timestamps) - Locale switcher to compare translations side by side -**Agent prompt hint:** - -> "Add a new blog post about our latest feature release" - ::: tip The content page is read-only. To edit content, copy the agent prompt from the UI and paste it into your AI agent. ::: @@ -105,115 +100,136 @@ Inspect validation results: - Duplicate entry detection - Vocabulary alignment checks -After reviewing issues, ask the agent to fix them: - -> "Fix all validation errors in the blog-post model" - -The agent calls `contentrain_validate` to get the error list, then `contentrain_content_save` to fix each issue. - -**Agent prompt hint:** - -> "Validate all content and fix any errors" - ### Branches (`/branches`) Manage content branches: -- List all `contentrain/*` branches +- List all `cr/*` branches - See diff summary for each branch - **Merge** approved branches - **Delete** rejected branches - View commit history per branch +- Click a branch to see a detailed preview with merge conflict detection -This is where you approve or reject agent-created content: - -1. Agent creates content on a branch via MCP tools -2. You review the changes in the Branches page -3. Click **Merge** to accept or **Delete** to reject -4. The agent detects your decision and proceeds accordingly - -**Agent prompt hint:** +### Branch Detail (`/branches/:name`) -> "Submit the current changes for review" +When you click a branch in the list, you see a detailed **merge preview** fetched from `/api/preview/merge`: -### Normalize (`/normalize`) +- Fast-forward status (can the branch merge cleanly?) +- Already-merged check (is this branch already in the content-tracking branch?) +- Conflict detection (best-effort list of conflicting paths via `git merge-tree`) +- Diff summary and file-by-file changes +- Sync-warning panel surfacing any files the last selective sync skipped -The normalize page is active when a normalize plan exists (`.contentrain/normalize-plan.json`): +This preview is generated without running the actual merge — a safe way to answer "what happens if I approve this?" before committing to the action. -- **Extraction review panel:** Candidates grouped by model with field mappings -- **Source trace panel:** Click any extraction to see its original file and line number -- **Patch preview panel:** See the exact source file changes that will happen in Phase 2 -- **Approve & Apply** button: Executes the extraction -- **Reject** button: Deletes the plan +### Doctor (`/doctor`) -This page appears only during the [normalize flow](./normalize). When no plan exists, it shows a prompt to start normalization: +Project health dashboard wrapping the `contentrain_doctor` MCP tool: -> "Scan my project and extract hardcoded strings into Contentrain" +- Environment checks (Node ≥22, git available) +- `.contentrain/` structure validation +- Model definition parsing +- Orphan content detection +- Branch pressure (warning at 50 `cr/*`, blocked at 80) +- SDK client freshness (comparing mtimes) +- Optional **usage analysis** toggle: unused keys, duplicate dictionary values, missing locale keys -## WebSocket Real-time Updates +Each check renders with severity (error / warning / info). The "Run" button re-fetches `/api/doctor?usage=...`. -Serve UI uses WebSocket connections for real-time updates: +**Agent prompt hint:** -- **File watcher:** When `.contentrain/` files change (from agent operations), the UI updates automatically -- **Context updates:** After every MCP write operation, `context.json` is updated and the UI reflects the latest state -- **Branch events:** New branches, merges, and deletions appear instantly -- **Normalize plan:** Plan file creation and status changes trigger UI refresh +> "Run a full project health check and fix any errors" -You do not need to manually refresh the page. Changes made by the agent appear in real time. +### Format Reference (`/format`) -## Approval Flow +A read-only reference of how Contentrain stores content — renders the output of the `contentrain_describe_format` tool via `/api/describe-format`: -The typical workflow between agent and developer: +- Models schema (JSON structure of `.contentrain/models/`) +- Content layout (directory and file structure) +- Metadata organization (SEO, entry-level metadata) +- Vocabulary format +- Locale strategies -### Step 1. Agent creates content +Useful as a living spec for developers and integrators who need the physical file format without reading docs. -You ask the agent to create or update content: +### Normalize (`/normalize`) -> "Create 5 testimonials for the landing page" +The normalize page is active when a normalize plan exists (`.contentrain/normalize-plan.json`): -The agent calls `contentrain_content_save`, which creates entries on a branch and commits to Git. +- **Extraction review panel:** Candidates grouped by model with field mappings +- **Source trace panel:** Click any extraction to see its original file and line number +- **Patch preview panel:** See the exact source file changes that will happen in Phase 2 +- **Approve & Apply** button: Executes the extraction +- **Reject** button: Deletes the plan -### Step 2. Developer reviews in UI +This page appears only during the [normalize flow](/guides/normalize). When no plan exists, it shows a prompt to start normalization. -The agent tells you to review: +## WebSocket Real-time Updates -> "I've created 5 testimonials on branch `contentrain/content/testimonials/...`. Review them at `http://localhost:3333/branches`" +Serve UI uses WebSocket connections for real-time updates. You do not need to manually refresh the page. -In the UI, you see the branch with a diff of all new entries. You can inspect each testimonial's content, check for quality, and verify the data. +### WebSocket Events -### Step 3. Approve or reject +The serve server broadcasts the following events over the WebSocket connection: -- **Approve:** Click **Merge** — the branch merges into the `contentrain` branch, baseBranch is advanced, content is live -- **Reject:** Click **Delete** — the branch is removed, content is discarded +| Event | Emitted when | Payload | +|---|---|---| +| `connected` | Client connects | (none) | +| `config:changed` | `.contentrain/config.json` changes | (none) | +| `context:changed` | `.contentrain/context.json` changes | `{ context }` | +| `model:changed` | A model definition is created/updated | `{ modelId }` | +| `content:changed` | Content entries are created/updated | `{ modelId, locale }` | +| `meta:changed` | SEO or model metadata is written | `{ modelId, entryId?, locale }` | +| `normalize:plan-updated` | Normalize plan is created/updated/deleted | (none) | +| `validation:updated` | Validation results change | (none) | +| `branch:created` | A new `cr/*` branch is created | `{ branch }` | +| `branch:merged` | A branch is merged into `contentrain` | `{ branch }` | +| `branch:rejected` | A branch is deleted | `{ branch }` | +| `branch:merge-conflict` | Branch merge fails | `{ branch, message }` | +| `sync:warning` | Merge succeeds but skips dirty working-tree files | `{ branch, skippedCount }` | +| `file-watch:error` | chokidar file watcher encounters an error | `{ message, timestamp }` | + +## HTTP API Surface + +The serve backend exposes REST endpoints at `http://localhost:3333/api/*`. Key routes: + +| Route | Method | Purpose | +|---|---|---| +| `/api/status` | GET | Wraps `contentrain_status` | +| `/api/capabilities` | GET | Provider + transport + branch health in one call | +| `/api/doctor?usage=...` | GET | Wraps `contentrain_doctor` (optional usage analysis) | +| `/api/describe-format` | GET | Wraps `contentrain_describe_format` | +| `/api/describe/:modelId` | GET | Wraps `contentrain_describe` | +| `/api/content/:modelId` | GET | List content entries | +| `/api/content/:modelId/:entryId` | GET | Single entry read | +| `/api/content/:modelId/:entryId/fix` | POST | Quick fix (content save) | +| `/api/validate?fix=true` | GET | Wraps `contentrain_validate` | +| `/api/branches` | GET | List `cr/*` branches | +| `/api/branches/diff?name=cr/...` | GET | Branch diff against `contentrain` | +| `/api/branches/approve` | POST | Approve & merge a branch | +| `/api/branches/reject` | POST | Delete a branch | +| `/api/branches/:name/sync-status` | GET | Cached sync warnings from last merge | +| `/api/preview/merge?branch=cr/...` | GET | Side-effect-free merge preview (FF / conflicts / already-merged) | +| `/api/history` | GET | Recent contentrain-related commits | +| `/api/context` | GET | `.contentrain/context.json` | +| `/api/normalize/*` | various | Scan / plan / approve / reject / apply / approve-branch | + +Every write route validates its body through Zod schemas (`parseOrThrow`) before reaching the MCP tool layer. -### Step 4. Agent detects the decision +## Approval Flow -The agent reads the filesystem state: +The typical workflow between agent and developer: -- Branch merged → content is on main, agent confirms success -- Branch deleted → agent asks what to change and iterates +1. **Agent creates content** via `contentrain_content_save` (or similar write tool), landing on a `cr/*` branch. +2. **Developer reviews in UI** at `/branches/:name` — sees the merge preview, per-file diff, sync warnings if any. +3. **Approve or Reject** — click **Merge** or **Delete**. +4. **Agent detects the decision** by re-reading the filesystem/context state. ::: warning For normalize operations, the workflow always uses review mode. Even if the project is configured for auto-merge, normalize branches require explicit approval. ::: -## Agent Prompt Hints in UI - -Every page in Serve UI includes context-aware agent prompts. These are copyable text blocks that you paste directly into your AI agent (Claude Code, Cursor, Copilot, etc.). - -Examples by page: - -| Page | Prompt | -|---|---| -| Dashboard | "Show me project status and pending changes" | -| Models | "Create a new singleton model for the pricing section" | -| Content | "Update the hero section title to ..." | -| Validate | "Fix all validation errors" | -| Branches | "Submit current changes for review" | -| Normalize | "Scan my project and extract hardcoded strings" | - -This design keeps the UI as a monitoring surface while the agent handles all actions. - ## Workflow Configuration The approval flow behavior is controlled by the workflow setting in `.contentrain/config.json`: @@ -230,42 +246,45 @@ The approval flow behavior is controlled by the workflow setting in `.contentrai | `auto-merge` | Content changes merge into `contentrain` branch, baseBranch is advanced via update-ref | ::: info -Normalize operations always use review mode regardless of this setting. Only standard content operations (create, update, delete) respect the auto-merge setting. +Normalize operations always use review mode regardless of this setting. ::: ## IDE Integration (stdio mode) -For IDE-embedded use (VS Code, Cursor), serve can run in stdio mode: +For IDE-embedded use (VS Code, Cursor, Claude Code), serve can run in stdio mode: ```bash npx contentrain serve --stdio ``` -This starts the MCP server with stdio transport instead of the web UI. The IDE connects directly to the MCP tools without a browser. +This starts the MCP server with stdio transport instead of the web UI. + +## HTTP MCP Transport + +For Studio, CI, or remote agents, serve can expose MCP over Streamable HTTP: + +```bash +npx contentrain serve --mcpHttp --authToken $(openssl rand -hex 32) +``` -Both modes (web UI and stdio) use the same MCP tools underneath. The difference is the transport layer: +**Secure-by-default:** binding to a non-localhost address (`0.0.0.0` / specific IPs) without `--authToken` (or `CONTENTRAIN_AUTH_TOKEN` env var) is a hard error — the HTTP MCP endpoint exposes full project write access. -- **Web UI:** HTTP + WebSocket, human reviews in browser -- **stdio:** Direct MCP protocol, IDE handles the interaction +See the [HTTP Transport guide](/guides/http-transport) for deployment patterns. ## Troubleshooting ### Port already in use ```bash -# Find and kill the existing process lsof -ti:3333 | xargs kill - -# Or use a different port +# or npx contentrain serve --port 4444 ``` ### UI not updating -If real-time updates stop: - 1. Check that the serve process is still running -2. Refresh the browser page to re-establish the WebSocket connection +2. Look for a `file-watch:error` banner at the top of the UI — this indicates the chokidar watcher stopped (e.g. OS inotify limit). Restart `contentrain serve` to reattach. 3. Verify that `.contentrain/` files are being written (check `context.json` timestamp) ### Content not appearing @@ -274,7 +293,17 @@ If content created by the agent does not appear: 1. Check if the content is on a feature branch (not yet merged into the `contentrain` branch) 2. Navigate to the Branches page to see pending branches -3. Merge the branch to make content visible on the Content page +3. Click the branch for a detailed merge preview +4. Merge the branch to make content visible on the Content page + +### Merge conflicts when approving + +When clicking **Merge** on a branch, the UI performs a real merge using the MCP `mergeBranch` helper. Conflicts can occur when: + +1. The branch and `contentrain` branch have diverged +2. You've made manual edits to `.contentrain/` files outside the agent workflow + +The UI surfaces the conflict message. Resolve it manually or ask the agent to create a fresh branch from the current `contentrain` state. ## Beyond Local: Contentrain Studio diff --git a/docs/packages/cli.md b/docs/packages/cli.md index 36904b3..247c7fd 100644 --- a/docs/packages/cli.md +++ b/docs/packages/cli.md @@ -44,6 +44,16 @@ Requirements: - Node.js 22+ - Git available in `PATH` +## Global Options + +These flags are available on every command: + +| Flag | Environment Variable | Description | +|------|----------------------|-------------| +| `--debug` | `CONTENTRAIN_DEBUG=1` | Enable debug logging to stderr (useful for troubleshooting) | + +Example: `contentrain --debug status` or `CONTENTRAIN_DEBUG=1 contentrain status`. + ## Commands | Command | Purpose | @@ -53,10 +63,14 @@ Requirements: | `contentrain doctor` | Check setup health, SDK freshness, orphan content, and branch limits | | `contentrain validate` | Validate content against schemas, optionally create review-branch fixes | | `contentrain generate` | Generate `.contentrain/client/` and `#contentrain` package imports | -| `contentrain diff` | Review and merge or reject pending `contentrain/*` branches | +| `contentrain describe` | Display full model schema and sample data | +| `contentrain describe-format` | Show file format specification and storage conventions | +| `contentrain scaffold` | Apply starter templates (blog, landing, docs, SaaS, ...) | +| `contentrain diff` | Review and merge or reject pending `cr/*` branches interactively | +| `contentrain merge ` | Merge one pending `cr/*` branch non-interactively | | `contentrain setup` | Configure MCP server and AI rules for your IDE | | `contentrain skills` | Install, update, or list AI skills and rules for your IDE | -| `contentrain serve` | Start the local review UI or the MCP stdio server | +| `contentrain serve` | Start the local review UI, the MCP stdio server, or the MCP HTTP server | | `contentrain studio connect` | Connect a repository to a Studio project | | `contentrain studio login` | Authenticate with Contentrain Studio | | `contentrain studio logout` | Log out from Studio | @@ -77,14 +91,9 @@ Requirements: Bootstraps a Contentrain project in your repository. ```bash -# Interactive setup -contentrain init - -# Skip prompts, use defaults -contentrain init --yes - -# Specify project root -contentrain init --root /path/to/project +contentrain init # Interactive +contentrain init --yes # Skip prompts +contentrain init --root /path # Different project root ``` | Flag | Description | @@ -92,594 +101,271 @@ contentrain init --root /path/to/project | `--yes` | Skip prompts, use defaults | | `--root ` | Project root path | -This creates: -- `.contentrain/config.json` — project configuration -- `.contentrain/models/` — model schema directory -- `.contentrain/content/` — content storage directory -- IDE rules and Agent Skills (Claude Code, Cursor, Windsurf, GitHub Copilot) - -If the directory is not a git repo, `contentrain init` runs `git init` automatically. - -::: info IDE Rules & Skills -`contentrain init` installs a compact essential guardrails file (~86 lines, always-loaded) plus Agent Skills directories (on-demand) for detected IDEs. Old granular rule files from previous versions are automatically cleaned up. GitHub Copilot support is included via `.github/copilot-instructions.md`. -::: +Creates `.contentrain/config.json`, `.contentrain/models/`, `.contentrain/content/`, plus IDE rules and Agent Skills. Runs `git init` if not already a repo. --- ### `contentrain status` -Shows a comprehensive project overview. - ```bash -# Human-readable output contentrain status - -# JSON output for CI pipelines -contentrain status --json - -# Specify project root -contentrain status --root /path/to/project +contentrain status --json # CI-friendly JSON +contentrain status --root /path ``` -| Flag | Description | -|------|-------------| -| `--json` | Output results as JSON (for CI/CD) | -| `--root ` | Project root path | - -Outputs: -- Project configuration (stack, workflow mode, locales) -- Registered models with entry counts -- Active `contentrain/*` branches and their health -- Validation summary (errors, warnings) -- Last operation context +Outputs config, models, active `cr/*` branches and their health, validation summary, and last operation context. --- ### `contentrain doctor` -Runs a health check on your project setup. +Runs a health check on your project. ```bash contentrain doctor - -# Specify project root -contentrain doctor --root /path/to/project +contentrain doctor --usage # Analyze content key usage in source +contentrain doctor --json # CI-friendly JSON; exits non-zero on failures ``` | Flag | Description | |------|-------------| +| `--usage` | Analyze unused keys, duplicate values, locale coverage gaps | +| `--json` | Machine-readable output; non-zero exit on check failures | | `--root ` | Project root path | -Checks for: -- Missing or misconfigured `.contentrain/config.json` -- SDK client freshness (is the generated client stale?) -- Orphan content (entries referencing deleted models) -- Branch limit pressure (too many pending review branches) -- Missing dependencies +Checks: `.contentrain/config.json` shape, SDK client freshness (mtime comparison), orphan content, branch limits (warning at 50, blocked at 80), Node/git versions. --- ### `contentrain validate` -Validates all content against model schemas. - ```bash -# Check for issues contentrain validate - -# Auto-fix structural issues and create a review branch -contentrain validate --fix - -# Interactive mode — choose which issues to fix -contentrain validate --interactive - -# Validate a single model +contentrain validate --fix # Auto-fix and create review branch +contentrain validate --interactive # Choose fixes interactively +contentrain validate --watch # Re-run on .contentrain/ changes (read-only) contentrain validate --model blog-posts - -# JSON output for CI pipelines -contentrain validate --json +contentrain validate --json # CI-friendly JSON ``` | Flag | Description | |------|-------------| -| `--fix` | Auto-fix structural issues and create a review branch | +| `--fix` | Auto-fix and create a `cr/fix/*` review branch | | `--interactive` | Choose which issues to fix interactively | -| `--model ` | Validate a single model instead of all | -| `--json` | Output results as JSON (for CI/CD) | -| `--root ` | Project root path | +| `--watch` | Re-run when `.contentrain/` changes (read-only polling mode) | +| `--model ` | Validate one model instead of all | +| `--json` | CI-friendly JSON | -Validation catches: -- Missing required fields -- Type mismatches (string where integer expected) -- Invalid relation references -- Locale coverage gaps -- Canonical serialization violations - -::: warning Auto-Fix Creates a Branch -When using `--fix`, the validator creates a `contentrain/*` review branch with the fixes. You still need to review and merge the changes. +::: tip Watch mode for development +Run `contentrain validate --watch` in one terminal alongside your editing workflow. It re-runs on `.contentrain/` changes without creating branches (read-only). Rapid feedback while editing content. ::: --- ### `contentrain generate` -Generates the typed SDK client from your model definitions. +Generates the typed SDK client from model definitions. ```bash -# Generate once contentrain generate +contentrain generate --watch # Regen on model/content changes +contentrain generate --json # CI-friendly JSON +``` -# Watch mode (re-generates on model/content changes) -contentrain generate --watch +Writes `.contentrain/client/` (ESM, CJS, types + per-model data modules) and adds `#contentrain` subpath to `package.json`. -# Specify project root -contentrain generate --root /path/to/project -``` +--- -This reads `.contentrain/models/` and `.contentrain/content/` and produces: +### `contentrain describe ` -``` -.contentrain/client/ - index.mjs — ESM entry - index.cjs — CJS entry - index.d.ts — Generated TypeScript types - data/ - {model}.{locale}.mjs — Static data modules +```bash +contentrain describe blog-post +contentrain describe blog-post --sample --locale en +contentrain describe blog-post --json ``` -It also updates your `package.json` with `#contentrain` subpath imports: - -```json -{ - "imports": { - "#contentrain": { - "types": "./.contentrain/client/index.d.ts", - "import": "./.contentrain/client/index.mjs", - "require": "./.contentrain/client/index.cjs", - "default": "./.contentrain/client/index.mjs" - } - } -} -``` +Shows full schema, field types, stats, sample data, and import snippet. -After generation, import the client in your app: +--- -```ts -import { query, singleton, dictionary, document } from '#contentrain' -``` +### `contentrain describe-format` -::: tip Watch Mode for Development -Run `contentrain generate --watch` alongside your framework's dev server. Add it to your `package.json` scripts: -```json -{ - "scripts": { - "contentrain:watch": "contentrain generate --watch" - } -} +```bash +contentrain describe-format +contentrain describe-format --json ``` -::: ---- +Prints the Contentrain content-format specification (directory structure, JSON formats, markdown conventions, locale strategies). -### `contentrain diff` +--- -Review pending `contentrain/*` branches. +### `contentrain scaffold` ```bash -contentrain diff - -# Specify project root -contentrain diff --root /path/to/project +contentrain scaffold # Interactive picker +contentrain scaffold --template blog +contentrain scaffold --template saas --locales en,tr,de --no-sample +contentrain scaffold --template blog --json ``` -| Flag | Description | -|------|-------------| -| `--root ` | Project root path | - -Shows: -- List of pending review branches -- Changes in each branch (models added/modified, content entries changed) -- Options to merge or reject each branch - -Use `contentrain status` first to see how many branches are pending. +Templates: `blog`, `landing`, `docs`, `ecommerce`, `saas`, `i18n`, `mobile`. --- -### `contentrain setup` - -Configures the MCP server and installs AI rules/skills for your IDE in one command. +### `contentrain diff` ```bash -# Configure for a specific IDE -contentrain setup claude-code -contentrain setup cursor -contentrain setup vscode -contentrain setup windsurf -contentrain setup copilot - -# Configure all detected IDEs at once -contentrain setup --all - -# Specify project root -contentrain setup --root /path/to/project +contentrain diff +contentrain diff --json # Summary of pending cr/* branches for CI ``` -| Flag | Description | -|------|-------------| -| `--all` | Configure all detected IDEs | -| `--root ` | Project root path | - -What it does: -1. Writes the correct MCP config file for the target IDE -2. Installs AI rules and skills if not already present -3. Merges into existing config without overwriting other MCP servers - -| Agent | Config File Created | -|-------|-------------------| -| `claude-code` | `.mcp.json` | -| `cursor` | `.cursor/mcp.json` | -| `vscode` | `.vscode/mcp.json` | -| `windsurf` | `.windsurf/mcp.json` | -| `copilot` | `.vscode/mcp.json` | - -::: tip Already done by `contentrain init` -`contentrain init` auto-detects your IDE and writes the MCP config during project setup. Use `contentrain setup` when you switch IDEs or want to add another IDE to an existing project. -::: +Interactive (default) review of pending review branches. `--json` emits `{ branches: [{name, base, filesChanged, insertions, deletions, stat}] }` without entering the interactive loop. --- -### `contentrain skills` - -Install, update, or list Contentrain AI skills and rules for your IDE. +### `contentrain merge ` ```bash -# Install skills and rules for detected IDEs -contentrain skills +contentrain merge cr/content/faq/1234-abcd +contentrain merge cr/content/faq/1234-abcd --yes # Skip confirm (CI) +``` + +Non-interactive single-branch sibling of `contentrain diff`. Delegates to MCP's `mergeBranch` so dirty-file protections + selective sync warnings behave identically. -# Force update all skills (overwrite existing) -contentrain skills --update +--- -# List installed skills and their status -contentrain skills --list +### `contentrain setup` -# Specify project root -contentrain skills --root /path/to/project +```bash +contentrain setup claude-code # or: cursor, vscode, windsurf, copilot +contentrain setup --all # Configure every detected IDE ``` -| Flag | Description | -|------|-------------| -| `--list` | List installed skills with ✓/✗ status per IDE | -| `--update` | Force update all skills and rules (overwrites existing files) | -| `--root ` | Project root path | - -Detects and installs for all major AI-powered IDEs: +Writes the correct `.mcp.json` (or equivalent) for the target IDE and installs AI rules/skills if absent. Merges into existing config without overwriting other MCP servers. -| IDE | Rules Directory | Skills Directory | -|-----|----------------|-----------------| -| Claude Code | `.claude/rules/` | `.claude/skills/` | -| Cursor | `.cursor/rules/` | `.cursor/skills/` | -| Windsurf | `.windsurf/rules/` | `.windsurf/skills/` | -| GitHub Copilot | `.github/` | `.agents/skills/` | +--- -Installs: -- **Essential rules** (~86 lines, always-loaded guardrails) -- **15 Agent Skills** (on-demand workflow procedures with reference docs) +### `contentrain skills` -::: tip Skills vs Rules -**Rules** are always-loaded behavioral guardrails (compact, ~86 lines). **Skills** are on-demand procedural workflows the agent loads when needed (normalize, content CRUD, translation, etc.). Both are plain markdown files that IDEs auto-discover. -::: +```bash +contentrain skills # Install / refresh +contentrain skills --update # Force update +contentrain skills --list # Show installed status per IDE +``` -::: info Already installed by `contentrain init` -`contentrain init` automatically installs skills and rules during project setup. Use `contentrain skills --update` to refresh them after upgrading `@contentrain/skills` or `@contentrain/rules` packages. -::: +Installs 15 Agent Skills + essential rules across detected IDEs (Claude Code, Cursor, Windsurf, GitHub Copilot). --- ### `contentrain serve` -Starts the local review UI or the MCP stdio server. +Three roles: web UI, MCP stdio, MCP HTTP. -#### Web UI Mode (default) +#### Web UI (default) ```bash -# Default: localhost:3333 contentrain serve - -# Custom host and port contentrain serve --port 8080 --host 0.0.0.0 - -# Open browser automatically -contentrain serve --open - -# Demo mode — try without a real project -contentrain serve --demo +contentrain serve --demo # Temporary demo project, no setup required ``` -| Flag | Description | -|------|-------------| -| `--port ` | HTTP server port (default: `3333`) | -| `--host
` | Bind address (default: `localhost`) | -| `--open` | Open browser automatically | -| `--demo` | Start with a temporary demo project (no setup needed) | -| `--root ` | Project root path | - -**Environment variable overrides:** - -| Variable | Equivalent Flag | Description | -|----------|----------------|-------------| -| `CONTENTRAIN_STDIO=true` | `--stdio` | Use stdio MCP transport | -| `CONTENTRAIN_PORT` | `--port` | HTTP server port | -| `CONTENTRAIN_HOST` | `--host` | Bind address | -| `CONTENTRAIN_NO_OPEN=true` | — | Disable auto browser open | -| `CONTENTRAIN_PROJECT_ROOT` | `--root` | Project root path | - -CLI flags take precedence over environment variables. +Serves REST endpoints (`/api/status`, `/api/content`, `/api/branches`, `/api/doctor`, `/api/describe-format`, `/api/preview/merge`, `/api/normalize/*`, `/api/capabilities`, `/api/branches/:name/sync-status`), a WebSocket stream (`meta:changed`, `file-watch:error`, `sync:warning`, `branch:*` events), and the bundled Vue UI. -The web UI provides: -- REST endpoints for status, content, validation, branches, and normalize data -- WebSocket stream for live updates -- Embedded Vue application for visual content review -- Branch management (merge, reject, inspect diffs) - -#### MCP Stdio Mode +#### MCP stdio ```bash contentrain serve --stdio ``` -| Flag | Description | -|------|-------------| -| `--stdio` | Use stdio MCP transport (for IDE integration) | +For IDE agents. Same 17 tools, stdio transport. -Use stdio mode when connecting an IDE agent (Claude Code, Cursor, Windsurf) to the local project. This exposes all 16 MCP tools over the stdio transport. - -The fastest way to configure this is with the `setup` command: +#### MCP HTTP ```bash -contentrain setup claude-code # or: cursor, vscode, windsurf, copilot +contentrain serve --mcpHttp --authToken $(openssl rand -hex 32) +contentrain serve --mcpHttp --port 3334 --host 0.0.0.0 --authToken $TOKEN ``` -
-Manual config (all IDEs use the same JSON) - -```json -{ - "mcpServers": { - "contentrain": { - "command": "npx", - "args": ["contentrain", "serve", "--stdio"] - } - } -} -``` +| Flag | Env var | Description | +|------|---------|-------------| +| `--mcpHttp` | `CONTENTRAIN_MCP_HTTP=true` | Enable HTTP MCP at `POST /mcp` | +| `--port ` | `CONTENTRAIN_PORT` | Port (default 3333) | +| `--host ` | `CONTENTRAIN_HOST` | Bind address (default `localhost`) | +| `--authToken ` | `CONTENTRAIN_AUTH_TOKEN` | Required Bearer token | -| IDE | Config file | -|-----|-------------| -| Claude Code | `.mcp.json` | -| Cursor | `.cursor/mcp.json` | -| VS Code | `.vscode/mcp.json` | -| Windsurf | `.windsurf/mcp.json` | - -
+**Secure-by-default:** non-localhost binds (`0.0.0.0` or specific IPs) **hard-error** without `--authToken` / `CONTENTRAIN_AUTH_TOKEN`. This is deliberate (OWASP Secure-by-Default) — the HTTP MCP endpoint exposes full project write access. ## Studio Integration -The `studio` command group connects the CLI to [Contentrain Studio](/studio) — the enterprise web surface for team content management. +The `studio` command group connects the CLI to [Contentrain Studio](/studio). ### Authentication ```bash -# Sign in via GitHub or Google OAuth contentrain studio login - -# Select provider directly contentrain studio login --provider github - -# Connect to a self-hosted Studio instance contentrain studio login --url https://studio.example.com - -# Check who you're logged in as contentrain studio whoami - -# Sign out and clear stored credentials contentrain studio logout ``` -| Flag | Description | -|------|-------------| -| `--provider ` | Skip provider selection prompt | -| `--url ` | Studio instance URL (default: `https://studio.contentrain.io`) | - -Credentials are stored in `~/.contentrain/credentials.json` with `0o600` permissions — never inside the project directory. - -**Environment variables:** - -| Variable | Description | -|----------|-------------| -| `CONTENTRAIN_STUDIO_TOKEN` | Skip interactive login in CI/CD | -| `CONTENTRAIN_STUDIO_URL` | Override Studio instance URL | +Credentials stored in `~/.contentrain/credentials.json` (mode `0o600`). Use `CONTENTRAIN_STUDIO_TOKEN` for CI. -### Connecting a Repository +### Connecting a Repository {#connecting-a-repository} ```bash -# Interactive flow: workspace → GitHub App → repo → scan → create project contentrain studio connect - -# Skip workspace selection contentrain studio connect --workspace ws-123 - -# JSON output for scripting contentrain studio connect --json ``` -| Flag | Description | -|------|-------------| -| `--workspace ` | Skip workspace selection prompt | -| `--json` | Output result as JSON (workspace, project, repository, scan) | - -The `connect` command links your local repository to a Studio project in one interactive flow: - -1. **Workspace** — select an existing workspace (auto-selects if only one) -2. **GitHub App** — checks if the Contentrain GitHub App is installed; if not, opens the browser for installation -3. **Repository** — detects the current git remote and matches it against accessible repos -4. **Scan** — checks the repository for `.contentrain/` configuration, reports found models and locales -5. **Create** — prompts for a project name and creates the project in Studio - -After a successful connection, workspace and project IDs are saved as defaults so subsequent `studio` commands skip interactive selection. - -::: tip Run `contentrain init` First -The connect flow works best when `.contentrain/` is already initialized and pushed to the repository. The scan step confirms your setup, but you can also connect first and initialize later. -::: +Interactive flow: workspace → GitHub App install → repo detection → `.contentrain/` scan → project creation. Defaults are cached for subsequent `studio` commands. ### Project Monitoring -#### `contentrain studio status` - -```bash -contentrain studio status -contentrain studio status --workspace ws-123 --project proj-456 --json -``` - -| Flag | Description | -|------|-------------| -| `--workspace ` | Workspace ID (skip selection prompt) | -| `--project ` | Project ID (skip selection prompt) | -| `--json` | Output as JSON | - -Shows project overview: branches, CDN status, and team. - -#### `contentrain studio activity` - ```bash -contentrain studio activity -contentrain studio activity --limit 10 --json +contentrain studio status # Branches + CDN + team +contentrain studio activity --limit 10 # Recent activity feed +contentrain studio usage # AI messages, storage, bandwidth ``` -| Flag | Description | -|------|-------------| -| `--limit ` | Number of entries (default: `20`) | -| `--workspace ` | Workspace ID | -| `--project ` | Project ID | -| `--json` | Output as JSON | - -Shows recent activity feed. - -#### `contentrain studio usage` - -```bash -contentrain studio usage -contentrain studio usage --workspace ws-123 --json -``` - -| Flag | Description | -|------|-------------| -| `--workspace ` | Workspace ID | -| `--project ` | Project ID (for context resolution) | -| `--json` | Output as JSON | - -Shows workspace usage metrics (AI messages, storage, bandwidth). - ### Branch Management -#### `contentrain studio branches` - ```bash contentrain studio branches -contentrain studio branches --workspace ws-123 --project proj-456 --json ``` -| Flag | Description | -|------|-------------| -| `--workspace ` | Workspace ID | -| `--project ` | Project ID | -| `--json` | Output as JSON | - List pending branches, interactively merge or reject. ### CDN Setup & Delivery -#### `contentrain studio cdn-init` - -```bash -contentrain studio cdn-init -contentrain studio cdn-init --workspace ws-123 --project proj-456 -``` - -| Flag | Description | -|------|-------------| -| `--workspace ` | Workspace ID | -| `--project ` | Project ID | - -Interactive setup: create API key, trigger first build, get SDK snippet. - -#### `contentrain studio cdn-build` - ```bash -contentrain studio cdn-build -contentrain studio cdn-build --wait --json +contentrain studio cdn-init # First-time CDN setup +contentrain studio cdn-build --wait # Trigger + wait for build ``` -| Flag | Description | -|------|-------------| -| `--wait` | Wait for build to complete | -| `--workspace ` | Workspace ID | -| `--project ` | Project ID | -| `--json` | Output as JSON | - -Trigger a CDN rebuild after content changes. - -### Webhooks - -#### `contentrain studio webhooks` +### Webhooks & Submissions ```bash contentrain studio webhooks -contentrain studio webhooks --workspace ws-123 --project proj-456 --json -``` - -| Flag | Description | -|------|-------------| -| `--workspace ` | Workspace ID | -| `--project ` | Project ID | -| `--json` | Output as JSON | - -Manage webhooks: create, delete, test, view deliveries. - -### Form Submissions - -#### `contentrain studio submissions` - -```bash contentrain studio submissions --form contact-form -contentrain studio submissions --form contact-form --status pending --json +contentrain studio submissions --form contact-form --status pending ``` -| Flag | Description | -|------|-------------| -| `--form ` | Form model ID | -| `--status ` | Filter by status (`pending`, `approved`, `rejected`) | -| `--workspace ` | Workspace ID | -| `--project ` | Project ID | -| `--json` | Output as JSON | - -Manage form submissions: list, approve, reject. - -::: tip Studio + CLI = Full Developer Experience -Studio handles team collaboration, media management, AI conversations, and CDN delivery in the browser. The CLI gives developers terminal access to the same operations — authenticate once, then manage branches, trigger builds, and monitor usage without leaving the editor. -::: +Each Studio command accepts `--workspace `, `--project `, and `--json` for scripting. --- ## Typical Workflow ```bash -# 1. Initialize the project (auto-configures MCP for detected IDEs) +# 1. Initialize (auto-configures MCP for detected IDEs) contentrain init -# 2. Or set up MCP for a specific IDE manually +# 2. Or set up a specific IDE later contentrain setup claude-code -# 3. Check project health +# 3. Inspect project health contentrain status contentrain doctor @@ -688,7 +374,7 @@ contentrain doctor # 5. Generate the typed SDK client contentrain generate -# 6. Validate everything +# 6. Validate everything (optionally --watch during dev) contentrain validate # 7. Review agent-created branches @@ -699,7 +385,7 @@ contentrain serve ``` ::: tip From Local to Team -The CLI covers single-developer workflows. When you need workspace/project management, role-based collaboration, visual diff review, media operations, and content CDN delivery, [Contentrain Studio](/studio) extends the same Git-native model with an open-core team web surface that can be self-hosted or run as a managed Pro/Enterprise offering. +The CLI covers single-developer workflows. When you need workspace/project management, role-based collaboration, visual diff review, media operations, and content CDN delivery, [Contentrain Studio](/studio) extends the same Git-native model with an open-core team web surface. ::: ## Related Pages diff --git a/docs/packages/mcp.md b/docs/packages/mcp.md index e055f3b..a6c5c60 100644 --- a/docs/packages/mcp.md +++ b/docs/packages/mcp.md @@ -1,6 +1,6 @@ --- title: MCP Tools -description: Complete reference for @contentrain/mcp — the provider-agnostic MCP engine powering AI content governance with 16 deterministic tools over stdio or HTTP +description: Complete reference for @contentrain/mcp — the provider-agnostic MCP engine powering AI content governance with 17 deterministic tools over stdio or HTTP order: 1 slug: mcp --- @@ -43,15 +43,14 @@ Optional parser support for higher-quality source scanning: ## Tool Catalog -The MCP server exposes 16 tools organized by function. Each tool includes [MCP annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) so clients can distinguish safe reads from writes and destructive operations. - - +The MCP server exposes **17 tools** organized by function. Each tool includes [MCP annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) so clients can distinguish safe reads from writes and destructive operations. | Tool | Title | Read-only | Destructive | |------|-------|-----------|-------------| | `contentrain_status` | Project Status | Yes | — | | `contentrain_describe` | Describe Model | Yes | — | | `contentrain_describe_format` | Describe Format | Yes | — | +| `contentrain_doctor` | Project Health Report | Yes | — | | `contentrain_init` | Initialize Project | — | — | | `contentrain_scaffold` | Scaffold Template | — | — | | `contentrain_model_save` | Save Model | — | — | @@ -75,6 +74,7 @@ The MCP server exposes 16 tools organized by function. Each tool includes [MCP a | `contentrain_status` | Project overview | Config, models, branch health, context, validation summary | | `contentrain_describe` | Model deep-dive | Full schema, sample data, field types for any model | | `contentrain_describe_format` | Format reference | File structure, JSON formats, markdown conventions, locale strategies | +| `contentrain_doctor` | Health diagnostics | Setup validation, SDK freshness, orphan content, branch limits, unused keys, missing translations | | `contentrain_content_list` | Read content | List and filter content entries with optional relation resolution | ### Write Tools (Git-Backed, Branch-Isolated) @@ -88,7 +88,7 @@ The MCP server exposes 16 tools organized by function. Each tool includes [MCP a | `contentrain_content_save` | Write content | Save entries for any model kind (collection, singleton, dictionary, document) | | `contentrain_content_delete` | Remove content | Delete specific content entries | | `contentrain_validate` | Check & fix | Validate content against schemas, optionally auto-fix structural issues | -| `contentrain_submit` | Push branches | Push `contentrain/*` review branches to remote | +| `contentrain_submit` | Push branches | Push `cr/*` review branches to remote | | `contentrain_merge` | Merge branches | Merge a review-mode branch into contentrain locally (no external platform needed) | ### Normalize Tools (Scan + Apply) @@ -129,7 +129,7 @@ All write operations create or update `cr/*` branches: - Content changes go to isolated branches (`cr/{scope}/{target}[/{locale}]/{timestamp}-{suffix}`) - Humans review via `contentrain diff` or the serve UI - Approved changes merge into the `contentrain` branch, baseBranch is advanced via update-ref -- Branch health is tracked and surfaced via `contentrain_status` +- Branch health is tracked and surfaced via `contentrain_status` (warning at 50, blocked at 80 active branches) - Legacy `contentrain/*` branches are auto-migrated on first init ### 4. Local-First by Default, Remote Providers Opt-In @@ -161,9 +161,9 @@ Agent drivers treat `capability_required` as a retry signal. See [Providers & Tr ## Transports - **stdio** — `contentrain serve --stdio` or `npx contentrain-mcp`. IDE agents (Claude Code, Cursor, Windsurf) connect over stdin/stdout. -- **HTTP** — `contentrain serve --mcpHttp --authToken $TOKEN` or the programmatic `startHttpMcpServer({...})` / `startHttpMcpServerWith({ provider })` exports. Streamable HTTP at `POST /mcp` with optional Bearer auth. See the [HTTP Transport guide](/guides/http-transport). +- **HTTP** — `contentrain serve --mcpHttp --authToken $TOKEN` or the programmatic `startHttpMcpServer({...})` / `startHttpMcpServerWith({ provider })` exports. Streamable HTTP at `POST /mcp` with secure-by-default Bearer auth. See the [HTTP Transport guide](/guides/http-transport). -Both transports serve the same 16 tools and the same JSON response shapes. +Both transports serve the same 17 tools and the same JSON response shapes. ## Providers @@ -195,12 +195,11 @@ Use the [Ecosystem Map](/ecosystem) when you need the full package-to-product re ### Check Project Status -```ts -// Agent calls contentrain_status -// Returns: config, models list, branch health, pending changes, validation state -``` +Ask your agent: *"What's the current state of my Contentrain project?"* — triggers `contentrain_status`. Returns config, models list, branch health, pending changes, validation state. + +### Run Health Checks -Ask your agent: *"What's the current state of my Contentrain project?"* +Ask your agent: *"Is my Contentrain setup healthy?"* — triggers `contentrain_doctor`. Returns structured checks (env, structure, models, orphans, branches, SDK freshness). With `usage: true`, also analyzes unused keys, duplicates, missing translations. ### Create a Model @@ -250,11 +249,11 @@ Ask your agent: *"Add a new blog post about getting started"* // Phase 2: Extract content // Agent calls contentrain_apply with mode: "extract" -// Creates models, writes content entries, tracks sources +// Creates models, writes content entries, tracks sources (cr/normalize/extract/*) // Phase 3: Reuse in source // Agent calls contentrain_apply with mode: "reuse" -// Patches source files with i18n function calls +// Patches source files with i18n function calls (cr/normalize/reuse/*) ``` Ask your agent: *"Scan my landing page for hardcoded strings and extract them"* @@ -292,16 +291,16 @@ This auto-creates the correct MCP config file and installs AI rules/skills. -Once connected, the agent has access to all 16 MCP tools and can manage your content through natural language. +Once connected, the agent has access to all 17 MCP tools and can manage your content through natural language. ## Trust Model | Trust Level | Tools | Risk | Notes | |-------------|-------|------|-------| -| **HIGH** (read-only) | `status`, `describe`, `describe_format`, `content_list` | None | Safe to call anytime, no side effects | -| **MEDIUM** (git-isolated writes) | `model_save`, `content_save`, `content_delete`, `model_delete`, `validate`, `scaffold`, `bulk` | Low | Changes isolated to `contentrain/*` branches, reviewable | +| **HIGH** (read-only) | `status`, `describe`, `describe_format`, `doctor`, `content_list` | None | Safe to call anytime, no side effects | +| **MEDIUM** (git-isolated writes) | `model_save`, `content_save`, `content_delete`, `model_delete`, `validate`, `scaffold`, `bulk` | Low | Changes isolated to `cr/*` branches, reviewable | | **LOW** (source modification) | `scan`, `apply` | Medium | Normalize touches source files — always use dry_run first | -| **MEDIUM** (remote push) | `submit` | Medium | Pushes branches to remote — requires network access | +| **MEDIUM** (remote push) | `submit`, `merge` | Medium | Pushes branches to remote or merges — requires network access and review | ::: danger Source Modifications The `contentrain_apply` tool with `mode: "reuse"` modifies your source code files. Always run with `dry_run: true` first, review the patches carefully, and use the review workflow before merging. @@ -311,12 +310,13 @@ The `contentrain_apply` tool with `mode: "reuse"` modifies your source code file ``` 1. contentrain_status → understand project state -2. contentrain_init → bootstrap if needed -3. contentrain_describe_format → understand storage contract -4. contentrain_model_save → define content schemas -5. contentrain_content_save → write content entries -6. contentrain_validate → check everything is valid -7. contentrain_submit → push for review +2. contentrain_doctor → validate setup health +3. contentrain_init → bootstrap if needed +4. contentrain_describe_format → understand storage contract +5. contentrain_model_save → define content schemas +6. contentrain_content_save → write content entries +7. contentrain_validate → check everything is valid +8. contentrain_submit → push for review ``` ## Core Exports @@ -334,16 +334,30 @@ await server.connect(transport) Available subpath exports: -- `@contentrain/mcp/server` — MCP server factory +- `@contentrain/mcp/server` — MCP server factory and stdio setup +- `@contentrain/mcp/server/http` — HTTP transport server factory - `@contentrain/mcp/core/config` — Config manager +- `@contentrain/mcp/core/context` — Context JSON manager - `@contentrain/mcp/core/model-manager` — Model CRUD - `@contentrain/mcp/core/content-manager` — Content CRUD - `@contentrain/mcp/core/validator` — Validation engine - `@contentrain/mcp/core/scanner` — Source code scanner - `@contentrain/mcp/core/graph-builder` — Component graph - `@contentrain/mcp/core/apply-manager` — Normalize apply +- `@contentrain/mcp/core/doctor` — Health check engine +- `@contentrain/mcp/core/contracts` — RepoProvider interface types +- `@contentrain/mcp/core/ops` — Git operation utilities +- `@contentrain/mcp/core/overlay-reader` — Overlay file reading +- `@contentrain/mcp/core/scan-config` — Scan configuration - `@contentrain/mcp/git/transaction` — Git transaction flow +- `@contentrain/mcp/git/branch-lifecycle` — Branch health tracking - `@contentrain/mcp/templates` — Scaffold templates +- `@contentrain/mcp/tools/annotations` — Tool metadata (TOOL_NAMES, TOOL_ANNOTATIONS) +- `@contentrain/mcp/util/detect` — Framework detection +- `@contentrain/mcp/util/fs` — File system utilities +- `@contentrain/mcp/providers/local` — LocalProvider implementation +- `@contentrain/mcp/providers/github` — GitHubProvider implementation +- `@contentrain/mcp/providers/gitlab` — GitLabProvider implementation ## Related Pages diff --git a/docs/packages/rules.md b/docs/packages/rules.md index 88ee787..3978e32 100644 --- a/docs/packages/rules.md +++ b/docs/packages/rules.md @@ -94,7 +94,10 @@ import { } from '@contentrain/rules' // Check if a tool exists +console.log(MCP_TOOLS.length) // 17 console.log(MCP_TOOLS.includes('contentrain_validate')) // true +console.log(MCP_TOOLS.includes('contentrain_merge')) // true +console.log(MCP_TOOLS.includes('contentrain_doctor')) // true // Path to essential guardrails markdown console.log(ESSENTIAL_RULES_FILE) // 'essential/contentrain-essentials.md' diff --git a/docs/packages/types.md b/docs/packages/types.md index 6c784ef..fcb23cc 100644 --- a/docs/packages/types.md +++ b/docs/packages/types.md @@ -114,6 +114,31 @@ const result: ValidationResult = { | `ContextJson` | Last operation context written by MCP | | `ModelSummary` | Lightweight model info for listing operations | +### Provider Contract Types + +Third-party developers can implement custom providers by implementing these interfaces: + +| Interface / Type | Purpose | +|-----------|---------| +| `RepoProvider` | Full provider contract: read, write, branch, merge, diff operations | +| `RepoReader` | Read-only interface (readFile, listDirectory, fileExists) | +| `RepoWriter` | Write interface (applyPlan for atomic commits) | +| `ProviderCapabilities` | Capability flags (localWorktree, sourceRead, sourceWrite, pushRemote, branchProtection, pullRequestFallback, astScan) | +| `FileChange` | A single file addition, modification, or deletion (`{ path, content: string \| null }`) | +| `ApplyPlanInput` | Input for a single atomic commit (branch, changes, message, author, optional base) | +| `Commit` | Result of a commit operation (sha, message, author, timestamp) | +| `Branch` | Git branch metadata (name, sha, protected) | +| `FileDiff` | File change within a plan (path, status, before, after) | +| `MergeResult` | Merge outcome (merged flag, sha, pullRequestUrl, optional `sync?: SyncResult` for LocalProvider) | +| `SyncResult` | Selective file sync result (synced, skipped, optional warning) | +| `CommitAuthor` | Commit author metadata (name, email) | + +Pre-built capability set: + +- `LOCAL_CAPABILITIES` — Full capability set for LocalProvider (all seven capabilities enabled). Exported from `@contentrain/types` for custom providers that back onto the local filesystem. + +See [RepoProvider Reference](/reference/providers) for the complete interface definitions and a minimum-viable provider recipe. + ### Storage Types These types define the canonical JSON structure for each model kind on disk: diff --git a/docs/reference/providers.md b/docs/reference/providers.md index 0cecac4..96be6f8 100644 --- a/docs/reference/providers.md +++ b/docs/reference/providers.md @@ -41,13 +41,13 @@ interface ApplyPlanInput { changes: FileChange[] message: string author: CommitAuthor - base?: string // Defaults to provider's content-tracking branch + base?: string // Defaults to CONTENTRAIN_BRANCH ('contentrain') } ``` `changes` entries are `{ path, content }`; `content: null` means delete. Providers are responsible for resolving paths against their backing store and translating the change set into whatever commit primitive the backend supports. -## Branch ops +## Branch operations Providers extend `RepoReader` and `RepoWriter` with branch / merge / diff operations to form the full `RepoProvider`: @@ -65,7 +65,7 @@ interface RepoProvider extends RepoReader, RepoWriter { } ``` -`MergeResult` is `{ merged, sha, pullRequestUrl }`. GitHub's `repos.merge` fills `sha`; GitLab's MR-based flow fills both `sha` and `pullRequestUrl`; a provider that hits branch protection returns `merged: false` with a `pullRequestUrl` so the caller can delegate. +`MergeResult` is `{ merged, sha, pullRequestUrl, sync? }`. GitHubProvider fills `sha` on direct merges; GitLabProvider fills both `sha` and `pullRequestUrl` (merges via MR). LocalProvider populates `sync: SyncResult` to describe file syncing to the working tree. When branch protection blocks a direct merge, any provider may return `merged: false` with a `pullRequestUrl` fallback. ## Capabilities @@ -83,6 +83,18 @@ interface ProviderCapabilities { } ``` +Capability meanings: + +| Capability | Purpose | +|---|---| +| `localWorktree` | Provider backs onto a local filesystem worktree and can selectively sync changes to developer's working tree | +| `sourceRead` | Provider can read arbitrary source files outside `.contentrain/` (required for normalize extract) | +| `sourceWrite` | Provider can write arbitrary source files outside `.contentrain/` (required for normalize reuse) | +| `pushRemote` | Provider can push commits to a remote repository (required for submit) | +| `branchProtection` | Provider detects branch protection rules on the remote | +| `pullRequestFallback` | Provider can open a pull request as a fallback when direct merge is blocked | +| `astScan` | Provider can execute AST scanners against source files (implies local disk access) | + Built-in capability sets: | Capability | LocalProvider | GitHubProvider | GitLabProvider | @@ -95,7 +107,19 @@ Built-in capability sets: | `pullRequestFallback` | — | ✓ | ✓ | | `astScan` | ✓ | — | — | -`LOCAL_CAPABILITIES` is exported from `@contentrain/types` for ergonomic use in custom providers that back onto the local filesystem. +`LOCAL_CAPABILITIES` is exported from `@contentrain/types` for ergonomic use in custom providers that back onto the local filesystem: + +```ts +export const LOCAL_CAPABILITIES: ProviderCapabilities = { + localWorktree: true, + sourceRead: true, + sourceWrite: true, + pushRemote: true, + branchProtection: false, + pullRequestFallback: false, + astScan: true, +} +``` ## Supporting types @@ -124,6 +148,13 @@ interface MergeResult { merged: boolean sha: string | null pullRequestUrl: string | null + sync?: SyncResult // Only populated by LocalProvider +} + +interface SyncResult { + synced: string[] // Files successfully synced to working tree + skipped: string[] // Files skipped due to uncommitted local changes + warning?: string // Human-readable warning if files were skipped } ``` diff --git a/packages/cli/README.md b/packages/cli/README.md index 54d58ba..fe12599 100644 --- a/packages/cli/README.md +++ b/packages/cli/README.md @@ -27,7 +27,7 @@ This package is the human-facing companion to: - [`@contentrain/query`](https://github.com/Contentrain/ai/tree/main/packages/sdk/js) for generated runtime queries - [`@contentrain/rules`](https://github.com/Contentrain/ai/tree/main/packages/rules) and [`@contentrain/skills`](https://github.com/Contentrain/ai/tree/main/packages/skills) for agent guidance -## 🚀 Install +## Install Use `npx`: @@ -47,7 +47,15 @@ Requirements: - Node.js 22+ - Git available in `PATH` -## 🧰 Commands +## Global Flags + +| Flag | Env var | Description | +| --- | --- | --- | +| `--debug` | `CONTENTRAIN_DEBUG=1` | Verbose debug logging to stderr (works on every subcommand) | + +Example: `contentrain --debug status` or `CONTENTRAIN_DEBUG=1 contentrain validate`. + +## Commands | Command | Purpose | | --- | --- | @@ -61,7 +69,9 @@ Requirements: | `contentrain describe ` | Inspect a model's schema, stats, and import snippet | | `contentrain describe-format` | Print the Contentrain content-format specification | | `contentrain scaffold --template` | Apply a template (`blog`, `landing`, `docs`, `ecommerce`, `saas`, `i18n`, `mobile`) | -| `contentrain serve` | Start the local review UI, the MCP stdio server (`--stdio`), or the MCP HTTP server (`--mcpHttp`) | +| `contentrain setup ` | Configure MCP server + AI rules for IDE (Claude Code, Cursor, Windsurf, VSCode, Copilot) | +| `contentrain skills` | Install, update, or list Contentrain AI skills and IDE rules | +| `contentrain serve` | Start the local review UI (REST + WS), MCP stdio server (`--stdio`), or MCP HTTP server (`--mcpHttp`) | | `contentrain studio connect` | Connect a repository to a Studio project | | `contentrain studio login` | Authenticate with Contentrain Studio | | `contentrain studio logout` | Log out from Studio | @@ -75,7 +85,23 @@ Requirements: | `contentrain studio webhooks` | Manage webhooks | | `contentrain studio submissions` | Manage form submissions | -## 🔄 Typical Flow +## Flag Matrix + +Every read command supports `--json` for CI use; write commands surface `--watch` or `--yes` where they apply: + +| Command | Notable flags | +| --- | --- | +| `status` | `--json` | +| `doctor` | `--json`, `--usage` — non-zero exit on failure | +| `validate` | `--json`, `--fix`, `--interactive`, `--watch`, `--model ` | +| `generate` | `--json`, `--watch` | +| `diff` | `--json` | +| `merge` | `--yes` (skip confirm) | +| `describe` | `--sample`, `--locale`, `--json` | +| `scaffold` | `--template `, `--locales `, `--no-sample`, `--json` | +| `serve` | `--port`, `--host`, `--open`, `--demo`, `--stdio`, `--mcpHttp`, `--authToken` | + +## Typical Flow Initialize a project: @@ -83,39 +109,56 @@ Initialize a project: contentrain init ``` -Check project state: +Check project state (with optional JSON for CI): ```bash contentrain status +contentrain status --json + contentrain doctor +contentrain doctor --json +contentrain doctor --usage # Analyze content key usage ``` Generate the typed SDK client: ```bash contentrain generate +contentrain generate --watch # Watch for changes +contentrain generate --json # CI-friendly JSON output ``` -Validate content and create review-branch fixes when possible: +Validate content and create review-branch fixes: ```bash contentrain validate contentrain validate --fix +contentrain validate --watch # Live validation in dev mode +contentrain validate --json # CI output ``` Review pending changes: ```bash contentrain diff +contentrain diff --json # CI integration ``` Open the local UI: ```bash contentrain serve +contentrain serve --demo # Start with a temporary demo project ``` -## 🖥 `serve` Modes +Enable detailed logging: + +```bash +contentrain --debug status +CONTENTRAIN_DEBUG=1 contentrain validate # Via environment variable +``` + +## `serve` Modes `contentrain serve` has three roles. @@ -124,9 +167,12 @@ contentrain serve ```bash contentrain serve contentrain serve --port 3333 --host localhost +contentrain serve --demo # Temporary project (no setup needed) ``` -Serves the REST endpoints for status / content / validation / branches / normalize, a WebSocket stream for live updates, and the embedded Vue `serve-ui` app bundled with the CLI. +Serves REST endpoints for status / content / validation / branches / normalize / doctor / describe-format / preview-merge, a WebSocket stream for live updates, and the embedded Vue `serve-ui` app bundled with the CLI. + +WebSocket event types: `connected`, `config:changed`, `context:changed`, `meta:changed`, `model:changed`, `content:changed`, `branch:created`, `branch:merged`, `branch:rejected`, `branch:merge-conflict`, `sync:warning`, `validation:updated`, `normalize:plan-updated`, `file-watch:error`. ### MCP stdio (IDE agents) @@ -143,7 +189,7 @@ contentrain serve --mcpHttp --authToken $(openssl rand -hex 32) contentrain serve --mcpHttp --port 3333 --host 0.0.0.0 --authToken $TOKEN ``` -Spins up a [Streamable HTTP MCP](https://modelcontextprotocol.io) server at `POST /mcp`. Bearer auth is enforced when `--authToken` is set (or `CONTENTRAIN_AUTH_TOKEN` is exported). Use HTTP mode when: +Spins up a [Streamable HTTP MCP](https://modelcontextprotocol.io) server at `POST /mcp`. Bearer auth is **required** on non-localhost binds — the CLI hard-errors when no `--authToken` is set for an exposed interface (OWASP Secure-by-Default). Use HTTP mode when: - Studio's agent drives MCP remotely - a CI runner needs deterministic content operations @@ -151,7 +197,7 @@ Spins up a [Streamable HTTP MCP](https://modelcontextprotocol.io) server at `POS HTTP sessions use the same `LocalProvider` backing as stdio — the transport differs, the behaviour does not. Remote git-host providers (`GitHubProvider`, `GitLabProvider`) are constructed by embedders who instantiate the MCP server programmatically; see the MCP package docs for that flow. -## 📦 `generate` and `#contentrain` +## `generate` and `#contentrain` `contentrain generate` writes a typed client to `.contentrain/client/` and injects `#contentrain` imports into your `package.json`. @@ -167,7 +213,30 @@ Run with watch mode during local model/content work: contentrain generate --watch ``` -## 👀 Review Workflow +## IDE Setup and AI Skills + +Configure your IDE to use Contentrain's MCP server and AI agent rules: + +```bash +contentrain setup claude-code +contentrain setup cursor +contentrain setup vscode +contentrain setup --all # Configure all detected IDEs +``` + +Install or update AI agent skills and IDE rules: + +```bash +contentrain skills +contentrain skills --update # Force update +contentrain skills --list # List installed skills +``` + +This installs: +- Contentrain Agent Skills (task guidance for Claude, Cursor, etc.) +- IDE rules files (CLAUDE.md, .cursorrules, .windsurfrules) + +## Review Workflow Most write operations create feature branches from the dedicated `contentrain` branch. In review mode, these branches are pushed to remote for team review. In auto-merge mode, they are merged into the `contentrain` branch and baseBranch is advanced via update-ref. @@ -181,10 +250,10 @@ contentrain diff to understand: - how many active `cr/*` review branches exist on the `contentrain` branch -- whether branch health is blocking new writes +- whether branch health is blocking new writes (warning at 50, blocked at 80) - what changed before merging or deleting a branch -## 🔗 Studio Integration +## Studio Integration The `studio` command group connects the CLI to [Contentrain Studio](https://studio.contentrain.io) for enterprise workflows. @@ -227,21 +296,11 @@ contentrain studio submissions --form contact-form Credentials are stored securely in `~/.contentrain/credentials.json` with `0o600` permissions. Use `CONTENTRAIN_STUDIO_TOKEN` environment variable for CI/CD. -## 🤖 IDE Rules - -`contentrain init` installs project-level AI rules automatically: - -- `CLAUDE.md` for Claude Code or generic fallback -- `.cursorrules` for Cursor -- `.windsurfrules` for Windsurf - -If the target file already exists, Contentrain appends its rules instead of overwriting unrelated content where possible. - -## 📚 Documentation +## Documentation Full documentation at **[ai.contentrain.io/packages/cli](https://ai.contentrain.io/packages/cli)**. -## 🛠 Development +## Development From the monorepo root: @@ -250,3 +309,7 @@ pnpm --filter contentrain test -- --run pnpm --filter contentrain exec tsc --noEmit pnpm --filter contentrain build ``` + +## License + +MIT diff --git a/packages/mcp/README.md b/packages/mcp/README.md index cfc541d..ccd3b2a 100644 --- a/packages/mcp/README.md +++ b/packages/mcp/README.md @@ -25,7 +25,7 @@ This package is the runtime core behind Contentrain's MCP integration. It can be - an embeddable server (`createServer(projectRoot)`) - a low-level toolkit for config, models, content, validation, scanning, and git transaction flow -## 🚀 Install +## Install ```bash pnpm add @contentrain/mcp @@ -44,7 +44,7 @@ Optional parser support for higher-quality source scanning: They are listed as optional dependencies. The scanner still works without them, but Vue/Astro/Svelte detection is stronger when they are installed. -## ✨ What It Does +## What It Does `@contentrain/mcp` manages a `.contentrain/` directory in your project and exposes MCP tools for: @@ -54,28 +54,30 @@ They are listed as optional dependencies. The scanner still works without them, - validation and auto-fix - normalize scan and apply flows - bulk operations -- branch submission and branch-health awareness +- branch submission, review-mode merge, and branch-health awareness +- project health checking (doctor) All write operations are designed around git-backed safety: - a dedicated `contentrain` branch serves as the content state single source of truth -- each write creates a temporary worktree on a feature branch forked from `contentrain` +- each write creates a temporary worktree on a feature branch forked from `contentrain` (branch name: `cr/{operation}/{model}/{locale}/{timestamp}-{suffix}`) - auto-merge: feature merges into `contentrain`, baseBranch advanced via update-ref, `.contentrain/` files selectively synced to developer's working tree - review: feature branch pushed to remote for team review - developer's working tree is never mutated during MCP git operations (no stash, no checkout, no merge) - context.json is committed together with content changes, not as a separate commit -- keep canonical JSON output -- surface validation and next-step hints to the caller +- canonical JSON output — sorted keys, 2-space indent, trailing newline +- validation + next-step hints surfaced to the caller -## 🧰 Tool Surface +## Tool Surface -16 MCP tools with [annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) for client safety hints: +17 MCP tools with [annotations](https://spec.modelcontextprotocol.io/specification/2025-03-26/server/tools/#annotations) (`readOnlyHint`, `destructiveHint`, `idempotentHint`) for client safety hints: | Tool | Purpose | Read-only | Destructive | | --- | --- | --- | --- | | `contentrain_status` | Project status, config, models, branch health, context | Yes | — | | `contentrain_describe` | Full schema and sample data for a model | Yes | — | | `contentrain_describe_format` | File-format and storage contract reference | Yes | — | +| `contentrain_doctor` | Project health report (env, structure, models, orphans, branches, SDK) | Yes | — | | `contentrain_init` | Create `.contentrain/` structure and base config | — | — | | `contentrain_scaffold` | Apply a starter template such as blog, docs, landing, saas | — | — | | `contentrain_model_save` | Create or update a model definition | — | — | @@ -84,13 +86,13 @@ All write operations are designed around git-backed safety: | `contentrain_content_delete` | Delete content entries | — | **Yes** | | `contentrain_content_list` | Read content entries | Yes | — | | `contentrain_validate` | Validate project content, optionally auto-fix structural issues | — | — | -| `contentrain_submit` | Push `contentrain/*` branches to remote | — | — | +| `contentrain_submit` | Push `cr/*` branches to remote | — | — | | `contentrain_merge` | Merge a review-mode branch into contentrain locally | — | — | | `contentrain_scan` | Graph- and candidate-based hardcoded string scan | Yes | — | | `contentrain_apply` | Normalize extract/reuse execution with dry-run support | — | — | | `contentrain_bulk` | Bulk locale copy, status updates, and deletes | — | — | -## 🚀 Quick Start +## Quick Start ### Configure via CLI (recommended) @@ -120,7 +122,7 @@ const transport = new StdioServerTransport() await server.connect(transport) ``` -## 🔄 Example MCP Flow +## Example MCP Flow Typical agent workflow: @@ -132,7 +134,7 @@ Typical agent workflow: 6. For hardcoded strings, use `contentrain_scan` then `contentrain_apply` 7. Push review branches with `contentrain_submit` -## 🧪 Normalize Flow +## Normalize Flow Normalize is intentionally split into two phases: @@ -145,7 +147,7 @@ Normalize is intentionally split into two phases: - creates or updates models - writes content entries - records source tracking -- creates a review branch +- creates a review branch (`cr/normalize/extract/{domain}/{timestamp}`) ### 2. Reuse @@ -154,20 +156,15 @@ Normalize is intentionally split into two phases: - patches source files using agent-provided expressions - adds imports when needed - enforces patch path safety and scope checks -- creates a separate review branch +- creates a separate review branch (`cr/normalize/reuse/{model}/{locale}/{timestamp}`) This split keeps content extraction separate from source rewriting. ### Transport / provider requirements -Normalize (`contentrain_scan` and `contentrain_apply`) requires local -disk access — AST scanners walk the source tree and patch files in -place. It runs only on a `LocalProvider` (stdio transport, or HTTP -transport configured with a `LocalProvider`). +Normalize (`contentrain_scan` and `contentrain_apply`) requires local disk access — AST scanners walk the source tree and patch files in place. It runs only on a `LocalProvider` (stdio transport, or HTTP transport configured with a `LocalProvider`). -Remote providers such as `GitHubProvider` expose `astScan: false`, -`sourceRead: false`, and `sourceWrite: false`. Calling these tools -over a remote provider returns a uniform capability error: +Remote providers such as `GitHubProvider` expose `astScan: false`, `sourceRead: false`, and `sourceWrite: false`. Calling these tools over a remote provider returns a uniform capability error: ```json { @@ -177,28 +174,17 @@ over a remote provider returns a uniform capability error: } ``` -Agents driving a remote transport should fall back to a local transport -(or a local checkout) before invoking normalize. +Agents driving a remote transport should fall back to a local transport (or a local checkout) before invoking normalize. -## 🌐 Remote Providers +## Remote Providers MCP supports three backends behind the same `RepoProvider` contract: -- **LocalProvider** — simple-git + worktree. Every tool (normalize - included) works on it. Stdio transport defaults to this. -- **GitHubProvider** — Octokit over the Git Data + Repos APIs. No - clone, no worktree. `@octokit/rest` ships as an optional peer - dependency. -- **GitLabProvider** — gitbeaker over the GitLab REST API. No clone, - no worktree. `@gitbeaker/rest` ships as an optional peer - dependency. Supports gitlab.com and self-hosted CE / EE. - -Each remote provider implements the same surface: reader (readFile / -listDirectory / fileExists), writer (applyPlan — one atomic commit), -branch ops (list / create / delete / diff / merge / isMerged / -getDefaultBranch). `mergeBranch` goes straight through on GitHub; on -GitLab it opens an MR and immediately accepts it so the final -`MergeResult` shape matches either way. +- **LocalProvider** — simple-git + worktree. Every tool (normalize included) works on it. Stdio transport defaults to this. +- **GitHubProvider** — Octokit over the Git Data + Repos APIs. No clone, no worktree. `@octokit/rest` ships as an optional peer dependency. +- **GitLabProvider** — gitbeaker over the GitLab REST API. No clone, no worktree. `@gitbeaker/rest` ships as an optional peer dependency. Supports gitlab.com and self-hosted CE / EE. + +Each remote provider implements the same surface: reader (readFile / listDirectory / fileExists), writer (applyPlan — one atomic commit), branch ops (list / create / delete / diff / merge / isMerged / getDefaultBranch). `mergeBranch` goes straight through on GitHub; on GitLab it opens an MR and immediately accepts it so the final `MergeResult` shape matches either way. ### GitLab — installation & usage @@ -222,24 +208,18 @@ const server = createServer({ provider }) // serve over stdio or the HTTP transport from @contentrain/mcp/server/http ``` -Capabilities: `sourceRead`, `sourceWrite`, `astScan`, `localWorktree` -are all `false`; `pushRemote`, `branchProtection`, -`pullRequestFallback` are `true`. Normalize / scan / apply reject -with a capability error on GitLabProvider — fall back to a local -transport for those flows. +Capabilities: `sourceRead`, `sourceWrite`, `astScan`, `localWorktree` are all `false`; `pushRemote`, `branchProtection`, `pullRequestFallback` are `true`. Normalize / scan / apply reject with a capability error on GitLabProvider — fall back to a local transport for those flows. ### Bitbucket — coming soon -Bitbucket Cloud + Data Center support is on the roadmap. Until the -provider ships, use the `contentrain_describe_format` tool to drive -Contentrain content operations manually from a Bitbucket checkout via -the LocalProvider path. +Bitbucket Cloud + Data Center support is on the roadmap. Until the provider ships, use the `contentrain_describe_format` tool to drive Contentrain content operations manually from a Bitbucket checkout via the LocalProvider path. -## 📦 Core Exports +## Core Exports The package also exposes low-level modules for embedding and advanced use: - `@contentrain/mcp/server` +- `@contentrain/mcp/server/http` - `@contentrain/mcp/core/config` - `@contentrain/mcp/core/context` - `@contentrain/mcp/core/model-manager` @@ -248,31 +228,38 @@ The package also exposes low-level modules for embedding and advanced use: - `@contentrain/mcp/core/scanner` - `@contentrain/mcp/core/graph-builder` - `@contentrain/mcp/core/apply-manager` +- `@contentrain/mcp/core/scan-config` +- `@contentrain/mcp/core/doctor` +- `@contentrain/mcp/core/contracts` +- `@contentrain/mcp/core/ops` +- `@contentrain/mcp/core/overlay-reader` - `@contentrain/mcp/util/detect` - `@contentrain/mcp/util/fs` - `@contentrain/mcp/git/transaction` - `@contentrain/mcp/git/branch-lifecycle` +- `@contentrain/mcp/tools/annotations` - `@contentrain/mcp/templates` +- `@contentrain/mcp/providers/local` - `@contentrain/mcp/providers/github` - `@contentrain/mcp/providers/gitlab` These are intended for Contentrain tooling and advanced integrations, not for direct manual editing of `.contentrain/` files. -## 🧠 Design Constraints +## Design Constraints Key design decisions in this package: - local-first **by default** — stdio transport + LocalProvider works without any network dependency -- provider-agnostic engine — the same 16 tools run over LocalProvider, GitHubProvider, or GitLabProvider behind a single `RepoProvider` contract +- provider-agnostic engine — the same 17 tools run over LocalProvider, GitHubProvider, or GitLabProvider behind a single `RepoProvider` contract - remote provider SDKs (`@octokit/rest`, `@gitbeaker/rest`) are optional peer dependencies — pulled in only when their provider is used - JSON-only content storage - git-backed write workflow (worktree transaction locally, single atomic commit over the Git Data / REST APIs remotely) - canonical serialization — byte-deterministic output, sorted keys, trailing newline - framework-agnostic MCP layer - agent decides content semantics, MCP enforces deterministic execution -- capability gates — tools that need source-tree access (normalize, scan, apply) reject with a uniform `capability_required` error on remote providers +- capability gates — tools that need source-tree access (normalize, scan, apply, doctor) reject with a uniform `capability_required` error on remote providers -## 🛠 Development +## Development From the monorepo root: @@ -283,17 +270,17 @@ pnpm --filter @contentrain/mcp typecheck pnpm exec oxlint packages/mcp/src packages/mcp/tests ``` -## 🔗 Related Packages +## Related Packages - `contentrain` — CLI and local review tooling - `@contentrain/query` — generated runtime query SDK - `@contentrain/rules` — IDE/agent rules and prompts - `@contentrain/types` — shared schema and model types -## 📚 Documentation +## Documentation Full documentation at **[ai.contentrain.io/packages/mcp](https://ai.contentrain.io/packages/mcp)**. -## 📄 License +## License MIT diff --git a/packages/mcp/package.json b/packages/mcp/package.json index 0b099be..fd2bb38 100644 --- a/packages/mcp/package.json +++ b/packages/mcp/package.json @@ -116,6 +116,10 @@ "types": "./dist/git/branch-lifecycle.d.mts", "import": "./dist/git/branch-lifecycle.mjs" }, + "./tools/annotations": { + "types": "./dist/tools/annotations.d.mts", + "import": "./dist/tools/annotations.mjs" + }, "./templates": { "types": "./dist/templates/index.d.mts", "import": "./dist/templates/index.mjs" @@ -139,8 +143,8 @@ "dist" ], "scripts": { - "build": "tsdown src/index.ts src/server.ts src/core/config.ts src/core/context.ts src/core/model-manager.ts src/core/content-manager.ts src/core/meta-manager.ts src/core/validator/index.ts src/core/scanner.ts src/core/scan-config.ts src/core/doctor.ts src/core/graph-builder.ts src/core/apply-manager.ts src/util/detect.ts src/util/fs.ts src/util/id.ts src/git/transaction.ts src/git/branch-lifecycle.ts src/templates/index.ts src/core/contracts/index.ts src/core/ops/index.ts src/core/overlay-reader.ts src/providers/local/index.ts src/providers/github/index.ts src/providers/gitlab/index.ts src/server/http/index.ts --format esm --dts --external typescript", - "dev": "tsdown src/index.ts src/server.ts src/core/config.ts src/core/context.ts src/core/model-manager.ts src/core/content-manager.ts src/core/meta-manager.ts src/core/validator/index.ts src/core/scanner.ts src/core/scan-config.ts src/core/doctor.ts src/core/graph-builder.ts src/core/apply-manager.ts src/util/detect.ts src/util/fs.ts src/util/id.ts src/git/transaction.ts src/git/branch-lifecycle.ts src/templates/index.ts src/core/contracts/index.ts src/core/ops/index.ts src/core/overlay-reader.ts src/providers/local/index.ts src/providers/github/index.ts src/providers/gitlab/index.ts src/server/http/index.ts --format esm --dts --external typescript --watch", + "build": "tsdown src/index.ts src/server.ts src/core/config.ts src/core/context.ts src/core/model-manager.ts src/core/content-manager.ts src/core/meta-manager.ts src/core/validator/index.ts src/core/scanner.ts src/core/scan-config.ts src/core/doctor.ts src/core/graph-builder.ts src/core/apply-manager.ts src/util/detect.ts src/util/fs.ts src/util/id.ts src/git/transaction.ts src/git/branch-lifecycle.ts src/tools/annotations.ts src/templates/index.ts src/core/contracts/index.ts src/core/ops/index.ts src/core/overlay-reader.ts src/providers/local/index.ts src/providers/github/index.ts src/providers/gitlab/index.ts src/server/http/index.ts --format esm --dts --external typescript", + "dev": "tsdown src/index.ts src/server.ts src/core/config.ts src/core/context.ts src/core/model-manager.ts src/core/content-manager.ts src/core/meta-manager.ts src/core/validator/index.ts src/core/scanner.ts src/core/scan-config.ts src/core/doctor.ts src/core/graph-builder.ts src/core/apply-manager.ts src/util/detect.ts src/util/fs.ts src/util/id.ts src/git/transaction.ts src/git/branch-lifecycle.ts src/tools/annotations.ts src/templates/index.ts src/core/contracts/index.ts src/core/ops/index.ts src/core/overlay-reader.ts src/providers/local/index.ts src/providers/github/index.ts src/providers/gitlab/index.ts src/server/http/index.ts --format esm --dts --external typescript --watch", "test": "vitest run", "typecheck": "tsc --noEmit", "clean": "rm -rf dist" diff --git a/packages/mcp/src/tools/annotations.ts b/packages/mcp/src/tools/annotations.ts index b148bad..b6afb04 100644 --- a/packages/mcp/src/tools/annotations.ts +++ b/packages/mcp/src/tools/annotations.ts @@ -3,6 +3,11 @@ import type { ToolAnnotations } from '@modelcontextprotocol/sdk/types.js' /** * Centralized tool annotations registry. * MCP clients use these hints to distinguish read-only vs. write vs. destructive tools. + * + * Also serves as the **single source of truth for the tool name list**. Consumers + * that need to enumerate every registered tool (e.g. parity tests in + * `@contentrain/rules` / `@contentrain/skills`) should import `TOOL_NAMES` below + * rather than hardcoding the list. */ export const TOOL_ANNOTATIONS: Record = { // ─── Context (read-only) ─── @@ -121,3 +126,12 @@ export const TOOL_ANNOTATIONS: Record = { idempotentHint: false, }, } + +/** + * Canonical list of every registered MCP tool name, derived from the + * single source of truth above. Re-exported here with a stable name so + * parity tests in sibling packages (`@contentrain/rules`, + * `@contentrain/skills`) can assert against it without depending on + * `TOOL_ANNOTATIONS` internals. + */ +export const TOOL_NAMES: readonly string[] = Object.freeze(Object.keys(TOOL_ANNOTATIONS)) diff --git a/packages/rules/README.md b/packages/rules/README.md index 5f9e660..8e097c1 100644 --- a/packages/rules/README.md +++ b/packages/rules/README.md @@ -10,15 +10,16 @@ Shared AI-agent rules for Contentrain. Start here: - [2-minute product demo](https://ai.contentrain.io/demo) -- [Rules & skills docs](https://ai.contentrain.io/packages/rules) +- [Rules & skills docs](https://ai.contentrain.io/packages/rules) -This package is the policy layer of the Contentrain ecosystem. It defines how agents should behave when they work with: +This package is the **policy layer** of the Contentrain ecosystem. It defines how agents should behave when they work with: -- Contentrain MCP tools +- Contentrain MCP tools (17 operations) - schema and model design -- content quality -- normalize workflows +- content quality (SEO, accessibility, media, i18n) +- normalize workflows (extraction + reuse) - git-backed review flows +- security guardrails If `@contentrain/mcp` is the deterministic execution layer, `@contentrain/rules` is the behavioral contract. @@ -32,71 +33,100 @@ pnpm add @contentrain/rules ### Essential guardrails -Published under `essential/*`: +Published under `essential/`: -- `contentrain-essentials.md` — compact, always-loaded rules (~86 lines) covering architecture, model kinds, MCP tools, mandatory protocols, and security basics +- `contentrain-essentials.md` — compact, always-loaded rules covering architecture, model kinds, MCP tools, mandatory protocols, git workflow, and security basics. + +### Shared quality rules + +Published under `shared/` — detailed standards per domain: + +- `content-quality.md` — structure, required fields, content completeness +- `seo-rules.md` — meta optimization, keywords, canonical URLs +- `accessibility-rules.md` — alt text, ARIA labels, color contrast +- `media-rules.md` — image optimization, responsive sizing, asset naming +- `schema-rules.md` — model design, field types, relations, inheritance +- `i18n-quality.md` — translation completeness, locale parity +- `security-rules.md` — sensitive data patterns, secret detection, XSS prevention +- `mcp-usage.md` — tool invocation patterns, git workflows, trust levels +- `normalize-rules.md` — extraction and reuse constraints, scope safety +- `workflow-rules.md` — review mode, approval flows, branch lifecycle +- `content-conventions.md` — naming, slug generation, status conventions ### Prompt layers -Published under `prompts/*`: +Published under `prompts/` — mode-specific context the agent loads per task: -- `common.md` -- `generate-mode.md` -- `normalize-mode.md` -- `review-mode.md` +- `common.md` — shared preamble for all agent modes +- `generate-mode.md` — content creation constraints +- `normalize-mode.md` — string extraction and patching workflows +- `review-mode.md` — content validation and change review ### Context bridge -Published under `context/*`: +Published under `context/`: -- `context-bridge.md` +- `context-bridge.md` — how to integrate rules into agent context systems +- `templates/` — framework-specific context JSON for `nuxt`, `next`, `astro`, `sveltekit` ## Public Exports -The package root exports constants that can be used by tooling: +The package root exports constants for tooling: - `FIELD_TYPES` — 27 flat field types -- `MODEL_KINDS` — singleton, collection, document, dictionary -- `MCP_TOOLS` — 15 MCP tool names +- `MODEL_KINDS` — `singleton`, `collection`, `document`, `dictionary` +- `MCP_TOOLS` — 17 MCP tool names (includes `contentrain_merge` and `contentrain_doctor`) - `ESSENTIAL_RULES_FILE` — path to essential guardrails markdown - `STACKS` — supported framework stacks -## Example +## Quick Example ```ts import { MCP_TOOLS, ESSENTIAL_RULES_FILE, FIELD_TYPES } from '@contentrain/rules' -console.log(MCP_TOOLS.includes('contentrain_validate')) -console.log(ESSENTIAL_RULES_FILE) // 'essential/contentrain-essentials.md' -console.log(FIELD_TYPES.length) // 27 +console.log(MCP_TOOLS.length) // 17 +console.log(MCP_TOOLS.includes('contentrain_merge')) // true +console.log(MCP_TOOLS.includes('contentrain_doctor')) // true +console.log(ESSENTIAL_RULES_FILE) // 'essential/contentrain-essentials.md' +console.log(FIELD_TYPES.length) // 27 ``` ## Design Role `@contentrain/rules` exists to keep agent behavior aligned across tools and environments. -It should answer questions like: +Typical questions it answers: + +- What is acceptable content quality? (shared quality rules) +- How should an agent use MCP tools safely? (mcp-usage + tool reference) +- What is the normalize contract? (normalize-rules) +- What workflow and review constraints exist? (workflow-rules) + +Detailed procedures and step-by-step guides live in `@contentrain/skills` (Agent Skills standard format). + +## Parity with `@contentrain/mcp` + +`@contentrain/rules` is kept in lockstep with the MCP tool registry via cross-package parity tests. When a new MCP tool is registered in `@contentrain/mcp`: -- What is acceptable content quality? -- How should an agent use MCP tools? -- What is the normalize contract? -- What workflow and review constraints exist? +- `MCP_TOOLS` must include it (otherwise `tests/mcp-parity.test.ts` fails) +- the essentials document must mention it +- the skills reference must have a `### ` section -Detailed reference material and step-by-step procedures live in `@contentrain/skills` (Agent Skills standard format). +When MCP's branch-naming convention changes (e.g. `contentrain/*` → `cr/*`), the rules prose must follow — the parity test scans the rules for the legacy prefix and fails if it reappears. ## Relationship To Other Packages - `@contentrain/mcp` enforces file, validation, and git behavior - `@contentrain/skills` provides Agent Skills with progressive disclosure (SKILL.md + references/) -- `contentrain` exposes CLI and serve UX +- `contentrain` (CLI) installs rules + skills into the IDE during `contentrain init` - `@contentrain/query` is the generated runtime consumption layer Rule of thumb: -- `rules` = essential guardrails (always loaded, ~86 lines) -- `skills` = detailed procedures and reference docs (on-demand) +- `rules` = policy layer (quality standards, constraints, essentials) +- `skills` = procedural layer (workflows, detailed reference docs) -See [`AGENTS.md`](../../AGENTS.md) at the repo root for agent-level project guidance. +See [`AGENTS.md`](../../AGENTS.md) at the repo root for project-level agent guidance. ## Build diff --git a/packages/rules/essential/contentrain-essentials.md b/packages/rules/essential/contentrain-essentials.md index ac6c77d..b0a0e40 100644 --- a/packages/rules/essential/contentrain-essentials.md +++ b/packages/rules/essential/contentrain-essentials.md @@ -54,6 +54,7 @@ MCP is **deterministic infrastructure**. The agent (you) is the **intelligence l | `contentrain_submit` | Push branches to remote | | `contentrain_merge` | Merge a review-mode branch into contentrain locally | | `contentrain_bulk` | Batch operations (copy_locale/update_status/delete_entries) | +| `contentrain_doctor` | Project health report (env + structure + orphan content + branch pressure + SDK freshness) | ## Mandatory Protocols @@ -68,7 +69,7 @@ MCP is **deterministic infrastructure**. The agent (you) is the **intelligence l - A dedicated `contentrain` branch is the single source of truth for content state, created at init - Every write operation creates a temporary worktree on the `contentrain` branch automatically -- Feature branches (`contentrain/{operation}/{model}/{locale}/{timestamp}`) are created from `contentrain` for each operation +- Feature branches (`cr/{operation}/{model}/{locale}/{timestamp}`) are created from `contentrain` for each operation - **auto-merge** mode: feature branch merges into `contentrain`, then `contentrain` advances baseBranch via update-ref (fast-forward), then `.contentrain/` files are selectively synced to the developer's working tree - **review** mode: feature branch pushed to remote for team review - Developer's working tree is never mutated during MCP git operations (no stash, no checkout, no merge on the developer's tree) @@ -76,7 +77,7 @@ MCP is **deterministic infrastructure**. The agent (you) is the **intelligence l - The `contentrain` branch is protected from deletion - context.json is committed together with content changes, not as a separate commit - Never create branches manually, never commit directly to main or the `contentrain` branch -- 50+ active branches = warning, 80+ = blocked +- 50+ active `cr/*` branches = warning, 80+ = blocked ## CLI Serve — Review & Approval diff --git a/packages/rules/package.json b/packages/rules/package.json index 8def6f5..047f5a9 100644 --- a/packages/rules/package.json +++ b/packages/rules/package.json @@ -56,6 +56,7 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { + "@contentrain/mcp": "workspace:*", "@types/node": "^22.0.0", "tsdown": "^0.21.0", "typescript": "^5.7.0", diff --git a/packages/rules/prompts/normalize-mode.md b/packages/rules/prompts/normalize-mode.md index 1b8a762..f204d03 100644 --- a/packages/rules/prompts/normalize-mode.md +++ b/packages/rules/prompts/normalize-mode.md @@ -12,7 +12,7 @@ This mode converts a codebase with hardcoded strings into a Contentrain-managed |--------|---------------------|----------------| | Purpose | Pull content from source code into `.contentrain/` | Patch source files to reference extracted content | | Source files modified | No | Yes | -| Branch pattern | `contentrain/normalize/extract/{domain}/{timestamp}` | `contentrain/normalize/reuse/{model}/{locale}/{timestamp}` | +| Branch pattern | `cr/normalize/extract/{domain}/{timestamp}` | `cr/normalize/reuse/{model}/{locale}/{timestamp}` | | Prerequisite | Initialized `.contentrain/` | Completed extraction (content exists) | | Workflow mode | Always `review` | Always `review` | | Standalone value | Yes — content is manageable in Studio immediately | Depends on Phase 1 | diff --git a/packages/rules/prompts/review-mode.md b/packages/rules/prompts/review-mode.md index f3f69d5..b31a33d 100644 --- a/packages/rules/prompts/review-mode.md +++ b/packages/rules/prompts/review-mode.md @@ -2,14 +2,14 @@ > **Prerequisites:** Read `prompts/common.md` first. All shared rules apply. -This mode is for reviewing content changes on pending `contentrain/*` branches before they are merged. You act as a content quality reviewer, applying all Contentrain rules systematically. +This mode is for reviewing content changes on pending `cr/*` branches before they are merged. You act as a content quality reviewer, applying all Contentrain rules systematically. --- ## Pipeline ``` -Step 1: List open contentrain/* branches +Step 1: List open cr/* branches Step 2: Show diffs for selected branch Step 3: Apply review checklist Step 4: Recommend action @@ -19,19 +19,19 @@ Step 4: Recommend action ## Step 1: List Pending Branches -Call `contentrain_status` to see pending changes and open branches. Identify branches with the `contentrain/` prefix that are awaiting review. +Call `contentrain_status` to see pending changes and open branches. Identify branches with the `cr/` prefix that are awaiting review. Branch naming convention: ``` -contentrain/{operation}/{model}/{locale}/{timestamp} +cr/{operation}/{model}/{locale}/{timestamp} ``` Common branch types: -- `contentrain/content/...` — content updates -- `contentrain/model/...` — model changes -- `contentrain/normalize/extract/...` — normalize extraction -- `contentrain/normalize/reuse/...` — normalize reuse (source patching) -- `contentrain/new/scaffold-...` — scaffold operations +- `cr/content/...` — content updates +- `cr/model/...` — model changes +- `cr/normalize/extract/...` — normalize extraction +- `cr/normalize/reuse/...` — normalize reuse (source patching) +- `cr/new/scaffold-...` — scaffold operations --- diff --git a/packages/rules/shared/workflow-rules.md b/packages/rules/shared/workflow-rules.md index 7b6fa53..0cfd1f1 100644 --- a/packages/rules/shared/workflow-rules.md +++ b/packages/rules/shared/workflow-rules.md @@ -43,7 +43,7 @@ Contentrain supports two workflow modes, configured in `.contentrain/config.json All Contentrain branches follow a strict naming pattern: ``` -contentrain/{operation}/{model}/{locale}/{timestamp} +cr/{operation}/{model}/{locale}/{timestamp} ``` ### Examples diff --git a/packages/rules/src/index.ts b/packages/rules/src/index.ts index 6887f7d..77dfbf9 100644 --- a/packages/rules/src/index.ts +++ b/packages/rules/src/index.ts @@ -23,7 +23,7 @@ export type FieldType = (typeof FIELD_TYPES)[number] export const MODEL_KINDS = ['singleton', 'collection', 'document', 'dictionary'] as const export type ModelKind = (typeof MODEL_KINDS)[number] -// ─── MCP Tools (15 tools) ─── +// ─── MCP Tools (17 tools) ─── export const MCP_TOOLS = [ 'contentrain_status', 'contentrain_describe', 'contentrain_describe_format', @@ -32,7 +32,9 @@ export const MCP_TOOLS = [ 'contentrain_content_save', 'contentrain_content_delete', 'contentrain_content_list', 'contentrain_scan', 'contentrain_apply', 'contentrain_validate', 'contentrain_submit', + 'contentrain_merge', 'contentrain_bulk', + 'contentrain_doctor', ] as const export type McpTool = (typeof MCP_TOOLS)[number] diff --git a/packages/rules/tests/mcp-parity.test.ts b/packages/rules/tests/mcp-parity.test.ts new file mode 100644 index 0000000..7d7828e --- /dev/null +++ b/packages/rules/tests/mcp-parity.test.ts @@ -0,0 +1,75 @@ +import { describe, it, expect } from 'vitest' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { TOOL_NAMES } from '@contentrain/mcp/tools/annotations' +import { buildBranchName } from '@contentrain/mcp/git/transaction' +import { MCP_TOOLS, ESSENTIAL_RULES_FILE } from '../src/index.js' + +/** + * Cross-package parity tests. + * + * `@contentrain/rules` publishes a public catalog of tools and branch + * conventions that agents rely on. `@contentrain/mcp` is the runtime + * authority. Without this file, the two can (and historically did) drift: + * the rules catalog sat at 15 tools while MCP advertised 16; the + * essential rules kept teaching the legacy `contentrain/*` branch + * namespace after MCP switched to `cr/*`. + * + * The tests below fail loudly whenever either side moves without the + * other. Fix by aligning — not by muting the test. + */ + +const PKG_ROOT = join(import.meta.dirname, '..') + +describe('MCP parity — tool registry', () => { + it('MCP_TOOLS matches the MCP annotations registry exactly', () => { + const rulesSet = new Set(MCP_TOOLS) + const mcpSet = new Set(TOOL_NAMES) + + const missingFromRules = [...mcpSet].filter(t => !rulesSet.has(t)) + const missingFromMcp = [...rulesSet].filter(t => !mcpSet.has(t)) + + expect(missingFromRules, 'tools registered in @contentrain/mcp but missing from @contentrain/rules MCP_TOOLS').toEqual([]) + expect(missingFromMcp, 'tools in @contentrain/rules MCP_TOOLS but not registered in @contentrain/mcp').toEqual([]) + expect(MCP_TOOLS.length).toBe(TOOL_NAMES.length) + }) + + it('essential guardrails document every MCP tool', () => { + const content = readFileSync(join(PKG_ROOT, ESSENTIAL_RULES_FILE), 'utf-8') + for (const tool of TOOL_NAMES) { + expect(content, `essential rules do not mention ${tool}`).toContain(tool) + } + }) +}) + +describe('MCP parity — branch naming', () => { + it('buildBranchName() emits the `cr/` prefix that rules + skills document', () => { + const samples = [ + buildBranchName('content', 'blog-post', 'en'), + buildBranchName('model', 'team-member'), + buildBranchName('normalize/extract', 'marketing'), + buildBranchName('new', 'scaffold-landing', 'en'), + ] + for (const branch of samples) { + expect(branch, `branch name should start with "cr/": ${branch}`).toMatch(/^cr\//u) + } + }) + + it('rules docs do not reference the legacy `contentrain/{operation}/` branch prefix', () => { + // The `.contentrain/` directory path is correct — only the branch + // prefix is stale. Filter accordingly so the test doesn't + // false-positive on real filesystem paths. + const filesToScan = [ + 'essential/contentrain-essentials.md', + 'prompts/review-mode.md', + 'prompts/normalize-mode.md', + 'shared/workflow-rules.md', + ] + const legacyPattern = /(^|[^.])contentrain\/(content|model|normalize|new|fix|review)\b/gmu + for (const rel of filesToScan) { + const content = readFileSync(join(PKG_ROOT, rel), 'utf-8') + const matches = [...content.matchAll(legacyPattern)] + expect(matches.length, `legacy "contentrain//" branch prefix in ${rel}: ${matches.map(m => m[0]).join(', ')}`).toBe(0) + } + }) +}) diff --git a/packages/rules/tests/validate-rules.test.ts b/packages/rules/tests/validate-rules.test.ts index 276eb35..bea3cc7 100644 --- a/packages/rules/tests/validate-rules.test.ts +++ b/packages/rules/tests/validate-rules.test.ts @@ -25,7 +25,7 @@ describe('essential rules', () => { describe('constants', () => { it('FIELD_TYPES has 27 entries', () => { expect(FIELD_TYPES).toHaveLength(27) }) it('MODEL_KINDS has 4 entries', () => { expect(MODEL_KINDS).toHaveLength(4) }) - it('MCP_TOOLS has 15 entries', () => { expect(MCP_TOOLS).toHaveLength(15) }) + it('MCP_TOOLS has 17 entries', () => { expect(MCP_TOOLS).toHaveLength(17) }) it('all MCP tools match pattern', () => { for (const t of MCP_TOOLS) expect(t).toMatch(/^contentrain_/) }) diff --git a/packages/sdk/js/README.md b/packages/sdk/js/README.md index 7e62d1b..633fe95 100644 --- a/packages/sdk/js/README.md +++ b/packages/sdk/js/README.md @@ -341,24 +341,31 @@ const client = await clientModule.init() const hero = client.singleton('hero').get() ``` -## 🛠 CLI +## 🛠 Generation Commands -Generate once: +**Via the `contentrain` CLI (recommended for most users):** ```bash -npx contentrain-query generate +contentrain generate # Generate once +contentrain generate --watch # Regenerate on model/content changes +contentrain generate --json # Machine-readable JSON for CI ``` -Generate in watch mode: +**Via `contentrain-query` (programmatic / build tool flows):** ```bash +npx contentrain-query generate npx contentrain-query generate --watch +npx contentrain-query generate --root /path/to/project ``` -Use a different project root: +Or from TypeScript: -```bash -npx contentrain-query generate --root /path/to/project +```ts +import { generate } from '@contentrain/query/generate' + +const result = await generate({ projectRoot: process.cwd() }) +console.log(result.generatedFiles.length) ``` ## 📤 Package Exports diff --git a/packages/skills/README.md b/packages/skills/README.md index 0476429..d070005 100644 --- a/packages/skills/README.md +++ b/packages/skills/README.md @@ -10,10 +10,10 @@ Workflow skills and framework guides for Contentrain-aware AI agents. Start here: - [2-minute product demo](https://ai.contentrain.io/demo) -- [Rules & skills docs](https://ai.contentrain.io/packages/rules) +- [Rules & skills docs](https://ai.contentrain.io/packages/rules) - [Framework integration guide](https://ai.contentrain.io/guides/frameworks) -This package follows the [Agent Skills standard](https://agentskills.io) for progressive disclosure: each skill has a `SKILL.md` (loaded on activation) and optional `references/` (loaded on demand). +This package follows the [Agent Skills standard](https://agentskills.io) for **progressive disclosure**: each skill has a `SKILL.md` (loaded on activation) and optional `references/*.md` (loaded on demand). ## Install @@ -45,54 +45,71 @@ Works with Claude Code, Cursor, Windsurf, GitHub Copilot, OpenAI Codex, Gemini C ### Agent Skills (standard format) -Published under `skills/`: +Published under `skills/` — 15 production skills: | Skill | Description | |-------|-------------| -| `contentrain` | Core architecture, MCP tools, content formats | -| `contentrain-normalize` | Two-phase normalize (extract + reuse) | -| `contentrain-quality` | Content quality, SEO, accessibility, media | -| `contentrain-sdk` | @contentrain/query SDK usage (local + CDN) | -| `contentrain-content` | Content CRUD operations | -| `contentrain-model` | Model creation/update | -| `contentrain-init` | Project initialization | -| `contentrain-bulk` | Batch operations | -| `contentrain-validate-fix` | Validation and auto-fix | -| `contentrain-review` | Content quality review | -| `contentrain-translate` | Multi-locale translation | -| `contentrain-generate` | SDK client generation | -| `contentrain-serve` | Local review/normalize UI | -| `contentrain-diff` | Branch content diffs | -| `contentrain-doctor` | Project health diagnostics | +| `contentrain` | Core architecture, MCP tools, content formats, i18n, security | +| `contentrain-normalize` | Two-phase normalize (extract hardcoded strings + patch source files) | +| `contentrain-quality` | Content quality, SEO, accessibility, media optimization | +| `contentrain-sdk` | Query SDK usage (#contentrain imports, QueryBuilder, type-safe access) | +| `contentrain-content` | Create and manage content entries for existing models | +| `contentrain-model` | Design and save model definitions | +| `contentrain-init` | Initialize a new Contentrain project | +| `contentrain-bulk` | Batch operations on content entries | +| `contentrain-validate-fix` | Validate content and auto-fix structural issues | +| `contentrain-review` | Review content changes before publishing | +| `contentrain-translate` | Multi-locale translation workflows | +| `contentrain-generate` | Generate the typed SDK client from models | +| `contentrain-serve` | Start the local review and normalize UI | +| `contentrain-diff` | View content diffs between branches | +| `contentrain-doctor` | Diagnose project health issues | Each skill directory contains: + ``` skills/{name}/ -├── SKILL.md # Instructions (< 500 lines) +├── SKILL.md # Instructions (< 500 lines, quick reference) └── references/ # Detailed docs (loaded on demand) - └── *.md + └── *.md # Deep dives: architecture, patterns, examples ``` +Example references: `contentrain/references/mcp-tools.md`, `contentrain-normalize/references/extraction.md`, `contentrain-quality/references/seo.md`. + ### Workflow skills (backward compat) -Published under `workflows/*` — flat markdown files from previous versions. Still functional. +Published under `workflows/` — flat markdown files retained for compatibility: + +- `contentrain-init.md`, `contentrain-model.md`, `contentrain-content.md`, `contentrain-bulk.md` +- `contentrain-normalize.md`, `contentrain-validate-fix.md`, `contentrain-review.md` +- `contentrain-diff.md`, `contentrain-doctor.md`, `contentrain-serve.md` +- `contentrain-generate.md`, `contentrain-translate.md` + +Still fully functional; new projects should prefer the `skills/` structure. ### Framework guides -Published under `frameworks/*`: +Published under `frameworks/` — per-framework integration patterns: -- `nuxt.md`, `next.md`, `astro.md`, `sveltekit.md`, `vue.md`, `react.md`, `expo.md`, `react-native.md`, `node.md` +- `nuxt.md`, `next.md`, `astro.md`, `sveltekit.md` (meta frameworks) +- `react.md`, `vue.md` (UI libraries) +- `expo.md`, `react-native.md` (mobile) +- `node.md` (backend) ## Public Exports ```ts import { AGENT_SKILLS, WORKFLOW_SKILLS, FRAMEWORK_GUIDES } from '@contentrain/skills' -// Agent Skills catalog (name + description for Tier 1 discovery) -console.log(AGENT_SKILLS) +// Discover skills: name + description for agent activation +AGENT_SKILLS.forEach(({ name, description }) => { + console.log(`${name}: ${description}`) +}) + +// Backward compat: flat workflow list +console.log(WORKFLOW_SKILLS.length) // 12 -// Backward compat -console.log(WORKFLOW_SKILLS) +// Framework discovery console.log(FRAMEWORK_GUIDES) ``` @@ -100,15 +117,24 @@ console.log(FRAMEWORK_GUIDES) | Tier | What's Loaded | When | Token Cost | |------|--------------|------|------------| -| 1. Catalog | `name` + `description` | Session start | ~50 tokens/skill | +| 1. Catalog | `name` + `description` (AGENT_SKILLS) | Session start | ~50 tokens/skill | | 2. Instructions | Full `SKILL.md` body | Skill activated | < 5000 tokens | -| 3. References | `references/*.md` | Agent needs detail | Varies | +| 3. References | `references/*.md` files | Agent needs detail | Varies (50-500 tokens/file) | + +This reduces always-loaded context from thousands of lines to just the essentials plus catalog. + +## Parity with `@contentrain/mcp` + +`@contentrain/skills` is kept in lockstep with the MCP tool registry via cross-package parity tests (`tests/mcp-parity.test.ts`): + +- `skills/contentrain/references/mcp-tools.md` must have an `### ` heading for every tool in the MCP `TOOL_NAMES` registry (currently 17). +- Key skills (normalize, translate) must not reference legacy `contentrain/{operation}/...` branch prefixes — MCP now emits `cr/*`. -This reduces always-loaded context from ~4,700 lines to ~86 lines (essential guardrails only). +When MCP's surface changes, these tests fail until the skill docs catch up. ## IDE Support -Skills are installed by `contentrain init` for detected IDEs: +Skills are installed by `contentrain init` (and re-applied with `contentrain skills --update`) for detected IDEs: | IDE | Rules Dir | Skills Dir | |-----|-----------|------------| diff --git a/packages/skills/package.json b/packages/skills/package.json index 5ad86f8..833a3b7 100644 --- a/packages/skills/package.json +++ b/packages/skills/package.json @@ -62,6 +62,7 @@ "typecheck": "tsc --noEmit" }, "devDependencies": { + "@contentrain/mcp": "workspace:*", "@types/node": "^22.0.0", "tsdown": "^0.21.0", "typescript": "^5.7.0", diff --git a/packages/skills/skills/contentrain-normalize/SKILL.md b/packages/skills/skills/contentrain-normalize/SKILL.md index 391bec7..870b72d 100644 --- a/packages/skills/skills/contentrain-normalize/SKILL.md +++ b/packages/skills/skills/contentrain-normalize/SKILL.md @@ -60,7 +60,7 @@ branch is pushed. | Purpose | Pull content from source to `.contentrain/` | Patch source files with content references | | Scope | Full project scan | Per model or per domain | | Source files modified | No | Yes | -| Branch pattern | `contentrain/normalize/extract/{domain}/{timestamp}` | `contentrain/normalize/reuse/{model}/{locale}/{timestamp}` | +| Branch pattern | `cr/normalize/extract/{domain}/{timestamp}` | `cr/normalize/reuse/{model}/{locale}/{timestamp}` | | Prerequisite | Initialized `.contentrain/` | Completed extraction (content exists in `.contentrain/`) | | Workflow mode | Always `review` | Always `review` | | Standalone value | Yes -- content is manageable in Studio immediately | Depends on Phase 1 | @@ -133,7 +133,7 @@ Call `contentrain_apply(mode: "extract", dry_run: true)` to generate a preview. ### 6. Execute Extraction -After user approval, call `contentrain_apply(mode: "extract", dry_run: false)`. This creates model definitions and content files in `.contentrain/` on a `contentrain/normalize/extract/{timestamp}` branch. Source files are NOT modified. +After user approval, call `contentrain_apply(mode: "extract", dry_run: false)`. This creates model definitions and content files in `.contentrain/` on a `cr/normalize/extract/{timestamp}` branch. Source files are NOT modified. ### 7. Validate and Submit @@ -207,7 +207,7 @@ Call `contentrain_apply(mode: "reuse", scope: { model: "" }, patches: ### 4. Execute Reuse -After user confirmation, call `contentrain_apply(mode: "reuse", scope: { model: "" }, patches: [...], dry_run: false)`. This patches source files and creates a `contentrain/normalize/reuse/{model}/{timestamp}` branch. +After user confirmation, call `contentrain_apply(mode: "reuse", scope: { model: "" }, patches: [...], dry_run: false)`. This patches source files and creates a `cr/normalize/reuse/{model}/{timestamp}` branch. ### 5. Validate and Submit diff --git a/packages/skills/skills/contentrain-normalize/references/extraction.md b/packages/skills/skills/contentrain-normalize/references/extraction.md index 228118c..02c9bfd 100644 --- a/packages/skills/skills/contentrain-normalize/references/extraction.md +++ b/packages/skills/skills/contentrain-normalize/references/extraction.md @@ -113,7 +113,7 @@ Returns a preview of what will be created in `.contentrain/` without making chan contentrain_apply(mode: "extract", dry_run: false) ``` -Creates model definitions and content files in `.contentrain/` on a `contentrain/normalize/extract/{timestamp}` branch. `dry_run` defaults to `true`, so you MUST explicitly set `dry_run: false` to execute. +Creates model definitions and content files in `.contentrain/` on a `cr/normalize/extract/{timestamp}` branch. `dry_run` defaults to `true`, so you MUST explicitly set `dry_run: false` to execute. ### 7. Validate and Submit diff --git a/packages/skills/skills/contentrain-normalize/references/reuse.md b/packages/skills/skills/contentrain-normalize/references/reuse.md index 6a1861e..c59538f 100644 --- a/packages/skills/skills/contentrain-normalize/references/reuse.md +++ b/packages/skills/skills/contentrain-normalize/references/reuse.md @@ -42,7 +42,7 @@ Review the dry-run output: contentrain_apply(mode: "reuse", scope: { model: "" }, patches: [...], dry_run: false) ``` -`dry_run` defaults to `true`, so you MUST explicitly set `dry_run: false` to execute. This patches source files and creates a `contentrain/normalize/reuse/{model}/{timestamp}` branch. +`dry_run` defaults to `true`, so you MUST explicitly set `dry_run: false` to execute. This patches source files and creates a `cr/normalize/reuse/{model}/{timestamp}` branch. ### 5. Validate and Submit diff --git a/packages/skills/skills/contentrain-translate/SKILL.md b/packages/skills/skills/contentrain-translate/SKILL.md index 6d78590..8eed9b1 100644 --- a/packages/skills/skills/contentrain-translate/SKILL.md +++ b/packages/skills/skills/contentrain-translate/SKILL.md @@ -170,7 +170,7 @@ If validation fails, fix issues and re-save. Call `contentrain_submit` to commit the translations: -- Branch: `contentrain/content/{model}/{targetLocale}/{timestamp}`. +- Branch: `cr/content/{model}/{targetLocale}/{timestamp}`. - Each locale can be submitted independently. ### 11. Final Summary diff --git a/packages/skills/skills/contentrain/SKILL.md b/packages/skills/skills/contentrain/SKILL.md index 681573d..6791441 100644 --- a/packages/skills/skills/contentrain/SKILL.md +++ b/packages/skills/skills/contentrain/SKILL.md @@ -16,7 +16,7 @@ Contentrain consists of 6 packages that work together: | Package | Role | How agent uses it | |---|---|---| -| @contentrain/mcp | 16 MCP tools (scan, apply, validate, merge...) | MCP tool calls | +| @contentrain/mcp | 17 MCP tools (scan, apply, validate, merge, doctor...) | MCP tool calls | | contentrain (CLI) | init, serve, generate, doctor, diff, status | Shell commands | | @contentrain/types | Shared TypeScript contracts | Type safety | | @contentrain/query | Generated SDK client (Prisma-pattern) | `import from '#contentrain'` | diff --git a/packages/skills/skills/contentrain/references/mcp-pipelines.md b/packages/skills/skills/contentrain/references/mcp-pipelines.md index a833675..6c04b2a 100644 --- a/packages/skills/skills/contentrain/references/mcp-pipelines.md +++ b/packages/skills/skills/contentrain/references/mcp-pipelines.md @@ -147,7 +147,7 @@ contentrain_submit # Push (always review mode) - A dedicated `contentrain` branch is the single source of truth for content state, created at init and protected from deletion - Every write operation creates a temporary worktree on a new feature branch forked from `contentrain` -- Branch naming: `contentrain/{operation}/{model}/{timestamp}` (locale included when applicable) +- Branch naming: `cr/{operation}/{model}/{timestamp}` (locale included when applicable) - Do not create branches manually. MCP handles Git transactions - Developer's working tree is never mutated during MCP operations (no stash, no checkout, no merge on the developer's tree) - context.json is committed together with content changes, not as a separate commit diff --git a/packages/skills/skills/contentrain/references/mcp-tools.md b/packages/skills/skills/contentrain/references/mcp-tools.md index 5f2b2bb..c300b98 100644 --- a/packages/skills/skills/contentrain/references/mcp-tools.md +++ b/packages/skills/skills/contentrain/references/mcp-tools.md @@ -269,13 +269,35 @@ Validate project content against model schemas. ### contentrain_submit -Push contentrain/* branches to remote. +Push `cr/*` feature branches to remote. | Parameter | Type | Required | Description | |-----------|------|----------|-------------| -| `branches` | string[] | No | Specific branches to push (omit for all contentrain/* branches) | +| `branches` | string[] | No | Specific branches to push (omit for all `cr/*` branches) | | `message` | string | No | Optional message for the push operation | +### contentrain_merge + +Merge a single review-mode `cr/*` branch into the content-tracking `contentrain` branch and advance the base branch via `update-ref`. Runs the worktree transaction with selective sync — dirty files in the developer's working tree are preserved rather than overwritten. + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `branch` | string | Yes | Feature branch name (must start with `cr/`) | + +Returns `{ action, commit, sync }` — `sync.skipped[]` lists files the selective sync skipped because the developer has uncommitted changes. The CLI surfaces this as a warning. + +## Doctor Tools + +### contentrain_doctor + +Structured project health report: git install, Node version, `.contentrain/` structure, model parse, orphan content, pending branch pressure, SDK client freshness. Read-only. Local-filesystem only (`localWorktree` capability — unavailable over remote providers). + +| Parameter | Type | Required | Description | +|-----------|------|----------|-------------| +| `usage` | boolean | No | Run the heavier usage-analysis branch (unused content keys, duplicate dictionary values, locale coverage). Default `false` | + +Returns `{ checks[], summary: { total, passed, failed, warnings }, usage? }`. Each check carries `name`, `pass`, `detail`, optional `severity: 'error' | 'warning' | 'info'`. + ## Bulk Tools ### contentrain_bulk diff --git a/packages/skills/skills/contentrain/references/workflow.md b/packages/skills/skills/contentrain/references/workflow.md index b619728..b5931a7 100644 --- a/packages/skills/skills/contentrain/references/workflow.md +++ b/packages/skills/skills/contentrain/references/workflow.md @@ -45,21 +45,21 @@ Contentrain supports two workflow modes, configured in `.contentrain/config.json ## 2. Branch Naming Convention -All Contentrain branches follow a strict naming pattern: +All Contentrain feature branches follow a strict naming pattern: ``` -contentrain/{operation}/{model}/{locale}/{timestamp} +cr/{operation}/{model}/{locale}/{timestamp}-{suffix} ``` ### Examples | Scenario | Branch Name | |----------|-------------| -| Content update | `contentrain/content/blog-post/en/1710300000` | -| Model creation | `contentrain/model/team-member/1710300000` | -| Normalize extraction | `contentrain/normalize/extract/blog/1710300000` | -| Normalize reuse | `contentrain/normalize/reuse/marketing-hero/en/1710300000` | -| Scaffold | `contentrain/new/scaffold-landing/en/1710300000` | +| Content update | `cr/content/blog-post/en/1710300000-a1b2` | +| Model creation | `cr/model/team-member/1710300000-c3d4` | +| Normalize extraction | `cr/normalize/extract/blog/1710300000-e5f6` | +| Normalize reuse | `cr/normalize/reuse/marketing-hero/en/1710300000-0789` | +| Scaffold | `cr/new/scaffold-landing/en/1710300000-1234` | ### Rules diff --git a/packages/skills/tests/mcp-parity.test.ts b/packages/skills/tests/mcp-parity.test.ts new file mode 100644 index 0000000..d6f45b0 --- /dev/null +++ b/packages/skills/tests/mcp-parity.test.ts @@ -0,0 +1,59 @@ +import { describe, it, expect } from 'vitest' +import { readFileSync } from 'node:fs' +import { join } from 'node:path' +import { TOOL_NAMES } from '@contentrain/mcp/tools/annotations' + +/** + * Cross-package parity tests. + * + * `@contentrain/skills` ships the canonical MCP tool reference and the + * workflow / normalize guides that agents load on demand. `@contentrain/mcp` + * is the runtime authority. Without these tests, drift creeps in: for a + * while, the reference jumped from `contentrain_submit` straight to + * `contentrain_bulk` with no `contentrain_merge` section, and normalize + * SKILL.md taught the legacy `contentrain/normalize/*` branch pattern + * after MCP switched to `cr/*`. + * + * The tests below fail loudly whenever either side moves without the + * other. Fix by aligning — not by muting the test. + */ + +const PKG_ROOT = join(import.meta.dirname, '..') +const TOOL_REF = join(PKG_ROOT, 'skills', 'contentrain', 'references', 'mcp-tools.md') + +describe('MCP parity — tool reference coverage', () => { + it('references/mcp-tools.md has a section for every MCP tool', () => { + const content = readFileSync(TOOL_REF, 'utf-8') + const missing: string[] = [] + for (const tool of TOOL_NAMES) { + const header = new RegExp(`^###\\s+${tool}\\b`, 'mu') + if (!header.test(content)) missing.push(tool) + } + expect(missing, `missing heading "### " in references/mcp-tools.md for: ${missing.join(', ')}`).toEqual([]) + }) +}) + +describe('MCP parity — branch naming', () => { + it('skills docs do not reference the legacy `contentrain//` branch prefix', () => { + // The `.contentrain/` directory path is correct — only the branch + // prefix is stale. Filter accordingly so we don't false-positive on + // real filesystem paths. + const filesToScan = [ + 'skills/contentrain/references/mcp-pipelines.md', + 'skills/contentrain/references/workflow.md', + 'skills/contentrain/references/mcp-tools.md', + 'skills/contentrain-normalize/SKILL.md', + 'skills/contentrain-normalize/references/extraction.md', + 'skills/contentrain-normalize/references/reuse.md', + 'skills/contentrain-translate/SKILL.md', + ] + const legacyPattern = /(^|[^.])contentrain\/(content|model|normalize|new|fix|review)\b/gmu + const violations: Record = {} + for (const rel of filesToScan) { + const content = readFileSync(join(PKG_ROOT, rel), 'utf-8') + const matches = [...content.matchAll(legacyPattern)].map(m => m[0].trim()) + if (matches.length > 0) violations[rel] = matches + } + expect(violations, `legacy branch prefix found: ${JSON.stringify(violations, null, 2)}`).toEqual({}) + }) +}) diff --git a/packages/types/README.md b/packages/types/README.md index e3eb8d0..82f136e 100644 --- a/packages/types/README.md +++ b/packages/types/README.md @@ -18,9 +18,9 @@ This package is the common schema layer used by: - `@contentrain/query` - `@contentrain/rules` -It defines the stable type vocabulary for models, config, metadata, validation, scanning, and context files. +It defines the stable type vocabulary for models, config, metadata, validation, scanning, context files, and provider contracts (enabling third-party RepoProvider implementations). -## ✨ When To Use It +## When To Use It Use `@contentrain/types` when you are: @@ -28,14 +28,15 @@ Use `@contentrain/types` when you are: - sharing model/config types between packages in a workspace - authoring framework integrations or SDK extensions - consuming Contentrain JSON structures directly in TypeScript +- implementing a custom `RepoProvider` for a new git backend -## 🚀 Install +## Install ```bash pnpm add @contentrain/types ``` -## 📦 What It Exports +## What It Exports Core unions: @@ -54,6 +55,7 @@ Core interfaces: - `FieldDef` - `ModelDefinition` +- `ModelSummary` - `ContentrainConfig` - `Vocabulary` - `EntryMeta` @@ -76,11 +78,40 @@ Storage/runtime helper types: - `DictionaryContentFile` - `CollectionEntry` - `CollectionContentOutput` +- `DocumentEntry` +- `DocumentContentOutput` - `SingletonMeta` - `CollectionMeta` - `DocumentMeta` - `DictionaryMeta` +Normalize/plan types: + +- `NormalizePlan` +- `NormalizePlanModel` +- `NormalizePlanExtraction` +- `NormalizePlanPatch` + +Provider contracts (re-exported from `provider.ts` — implement these to add a new git backend): + +- `RepoProvider` +- `RepoReader` +- `RepoWriter` +- `ProviderCapabilities` +- `FileChange` +- `CommitAuthor` +- `Commit` +- `ApplyPlanInput` +- `Branch` +- `FileDiff` +- `MergeResult` (includes optional `sync?: SyncResult` for local-worktree providers) +- `LOCAL_CAPABILITIES` (const — capability set for LocalProvider) + +Git transaction types: + +- `SyncResult` +- `ContentrainError` + Validate functions (pure, dependency-free): - `validateSlug(slug)` — kebab-case slug validation @@ -97,7 +128,18 @@ Serialize functions (pure, dependency-free): - `parseMarkdownFrontmatter(content)` — parse YAML frontmatter + body from markdown - `serializeMarkdownFrontmatter(data, body)` — serialize data + body into markdown frontmatter -## 🧭 Stability +Constants: + +- `CONTENTRAIN_DIR` — default `.contentrain` folder name +- `CONTENTRAIN_BRANCH` — default `contentrain` branch name for content tracking +- `PATH_PATTERNS` — file path conventions for models, content, meta +- `SLUG_PATTERN` — regex for valid slugs +- `ENTRY_ID_PATTERN` — regex for valid entry IDs +- `LOCALE_PATTERN` — regex for valid locale codes +- `CANONICAL_JSON` — serialization rules (indent, encoding, trailing newline, key sort) +- `SECRET_PATTERNS` — regex patterns for secret detection + +## Stability This package is intended to be the shared public contract across the Contentrain ecosystem. @@ -106,8 +148,9 @@ In practice that means: - types exported from the package root are the public surface - packages should depend on these shared definitions instead of redefining domain types - breaking changes here should be treated as ecosystem-level breaking changes +- the `RepoProvider` contract enables third-party implementations without depending on `@contentrain/mcp` internals -## 🧪 Quick Example +## Quick Example ```ts import type { @@ -145,7 +188,7 @@ const result: ValidationResult = { } ``` -## 📝 Import Style +## Import Style Type-only usage: @@ -166,7 +209,26 @@ import { } from '@contentrain/types' ``` -## 🏢 Studio Integration +Provider contract usage (for custom RepoProvider implementations): + +```ts +import type { RepoProvider, ProviderCapabilities } from '@contentrain/types' + +export class MyCustomProvider implements RepoProvider { + readonly capabilities: ProviderCapabilities = { + localWorktree: false, + sourceRead: true, + sourceWrite: true, + pushRemote: true, + branchProtection: true, + pullRequestFallback: true, + astScan: false, + } + // ...implement RepoProvider methods +} +``` + +## Studio Integration Studio (Nuxt 4, web) cannot import `@contentrain/mcp` directly because MCP depends on Node.js-only packages (`simple-git`, `@modelcontextprotocol/sdk`). The validate and serialize functions in this package are **pure, dependency-free, and browser-compatible** — designed for Studio to share the same validation contract as MCP. @@ -194,59 +256,6 @@ These require file system I/O or Node.js dependencies: - `writeContent()` / `deleteContent()` — content persistence with git worktree - `resolveContentDir()` / `resolveJsonFilePath()` — path resolution with `node:path` -### Studio implementation example - -```ts -// composables/useContentValidation.ts -import type { FieldDef, ContentrainConfig, ValidationError } from '@contentrain/types' -import { validateFieldValue, validateSlug, detectSecrets } from '@contentrain/types' - -export function useContentValidation(config: ContentrainConfig) { - function validateEntry( - fields: Record, - data: Record, - ): ValidationError[] { - const issues: ValidationError[] = [] - - for (const [fieldName, fieldDef] of Object.entries(fields)) { - // Schema validation (type, required, min/max, pattern, select) - const fieldErrors = validateFieldValue(data[fieldName], fieldDef) - for (const err of fieldErrors) { - issues.push({ ...err, field: fieldName }) - } - - // Secret detection on all string values - const secretErrors = detectSecrets(data[fieldName]) - for (const err of secretErrors) { - issues.push({ ...err, field: fieldName }) - } - } - - return issues - } - - return { validateEntry, validateSlug } -} -``` - -```ts -// composables/useDocumentEditor.ts -import { parseMarkdownFrontmatter, serializeMarkdownFrontmatter } from '@contentrain/types' - -export function useDocumentEditor() { - function loadDocument(rawMarkdown: string) { - const { frontmatter, body } = parseMarkdownFrontmatter(rawMarkdown) - return { frontmatter, body } - } - - function saveDocument(data: Record, body: string): string { - return serializeMarkdownFrontmatter(data, body) - } - - return { loadDocument, saveDocument } -} -``` - ### Unique constraints and relation validation `validateFieldValue` handles schema-level checks. Two things require external state: @@ -256,7 +265,7 @@ export function useDocumentEditor() { These are left to Studio's server-side or API layer to implement on top of the pure validation. -## 🧠 Design Role +## Design Role `@contentrain/types` exists so every package in the monorepo speaks the same domain language. @@ -267,6 +276,7 @@ Examples: - SDK codegen consumes `ModelDefinition` and `FieldDef` - AI rules align with the same model and workflow vocabulary - Studio uses the same validation functions in the browser +- Third-party providers implement `RepoProvider` to plug into MCP This package should stay: @@ -276,7 +286,7 @@ This package should stay: - stable - free of package-specific behavior -## 🛠 Development +## Development From the monorepo root: @@ -286,13 +296,13 @@ pnpm --filter @contentrain/types test pnpm --filter @contentrain/types typecheck ``` -## 🔗 Related Packages +## Related Packages - `@contentrain/mcp` - `contentrain` - `@contentrain/query` - `@contentrain/rules` -## 📄 License +## License MIT diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 531bc24..c0d5075 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -204,6 +204,9 @@ importers: packages/rules: devDependencies: + '@contentrain/mcp': + specifier: workspace:* + version: link:../mcp '@types/node': specifier: ^22.0.0 version: 22.19.15 @@ -238,6 +241,9 @@ importers: packages/skills: devDependencies: + '@contentrain/mcp': + specifier: workspace:* + version: link:../mcp '@types/node': specifier: ^22.0.0 version: 22.19.15 diff --git a/tsconfig.json b/tsconfig.json index f7f4ae0..82c8efc 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,6 +13,7 @@ "@contentrain/mcp/util/*": ["packages/mcp/src/util/*.ts"], "@contentrain/mcp/git/*": ["packages/mcp/src/git/*.ts"], "@contentrain/mcp/providers/*": ["packages/mcp/src/providers/*.ts", "packages/mcp/src/providers/*/index.ts"], + "@contentrain/mcp/tools/*": ["packages/mcp/src/tools/*.ts"], "@contentrain/mcp/templates": ["packages/mcp/src/templates/index.ts"], "@contentrain/query": ["packages/sdk/js/src/index.ts"], "@contentrain/query/generate": ["packages/sdk/js/src/generator/generate.ts"]