opticli.

Let your coding agent edit Optimizely content. You review the drafts.

Your coding agent uses opticli to find and edit pages and blocks. Edits go through the CMS API in your running site, so they're validated, versioned and saved as drafts. Production is read-only.

One change, four ways to run it

Run the change

Your agent runs

opticli set 7 TeaserText='Plan, track and report with the whole team' MetaTitle='Alloy Track: plan, track and report with the whole team' --dry-run --publish --db prod

error (refused): Refusing to write to 'alloy-demo-prod' on 'localhost,1433': it is a production database (role prod), which opticli only reads. hint: opticli writes to a production database only through a sealed apply, which the user runs in their own terminal.

Alloy TrackProductPage · ref 7 · en Dry runDraftPublishedRefused nothing saved saved as 7_1755 by opticli 7_1755 published by opticli alloy-demo-prod · nothing saved
@@ TeaserText
1−Involve the whole team!
1+Plan, track and report with the whole team
@@ MetaTitle
1−Alloy Track, online risk management where the whole team ge…
1+Alloy Track: plan, track and report with the whole team
  • valid: yes
  • access rights: user opticli
  • saved: no
  • saved: yes, a new version
  • published: no, that takes --publish
  • published: yes, this page has no approval sequence
  • production: read-only
  • write refused, dry runs too

An illustration built from opticli's real output, on Optimizely's Alloy sample site. The screencast below shows actual runs.

Watch it work

ScreencastAlloy sample site · CMS 12 · .NET 8 · 11 min, long pauses cut

What it does

Read content

Answer content questions without SQL

Chapter 2 · Find the content
opticli get 123 --fields MainContentArea

No more hand-written queries against tblContent. Items come back with every property decoded, including ContentAreas, local blocks, links and rich text. Reads go straight to the database, so the site doesn't need to be running.

Go from content to code

Chapter 3 · Find the code
opticli type TeaserBlock

See the C# class for a content type, the source line of each property and the Razor views, plus which ContentAreas accept it according to [AllowedTypes].

Know what a change will affect

Chapter 2 · Find the content
opticli where-used 456 --pages

Find every page and block that references an item, through nested blocks all the way up to pages. You can also resolve a URL to content, or list the unpublished drafts.

Content history

opticli history 123

See an item's change log: moves, deletes, restores and publishes, with who did each and when.

CMS 12 and CMS 13

opticli doctor

The same commands work on both, including CMS 13 databases upgraded from CMS 12. serve picks the right site agent for your CMS version.

Change content

Change content through the CMS API

Chapter 4 · Make the change
opticli set 123 Heading="New title" --dry-run

Writes go through IContentRepository inside your running site, so validation, versioning, events and caches all work. Changes are saved as drafts unless you publish, and every write command takes --dry-run.

Visual Builder pages

opticli composition 123 add element --in Left --type TextElement Heading=Hi

get shows an experience as its sections, rows, columns and elements, with display templates and settings. composition adds, moves, changes and removes them, or writes back the JSON get printed. Content variations and blueprints work too.

Page settings

opticli set 123 SimpleAddress=campaign

Read and set shortcuts and external links, simple addresses, categories, sort order and publish dates.

Safe deletes, with restore

Chapter 7 · Safety nets
opticli delete 456 --dry-run

delete only moves content to the recycle bin, and refuses while other pages or blocks still reference it, listing where. trash shows what's in the bin, and restore puts it back where it was.

Unpublish and discard

Chapter 7 · Safety nets
opticli unpublish 123

unpublish takes a page offline, the same way expiring it in the edit UI does, and shows which version was live so you can publish it again. discard removes a draft that was never published.

Approvals and scheduled publishing

opticli publish 123 --request-approval

Content with an approval sequence can't skip its reviewers: --request-approval sends it for review instead. --publish-at schedules the publish with the CMS's own scheduled job.

Upload files as media

opticli upload price-list.pdf --for 123

Each file becomes a media item of the type your site registers for its extension, in the page's own folder or any folder you choose. The output shows where it was stored.

Read and change access rights

Chapter 5 · A section as a plan
opticli access 123 --revoke Everyone

See who can read and edit an item, and where those rights are inherited from. Changes apply to that item only, and can never leave the site without an administering role.

