How a Headless CMS With an API and CLI Actually Works, for JavaScript and GitHub Setups
Search for "headless cms with an api and cli" and you get three related questions stacked on top of each other: how it works in a JavaScript project, how it works with GitHub, and what the JSON actually looks like. If you have some dev background, this is easy. If you don't, you just need to pick up a handful of basic concepts. Nothing here requires prior CMS experience. This post answers all three in one place, because anyone wiring this into a real project, developer or not, usually needs all three at once, not one page per question.
What Is a Headless CMS With an API and CLI?
A headless CMS with an API and CLI is a content system with no built-in editor screen. You create, read, update and publish content by calling an HTTP API directly or by running commands from a terminal, which is what the CLI wraps. The CMS stores and serves content, and your website, script, or agent decides what to do with it.
This is different from a traditional CMS, where you log into a web dashboard, type into a rich text editor, and click publish. A headless CMS with an API and CLI treats content as data that any program can touch, not as something a human types into a browser form. That distinction matters once you want a script, a CI pipeline, or an AI agent to publish content instead of a person clicking buttons.
The CLI is not a separate product from the API. It is a thin wrapper: running a command like floggy posts create sends the same API request you could send with curl or an SDK call, just with a friendlier interface for a terminal. If you understand the API, you already understand what the CLI does under the hood.
Headless CMS With API/CLI vs. Traditional CMS With a Web Editor
| Aspect | Headless CMS with API/CLI | Traditional CMS with web editor | | --- | --- | --- | | Primary interface | HTTP API, SDK, CLI | Browser-based dashboard | | Who/what can publish | Humans, scripts, CI jobs, AI agents | Humans only, through the UI | | Content storage | Structured data (typically JSON), reachable by other systems | Stored in the CMS's own database, tied to its rendering | | Version control | Content or config can live in git alongside code | Rarely versioned outside the CMS itself | | Automation | Native: scriptable end to end | Usually needs browser automation or a plugin | | Rendering | Decoupled; any frontend can consume the content | Coupled to the CMS's own templates or theme | | Bulk or programmatic content | Straightforward via loops, scripts, or generated collections | Manual entry, or slow custom tooling |
How Does the API and CLI Fit Into a JavaScript Project?
You install the CLI and SDK as dev dependencies with a package manager, then call them from npm scripts, build steps, or standalone Node scripts, the same way you'd use any other CLI tool in a JavaScript project. There is no separate install process outside your normal package.json workflow.
An illustrative (not literal) setup looks like adding the package:
npm install --save-dev @floggy/cliand then calling it from an npm script:
{
"scripts": {
"publish-post": "floggy posts create --file ./content/latest.md"
}
}The package name, command, and flag above are representative of the pattern, not a claim about the exact documented interface.
From here, a Node script can also call the SDK directly instead of shelling out to the CLI, which is useful when you want to build content programmatically rather than pointing the CLI at a static file. The example below is illustrative in the same way, showing the shape of an SDK call rather than a documented function signature:
import { createPost } from "@floggy/sdk";
await createPost({
title: "Draft title",
body: renderedMarkdown,
status: "draft",
});The SDK and CLI are two entry points to the same operations. Which one you reach for depends on whether you're scripting a one-off task (CLI is faster to type) or building logic that needs conditionals, loops, or error handling (SDK is easier to work with in code).
How Does This Fit a GitHub-Based Workflow?
In a GitHub-based workflow, content or configuration lives as files in a git repository, and the CLI runs as a step inside GitHub Actions to publish, update, or validate that content on a schedule or on merge. This turns publishing into a git event instead of a manual login-and-click action.
A common pattern: someone (or an agent) opens a pull request that adds or edits a markdown or JSON content file. A GitHub Actions workflow triggers on that PR, runs the CLI to validate the content shape, and posts the result as a check. Once the PR merges to the main branch, a second workflow runs the CLI again, this time to actually publish.
An illustrative (not literal) GitHub Actions step might look like this:
- name: Publish post
run: npx floggy posts publish --file ./content/new-post.md
env:
FLOGGY_API_KEY: ${{ secrets.FLOGGY_API_KEY }}The value of this pattern is that publishing inherits everything git already gives you: pull request review before anything goes live, a commit history of every content change, and the ability to revert a bad publish the same way you'd revert a bad code change. For programmatic or agent-driven content specifically, this means an AI agent's output can be reviewed as a diff before it reaches readers, instead of trusting the agent to publish directly with no checkpoint.
What Does the JSON Actually Look Like?
The content moving through a headless CMS with an API and CLI is typically a structured JSON object with fields for the content body, metadata like title and status, and identifiers the system uses to track the entry. The exact field names vary by system, but the shape below is representative of the pattern, not a literal documented schema for any specific product.
An illustrative content entry, the kind of object you'd get back from an API call or CLI command run with a JSON output flag:
{
"id": "post_8f2a1c",
"type": "post",
"title": "Example title",
"slug": "example-title",
"body": "Markdown or rich text content goes here.",
"status": "draft",
"collection": "blog",
"created_at": "2026-06-01T00:00:00Z",
"updated_at": "2026-06-02T00:00:00Z",
"metadata": {
"author": "example-user",
"tags": ["example", "illustrative"]
}
}A CLI command that lists entries or creates one typically prints or accepts this same shape, often with a --json flag to get machine-readable output instead of a human-friendly table:
floggy posts list --jsonThe reason this shape matters for a JavaScript or GitHub-based setup is that JSON is what makes content portable between the CMS, your build scripts, your CI checks, and any script an agent writes to generate content. Because it's plain structured data, you can validate it with a JSON schema, diff it in a pull request, or transform it in a script before it ever reaches the API.
Why Does This Matter for Agentic and Programmatic Use Cases?
An API-and-CLI-first CMS matters for agentic and programmatic use cases because an AI agent, a scheduled job, or a script cannot click through a web dashboard, it can only call functions and read structured responses. If publishing requires a human at a keyboard, automation stops at the point where a person has to log in and press a button.
With an API and CLI, an agent can generate a post, call the create endpoint (or the equivalent CLI command), and publish it on a schedule, no different in mechanics from a cron job triggering a script. Custom collections extend this beyond blog posts: instead of a fixed "post" content type, you define your own collection shape (a directory of local businesses, a set of product comparisons, a list of glossary terms) and the same create, update, and publish operations work against it. That's what makes programmatic SEO at scale possible: one script or one agent loop, run against a collection definition, can generate and publish hundreds of structured pages instead of someone typing each one into an editor.
The GitHub-based pattern from earlier fits naturally on top of this. An agent's generated content becomes a pull request, a human or automated check reviews it, and the CLI in a GitHub Actions workflow handles the actual publish step once it's approved. Structured content plus a scriptable interface is what makes agent-driven publishing something you can build and review, rather than something you have to trust blindly.
Who This Is Actually For
This approach fits developers, solo founders, SEO agencies, and companies who want a content system they can drive from code rather than from a browser tab. If your workflow already involves git, CI, and scripts, an API-and-CLI-first CMS slots into that workflow instead of asking you to leave it.
A solo developer can wire up a script that drafts posts from an RSS feed or a set of notes and pushes them through the CLI. An SEO agency managing programmatic content for a client can define a custom collection and generate hundreds of entries from a spreadsheet or a script, with every entry reviewable as a pull request before it goes live. A company running AI agents to research and write content can give the agent API access instead of screen-scraping a dashboard, and can add a scheduled workflow to publish or check for updates automatically.
Floggy is built around this pattern: an API and CLI for programmatic and agent-driven publishing, custom collections for structuring content beyond a standard blog post, and the git-and-CI style review workflow described above, alongside the parts most people expect from a blog, a real editor, a custom domain, and a newsletter, for anyone who does want to write by hand some of the time.


