This release includes breaking changes for platform teams planning a safe upgrade.
✓ No known CVEs patched in this version
Topics
+8 more
Affected surfaces
Summary
AI summaryNew provider‑agnostic engine adds GitHub and GitLab providers with HTTP transport, correcting tool catalog drift across rules/skills.
Full changelog
Minor Changes
-
cb8f65e: chore(mcp): phase 10 alignment — docs parity, cohesion fixes, P1 bug fixes, new subpath exports
Follow-up to the phase-0-through-9 provider-agnostic refactor. Ships
in one PR because the pieces are interlocking: the bug fixes rely on
new primitives, the new primitives unlock the feature gaps the docs
claimed were already covered.New public subpath exports
@contentrain/mcp/core/contracts—RepoProvider/RepoReader/
RepoWriter/ capabilities / file-change / branch / commit types,
re-exported from@contentrain/typesfor backward compat.@contentrain/mcp/providers/local—LocalProvider,LocalReader,
related types. Previously internal-only.
These paths were referenced in package documentation since phase 5
but had noexportsentry, so external imports failed with
ERR_PACKAGE_PATH_NOT_EXPORTED. Now callable.Bug fixes (P1)
- Remote write base branch invariant —
commit-plan.tsand its
call sites now always fork remote feature branches from the
contentrainsingleton branch, matching the local flow. Previous
behaviour forked fromconfig.repository.default_branch(usually
main), breaking the single-source-of-truth invariant in any
project that set the repository's default branch explicitly. - Stale remote context / validation — the new
OverlayReader
primitive layers pendingFileChanges on top of the underlying
reader.buildContextChangeand post-savevalidateProjectnow
see the state the pending commit produces instead of the
pre-change base branch. Fixes commits whose context.json entry
counts or validation result reflected the old state.
Read-only tools on HTTP + remote providers (P2)
contentrain_status,contentrain_describe, and
contentrain_content_listno longer gate on!projectRoot. They
work against anyToolProvider—LocalProvider,GitHubProvider,
GitLabProvider— through the reader surface. Branch health + stack
detection (local-only) are skipped gracefully when no project root
is available.contentrain_content_listwithresolve: truestill requires local
disk (cross-model relation hydration walks other models' content
files); the reader path rejects it with a descriptive error.
Cohesion
commitThroughProvider— shared helper that encapsulates the
LocalProvidervs remoteRepoProviderdispatch. The eight
repeatedif (provider instanceof LocalProvider) { … } else { … }
blocks acrosscontent.ts/model.tscollapse to single calls.
Uniform{ commitSha, workflowAction, sync? }return shape.providers/shared/{errors,paths}.ts— consolidated
isNotFoundError+normaliseContentRoot/resolveRepoPathused
by both GitHub and GitLab providers. Removes four duplicate
isNotFoundhelpers with asymmetric semantics (GitLab's lenient
description-match fallback is gone — status-based check only).workflow.ts—contentrain_submitandcontentrain_mergenow
gate on explicitprovider.capabilities.Xinstead of the
!projectRootproxy. Matches the patternnormalize.tsadopted in
phase 6.util/serializer.tswas previously dead-code removed in phase 9.
Test coverage
tests/providers/local/reader.test.ts— new, 11 casestests/core/overlay-reader.test.ts— new, 11 casestests/server/http.test.ts— +5 cases (content_delete, model_save,
model_delete, validate, status remote) and an updated
capability-error test that now exercisescontentrain_submit
(genuinely local-only) instead ofcontentrain_status.
Tool surface
No changes. Same 16 tools, same parameters, same response shapes.
Stdio + LocalProvider flows behave identically to the previous
release. -
0c6125b: feat(mcp): phase 11 — embedding surface + two more P2 fixes
Follow-up to phase 10. Extends the public surface Studio (and any
third-party integrator) consumes, and closes two additional bugs
surfaced while writing the handoff documentation.New public subpath exports
-
@contentrain/mcp/core/ops— plan helpers (planContentSave,
planContentDelete,planModelSave,planModelDelete) plus the
path helpers (contentDirPath,contentFilePath,
documentFilePath,metaFilePath) integrators need to compose
their own write paths against aRepoProvider. -
@contentrain/mcp/core/overlay-reader— theOverlayReader
primitive required by any non-local write path that needs
buildContextChange/validateProjectto see post-commit state.Bug fixes (P2)
-
ApplyPlanInput.basecontract alignment.GitHubProviderand
GitLabProviderpreviously fell back to the repository's default
branch (main / master / trunk) whenbasewas omitted — in direct
conflict with the docstring that said "defaults to provider's
content-tracking branch". Both implementations now default to
CONTENTRAIN_BRANCH, matching the documented contract and the
LocalProvidertransaction behaviour. Tests that locked in the old
behaviour are rewritten; the docstring is tightened to be
unambiguous. -
contentrain_statuscontext field on remote. When the session
has noprojectRoot,contentrain_statuspreviously returned
context: nullunconditionally, even though remote writes do
commit.contentrain/context.json.readContextgains a reader
overload;tools/context.tsuses it for remote flows. Remote
statuscalls now surface the last operation + stats.Tests
-
tests/server/http.test.ts—status works read-only over a remote providernow seeds.contentrain/context.jsonand asserts
the committedlastOperation+statspropagate. -
tests/providers/{github,gitlab}/apply-plan.test.ts— the
old "falls back to repo default branch" cases are rewritten to
assert the new CONTENTRAIN_BRANCH default.
-
-
ec5325f: feat: serve correctness + level-ups — drift fixes, capability surface, sync warnings, secure-by-default auth
Consolidates a four-agent review of the
contentrain servesurface
and the@contentrain/mcphelpers it consumes. Ships as a single
cohesive PR because the drift fixes are invisible without the UI
affordances that surface them (sync warnings UI, capability badge,
branch health banner).MCP — new public helpers + empty-repo init
-
branchDiff(projectRoot, { branch, base? })in
@contentrain/mcp/git/branch-lifecycle. Defaultsbaseto
CONTENTRAIN_BRANCH— the singleton content-tracking branch every
feature branch forks from. Replaces the CLI's duplicated
git.diff([${defaultBranch}...${branch}])calls, which surfaced
unrelated historical content changes oncecontentrainadvanced
past the repo's default branch. -
contentrain_inittool now handles greenfield directories: if the
repo has zero commits aftergit init(or existed commit-free),
it seeds an--allow-emptyinitial commit so
ensureContentBranchhas a base ref to anchor on. Previously the
CLIinitcommand created this commit manually while the MCP
tool skipped the step — the tool failed on an empty directory
the CLI handled fine.Serve server — correctness + new routes + auth
-
Merge flow — 3 duplicated merge-via-worktree implementations
(/api/branches/approve,/api/normalize/approve, and thediff
CLI command) now delegate to MCP'smergeBranch()helper, which
runs the worktree transaction with selective sync + dirty-file
protection. Skipped-file warnings are cached server-side and
surfaced to the UI via the newsync:warningWebSocket event +
/api/branches/:name/sync-statusroute. Merge conflicts
broadcastbranch:merge-conflictinstead of silently succeeding. -
Branch diff —
/api/branches/diffdelegates to the new
branchDiff()helper withCONTENTRAIN_BRANCHas the default base. -
History filter — tolerant of BOTH legacy
Merge branch 'contentrain/'and currentMerge branch 'cr/'commit patterns
so post-migration history doesn't drop merges. -
.catch(() => {})error swallowing at 3 sites replaced with
proper propagation. Conflicts and cleanup failures no longer
pretend to succeed. -
Normalize plan approve broadcasts
branch:createdon the
returnedgit.branchmetadata (parity with content save). -
New
/api/capabilitiesroute — provider type, transport,
capability manifest, branch health, repo info in one call.
Dashboard consumes this to render a capability badge. -
New
/api/branches/:name/sync-status— on-demand sync warning
fetch for the branch detail page; 1h TTL cache in memory. -
New WS events —
branch:rejected,branch:merge-conflict,
sync:warning. -
Zod input validation on every write route via
serve/schemas.ts. Catches malformed bodies with a structured 400
error before they reach the MCP tool layer. Addszodto the CLI's
direct dependencies. -
Secure-by-default auth —
contentrain serveon a non-localhost
interface now HARD ERRORS when no--authTokenis set. No opt-out
flag (OWASP Secure-by-Default). Matches industry tooling pattern
(Postgres, helm, kubectl port-forward).Serve UI — level-ups that make the fixes visible
-
useWatch.ts— WSEvent union widened for the new event types. -
projectstore —capabilitiesstate +branchHealthAlarm
computed +fetchCapabilities()action. -
AppLayout — global branch-health banner (warning / blocked),
sync-warning toasts with "View details" action deep-linking to
the branch detail page, merge-conflict toasts with the failure
message. -
DashboardPage — capability badge (provider type · transport)
next to the workflow + stack badges. -
BranchDetailPage — sync warnings panel listing files the
selective sync skipped, with the clear reason why the developer's
working tree was preserved. -
ValidatePage — issues are clickable when a
modelis present;
deep-links to the content list filtered tolocale/id/slug.CLI — delegation to MCP helpers
-
commands/diff.ts— both the diff summary and the merge path now
callbranchDiff()/mergeBranch()from MCP. Surfaces
sync.skipped[]warnings to the user. Removes the duplicated
contentrainbranch + worktree + update-ref + checkout dance. -
commands/doctor.ts— branch health check delegates to MCP's
checkBranchHealth(). Previously filteredcontentrain/*directly
after the Phase 7 naming migration tocr/*, so the check was
effectively a no-op. -
commands/validate.tsnon-interactive path — capturestx.complete()
result and surfaces the branch name + workflow action in review
mode. Previously this metadata was silently dropped.Verification
-
pnpm -r typecheck→ 0 errors across 8 packages. -
oxlintmonorepo → 0 warnings across 399 files. -
vue-tsc --noEmitserve-ui → 0 errors. -
pnpm --filter @contentrain/mcp build+pnpm --filter contentrain build:cli-only→ clean. -
MCP fast suite (
tests/core tests/conformance tests/serialization-parity tests/git tests/providers tests/server tests/util) → 443/443 green, 2 skipped. Includes the newsetup.test.tsempty-repo case + the newbranch-lifecycle.test.tsbranchDiffsuite.Tool surface
No changes. Same 16 MCP tools, same arg schemas, same response
shapes. Stdio + LocalProvider flows behave identically to the
previous release.
-
-
035e14e: feat: MCP boundary hardening + CLI command polish
Folds the P2 "MCP entrypoint owns a private provider contract" finding
into a single pass with CLI gap-filling — one cohesive PR because the
new CLI commands (merge,describe,describe-format,scaffold)
ride the very in-memory client helper that the boundary refactor
makes safe to commit to.@contentrain/types—MergeResult.sync-
MergeResultgains an optionalsync?: SyncResultfield. Remote
providers (GitHub, GitLab) omit it;LocalProviderpopulates it
so selective-sync bookkeeping survives the trip through the shared
RepoProvider.mergeBranch()boundary.@contentrain/mcp— provider boundary -
LocalProvidernow implements the fullRepoProvidersurface:
listBranches,createBranch,deleteBranch,getBranchDiff,
mergeBranch,isMerged,getDefaultBranch. All seven wrap
existing simple-git / transaction helpers through a new
providers/local/branch-ops.tsmodule that mirrors the
providers/github/branch-ops.tsshape. -
mergeBranch(branch, into)assertsinto === CONTENTRAIN_BRANCH—
the local flow merges feature branches into the content-tracking
branch and advances the base branch viaupdate-ref, so arbitrary
targets would bypass that invariant. -
server.ts: the privateToolProvider = RepoReader & RepoWriter & { capabilities }alias collapses totype ToolProvider = RepoProvider. Tool handlers now depend on the shared surface
directly; the alias is kept purely so existingToolProvider
imports do not have to migrate. -
providers/local/types.ts—LocalSelectiveSyncResultis removed
in favour of the sharedSyncResultfrom@contentrain/types.
workflowOverrideis typed with the sharedWorkflowModeunion
instead of the duplicated'review' | 'auto-merge'literal.
Matching swap insidegit/transaction.tsso the whole write path
speaks one union.contentrain— four new commands + shared MCP client -
utils/mcp-client.ts— new sharedopenMcpSession(projectRoot)
helper built onInMemoryTransport.createLinkedPair(). Used by
the new commands and available for future ones that wrap MCP
tools one-shot. -
contentrain merge <branch>— scriptable single-branch sibling
tocontentrain diff. Delegates to the samemergeBranch()MCP
helper so dirty-file protections + selective-sync warnings are
preserved.--yesskips the confirmation prompt for CI use. -
contentrain describe <model>— wrapscontentrain_describe.
Human-readable metadata + fields + stats + import snippet view,
with--sample,--locale,--json. -
contentrain describe-format— wrapscontentrain_describe_format.
Useful for humans pairing with an agent that's asked for the
format primer. -
contentrain scaffold --template <id>— wraps
contentrain_scaffold. Interactive template picker when no flag
is passed;--locales en,tr,de,--no-sample,--json. -
commands/status.ts— branch-health thresholds (50/80) now come
fromcheckBranchHealth()instead of being duplicated inline. The
JSON output surfaces the fullbranch_healthobject so CI
consumers see the same warning/blocked state the text mode does.Verification
-
pnpm -r typecheckacross@contentrain/types,
@contentrain/mcp, andcontentrain— 0 errors. -
oxlintacross MCP + CLI + types src/tests — 0 warnings. -
@contentrain/typesvitest — 110/110. -
contentrainvitest — 130/130. Includes the 11 new command tests
(merge,describe,scaffold) and the updatedstatusbranch-
health test against the newcheckBranchHealth()mock. -
New
tests/providers/local/branch-ops.test.ts— 7/7. Covers
contract shape, prefix-filtered branch listing, create/delete
round-trip, diff status mapping (added/modified), post-merge
isMergedflip,mergeBranchtarget guard, and config-driven
getDefaultBranch.Tool surface
No changes. Same 16 MCP tools, same arg schemas, same response
shapes. The boundary changes are purely internal.
-
-
071c46f: feat(mcp,cli): phase 14c — extract doctor into a reusable MCP tool + serve route
Pulls the 540-line
contentrain doctorCLI command apart so the same
health report drives three consumers: the CLI, the new
contentrain_doctorMCP tool, and the Serve UI's/api/doctorroute.@contentrain/mcp— new shared surface-
@contentrain/mcp/core/doctor—runDoctor(projectRoot, { usage? })returns a structuredDoctorReport:
ts interface DoctorReport { checks: Array<{ name; pass; detail; severity? }>; summary: { total; passed; failed; warnings }; usage?: { unusedKeys; duplicateValues; missingLocaleKeys }; }
Every check now carries an explicitseverity(error|
warning|info) so consumers can render pass/warn/fail
independently instead of inferring from text. Orphan content and
stale SDK client drop towarning; missing git / config /
structure stay aterror. -
contentrain_doctorMCP tool — read-only, local-only (gated
behindlocalWorktree). Arg:{ usage?: boolean }. Returns the
DoctorReportJSON verbatim. Advertised alongside
contentrain_describe_formatin the tools list.contentrain— CLI + serve consumers -
CLI
contentrain doctorcollapses to a thin pretty-printer
overrunDoctor(). Default (interactive) output is byte-identical
to the old command — same check labels, samestatus icon name: detailformat, same grouped usage output. New flags:
---json— silent, emits the rawDoctorReportto stdout.
Exits non-zero when any check fails so CI pipelines can wire
contentrain doctor --jsonas a gate.
- Interactive mode also exits non-zero now on any failure (was
always 0 before, which meant CI never noticed). -
GET /api/doctor— wraps the MCP tool.?usage=trueor
?usage=1opts into usage analysis. The Serve UI consumes this
for the Doctor panel being added in phase 14d.Scope notes
-
Doctor is inherently local-filesystem work (Node version, git
binary, mtime comparisons, orphan-dir walk, source-file scan), so
contentrain_doctoris capability-gated behindlocalWorktree
and throws a structured capability error over remote providers —
matchingcontentrain_setup,contentrain_scaffold, etc. -
No behaviour change for existing users. The CLI command still
prints the same rows; the new JSON output and non-zero exit codes
are additive.Verification
-
oxlintacross mcp/cli src + tests → 0 warnings on 350 files. -
@contentrain/mcptypecheck → 0 errors. -
contentraintypecheck → 0 errors. -
Unit tests:
tests/core/doctor.test.ts— 6/6 (uninitialised project,
minimal valid project, orphan detection with warning severity,
default-omits-usage, usage-flag-adds-3-checks, stale-SDK-mtime).tests/tools/doctor.test.ts— 4/4 (structured report over
fixture,{usage: true}opt-in, capability error on remote
provider, tool advertised in list).tests/commands/doctor.test.ts(CLI) — 7/7, rewritten to mock
runDoctordirectly. Covers--jsonoutput, exit-code
semantics (failure → 1), usage detail rendering,--usage
forwarding.tests/integration/serve.integration.test.ts— 24/24 (new
/api/doctortest: default,?usage=true,?usage=1).
Tool surface
-
+1 tool:
contentrain_doctor. All existing tools unchanged.
-
-
95eb6dc: fix(rules,skills,mcp): align rules/skills catalogs with MCP tool surface +
cr/*branches, lock with parity testsCloses the two P1 drift findings and installs a drift-detection
mechanism so they don't come back:- Missing
contentrain_merge—@contentrain/rulespublic
MCP_TOOLSlisted 15 tools.@contentrain/mcpregisters 17
(includingmergeand the newdoctor).@contentrain/skills
tool reference also jumped fromsubmitstraight tobulk. - Legacy
contentrain/{operation}/...branch namespace —
MCP'sbuildBranchName()returnscr/...(Phase 7 migration)
andcheckBranchHealthfilters oncr/, 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 fromTOOL_ANNOTATIONS.
Single source of truth — parity tests in sibling packages now
import this instead of hardcoding. - New
./tools/annotationssubpath export inpackage.json. - Build script now emits the new subpath.
@contentrain/rulesMCP_TOOLSextended to 17 tools (contentrain_merge,
contentrain_doctoradded in catalog order).essential/contentrain-essentials.md— tool table gainsdoctor
row; feature-branch pattern rewritten tocr/{operation}/...;
health-threshold language mentionscr/*.prompts/review-mode.md— every legacycontentrain/<op>/...
reference →cr/<op>/...(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_NAMESexact match- Essential guardrails mention every MCP tool
buildBranchName()output starts withcr/(sampled across scopes)- Rules docs do not contain the legacy
contentrain/<op>/...
branch prefix (false-positive filter excludes.contentrain/paths)
package.json—@contentrain/mcp: workspace:*added as devDep
for the parity test.
@contentrain/skillsskills/contentrain/references/mcp-tools.md— new sections for
contentrain_merge(after submit) andcontentrain_doctor
(new Doctor Tools subsection). Submit description updated to
cr/*branches.skills/contentrain/references/mcp-pipelines.md+workflow.md
— branch-naming spec + examples rewritten tocr/*.skills/contentrain-normalize/SKILL.md+references/extraction.mdreferences/reuse.md— 4 stalecontentrain/normalize/*
references →cr/normalize/*.
skills/contentrain-translate/SKILL.md— translate branch pattern
updated.tests/mcp-parity.test.ts(new) — 2 tests:references/mcp-tools.mdhas an### <tool>heading for every
MCP tool- 7 key skill docs do not contain the legacy branch prefix
package.json—@contentrain/mcp: workspace:*devDep.
Monorepo
tsconfig.jsonpaths —@contentrain/mcp/tools/*alias added so
TypeScript + vitest resolve the new subpath from source during dev.
Verification
oxlintacross rules + skills + mcp/tools → 0 warnings.tsc --noEmitacross rules, skills, mcp → 0 errors.@contentrain/rulesvitest → 16/16 (was 12 — 4 new parity tests).@contentrain/skillsvitest → 85/85 (was 83 — 2 new parity tests).
Tool surface
No MCP tool behaviour changes. The new
TOOL_NAMESexport is
additive; everything else is documentation + tests. - Missing
-
a488d49: feat(mcp): provider-agnostic engine + HTTP transport + GitHub & GitLab providers
The MCP package is now driven by a
RepoProviderabstraction. All
tools route through the same reader + writer + branch-ops contract,
and the server accepts any provider (not just local disk).Shipped in this release:
- HTTP transport (
@contentrain/mcp/server/http) — Streamable
HTTP MCP transport with optional Bearer auth. Works against any
provider. - GitHubProvider (
@contentrain/mcp/providers/github) — Octokit
over the Git Data + Repos APIs.@octokit/restis an optional
peer dependency. - GitLabProvider (
@contentrain/mcp/providers/gitlab) —
gitbeaker over the GitLab REST API. Supports gitlab.com and
self-hosted CE / EE.@gitbeaker/restis an optional peer
dependency. - Reader-backed reads everywhere —
listModels,
readModel,countEntries,checkReferences, and
validateProjectnow have reader overloads, so remote providers
get the same read-side behaviour (validation, reference
integrity, entry counts) as LocalProvider. - Capability-gated tools — normalize / scan / apply reject with
a uniformcapability_requirederror on providers that do not
expose local disk access.
No tool-surface changes. Stdio transport + LocalProvider remain the
default and behave identically to the previous release.Bitbucket provider is on the roadmap; see the README.
- HTTP transport (
Patch Changes
-
ca54941: docs: phase R2 — align every package README with current public surface
Each package README was cross-checked against its
src/exports,
package.jsonexportsmap, and (for MCP) theTOOL_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,
MergeResultwith optionalsync?: SyncResult,LOCAL_CAPABILITIES). - Documents
NormalizePlan*types,CONTENTRAIN_BRANCHconstant,
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_doctorrow 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. mergeBranchdescription notes thecr/*branch naming.- Capability gates section mentions doctor alongside scan/apply.
contentrain(CLI)- Global
--debugflag +CONTENTRAIN_DEBUGenv var documented. - New flags table:
--jsonon status/doctor/validate/generate/diff/
describe/scaffold;--watchon validate/generate;--demoand
--mcpHttp/--authTokenon 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 andcontentrain-query generateis the programmatic path. - Added TypeScript snippet for the programmatic
generate()API.
@contentrain/rulesMCP_TOOLSlength corrected to 17 (includescontentrain_merge
andcontentrain_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/*.mdloaded 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.
- Adds the provider-contracts section (
-
Updated dependencies [035e14e]
-
Updated dependencies [ca54941]
-
Updated dependencies [cb8f65e]
- @contentrain/[email protected]
Weekly OSS security release digest.
The CVE patches and breaking changes that affected production tools this week. One email, every Sunday.
No spam, unsubscribe anytime.
Share this release
About Contentrain/ai
Local-first MCP server for AI content governance — 13 tools for model/content CRUD, validation, normalization, and i18n across any framework.
Related context
Related tools
Beta — feedback welcome: [email protected]