Plans

Plans you can run again

Chapter 6 · Run it again
opticli apply plan.json --update-existing

With "guidNamespace", every item a plan creates gets the same GUID in every database. --update-existing then updates what's already there, restores it from the recycle bin if needed, and skips finished steps. export turns existing content from any database into a plan like this.

"MainBody": "@body.html"

A plan value of "@body.html" reads that file, so long rich text lives in HTML files you can review instead of inside the JSON. Links written as href="$id" point to content the plan creates and are saved as permanent links.

Dry runs that reach every step

Chapter 5 · A section as a plan
opticli apply plan.json --publish --dry-run

Steps on content the plan hasn't created yet run against stand-ins, so validators, required properties and [AllowedTypes] are checked before anything is written.

Environments and production

Run a production copy on localhost

opticli sites primary --from-config

After restoring a production database, one command makes your local host each site's primary host and moves SiteUrl with it, so links and canonical URLs point to localhost. The production hosts are kept. Save the mapping once and rerun it after every restore. users add creates a local admin login and stores its password in a file only you can read.

Pull content from production

Chapter 11 · Pull from production
opticli sync pull --from prod --all --dry-run

sync pull brings what editors did in production into your local database: new, changed and moved content, matched by GUID and written through your local site. It only reads production, keeps your own local changes, lists conflicts instead of overwriting them, and remembers what it synced, so the next pull is quick.

Push to production: the agent prepares, you run it

Chapter 12 · Push to production
opticli sync push --to prod /en/campaign/

A coding agent can prepare changes for production but can't write them. sync push seals what changed locally. You run the command it prints in your own terminal: it shows what it will do, then asks for the database's name and a write login, which is never saved. It refuses to run if the plan, the build or production changed since the seal. On Azure it can join production's event bus, so no restart is needed, and upload media to its blob storage.

Site operations

opticli jobs run "Content import"

See every job's schedule, last run and log, and where its code lives. Run one and wait for its result, stop it, or change when it runs. After a database restore, serve stops overdue jobs from all running at startup, and jobs that delete data permanently need an explicit flag.

Clean up what removed code left behind

Chapter 9 · Clean up leftovers
opticli types prune --dry-run

types --orphaned finds content types whose code is gone, and type shows leftover properties with their stored values. types prune removes what can go through the CMS, never content, records every removal first, and needs a flag before it deletes stored values.

Your IDE and your agent

Nothing to add to your solution

Chapter 1 · No setup
opticli serve

serve starts your existing build with a small agent injected at startup, through a .NET startup hook and a hosting startup. Your site's code and config stay as they are. ide on only adds a block to your own .csproj.user, which git ignores.

See changes in the site you're debugging

Chapter 13 · See it while debugging
opticli ide on

With ide on, the site you start from Rider or Visual Studio loads the agent from its own build, so opticli writes through that process and a reload shows the change, without a restart. No per-run setup, HTTPS with the development certificate works, and the debugger, hot reload and breakpoints stay as they are.

Built for coding agents

Chapter 14 · Let an agent do it
opticli skill install

Piped output is compact JSON. Every item has a ref you can pass to the next command, and errors come with a code and a hint. A Claude Code skill tells the agent when to use opticli and how to use it safely.

How it worksreads go straight to the database, writes through your running site

Safety

  • Which database does it use?

    Your local one by default: opticli reads the connection string from the site's Development config. To use a remote database you have to choose it explicitly, and every response then carries a warning.

    local by default
  • Can a read change anything?

    No. Reads use fixed queries. opticli sql accepts a single SELECT against the site's own database and runs it in a transaction that is rolled back.

    read-only
  • Can it publish or delete by accident?

    No. Changes are saved as drafts, under a CMS user named opticli. Publishing needs --publish. delete only moves content to the recycle bin, and refuses while other content still references it.

    drafts · recycle bin
  • Can it write to production?

    Not on its own. A database with the role prod is read-only: every response carries a warning, and serve and every write, dry runs included, are refused. The only way to write is a sealed apply that you run in your own terminal, with a write login you type and opticli never saves; an agent can prepare and seal it, not run it. Chapter 10 · Production is read-only

    refused · sealed apply only
  • Can starting it change a shared database?

    Only in limited ways. Against a remote development database, opticli turns off the scheduler, schema updates, content type sync and store remapping, and serve won't start a build with EF Core migrations the database lacks. Two things still happen: the CMS registers the build's scheduled jobs and add-on content roots, and the site's own startup code runs. Where your add-ons allow it, use a login without DDL rights.

    limited
  • What if my branch isn't what's deployed?

    opticli compares the build with the shared database: content types, properties, migrations. While they differ, writes stop until you confirm with --accept-drift, and opticli tells you whether the code or the database is newer. Reads keep working.

    writes stop on drift
  • What can the MCP server do to a production site?

    Only what the signed-in editor may do: every read and save is checked against their access rights, and content they can't read looks the same as content that doesn't exist. Changes are drafts, without script. Publishing and deleting are off until the site turns them on, and approval sequences always apply. Only apps on the editor's own machine can connect, and web-based assistants from addresses the site allows (claude.ai by default); editors can see and revoke their connections.

    only what the editor may
  • Can anyone else reach the site agent?

    It answers only to requests from this machine, only in Development, and only with the token of that run, which sits in a file only you can read. Requests that came through a proxy or tunnel are refused.

    loopback + run token only
  • Does the site I debug start differently?

    No. With ide on, the agent doesn't pin the database or touch the scheduler, and it never stops the site from starting: against another database, or outside Development, it stays off for that run and tells you why.

    no

For editors

opticli runs on a developer's machine. OptiCli.Mcp (OptiCli.Mcp.Cms13 on CMS 13) is an MCP server installed in the site, so editors can work on its content with their AI assistant in any environment.

An assistant, signed in as the editor

Editors connect an assistant that supports MCP servers (Claude Desktop has an extension for it) and sign in with their usual CMS login. The assistant then works as them, with their access rights: drafts by default, dry runs, validation, approval sequences and a preview link for every draft. Works with CMS 12 from 12.12.1 (CMS UI 12.16.1) and CMS 13, including Visual Builder pages.

For editors
EditorThe Alloy Track teaser should mention reporting.
AssistantSaved as a draft: TeaserText is now "Plan, track and report with the whole team". Here's the preview. Nothing is published yet.

Releases

Every release is on nuget.org, with the details in the changelog. After updating, run opticli skill install again to update the skill.

  1. 0.26.028 October 2026
    • The MCP server on CMS 13: install OptiCli.Mcp.Cms13 in a CMS 13 site. OptiCli.Mcp stays the package for CMS 12, now also on .NET 10. Both are set up the same way, so upgrading a site to CMS 13 is a package swap. Assistants can read Visual Builder pages too; see For editors.
    • MCP hardening: when a site runs another MCP server as well, the two no longer share endpoints or sessions. If that's your CMS 12 site, update OptiCli.Mcp to 0.26.0.
  2. 0.25.028 October 2026
    • The MCP server is out of preview: dotnet add package OptiCli.Mcp now installs it without --prerelease. It works with any assistant that supports MCP servers with an OAuth sign-in; see For editors.
    • Claude Desktop extension: every release includes opticli-cms.mcpb. Editors open it in Claude Desktop and enter the site's address.
  3. 0.24.026 October 2026
    • No restart after a production push: on sites that use the CMS's Azure providers, a sealed run can join production's event bus, so production's servers clear their caches right away. You enter the event bus connection at the run, like the write login, and it's never saved. The result says if a restart is still needed.
    • Media to production: sealed plans can upload files to production's blob storage, and sync push --media pushes media too.
    • Fewer blockers: content types and properties that only exist in production's database no longer block a seal, and sealed runs work against production sites that sign in with Microsoft Entra ID.

Older releases are in the changelog

Get started.NET 8 SDK or newer · a CMS 12 or CMS 13 site's repository
# install, or update to the latest version
dotnet tool install -g OptiCli
dotnet tool update -g OptiCli

# then, in your site's repository
opticli doctor            # what it found: project, database, types
opticli resolve https://example.com/en/about/
opticli skill install     # teach Claude Code to use it

Install it from nuget.org as a global tool and run it from anywhere inside your site's repository. Nothing is added to your solution.