@litpage/cli
v0.6.6
Published
Agent-first CLI for LitPage v2 content publishing
Maintainers
Readme
@litpage/cli
Publish Markdown to LitPage from your terminal.
LitPage CLI is an agent-first CLI for LitPage v2 content publishing. It is designed for LLM agents, CI jobs, scripts, and developers who want a stable way to push Markdown files to LitPage with machine-readable output.
All examples below use npx @litpage/cli ....
For agent and AI workflows, the security baseline is:
- prepare configuration before the agent starts
- inject the workspace key through the host environment or secret manager
- do not put the raw key into prompts, command lines, Markdown files, or checked-in config
Create a post.md file:
---
title: Hello LitPage
slug: hello-litpage
subdomain: docs
type: BLOG
language: EN
excerpt: First post published from Markdown
author:
name: Codex
updateReason: Initial draft
---
# Hello LitPage
This page was published from a local Markdown file.Then publish it:
npx @litpage/cli publish ./post.mdIf your file includes complete frontmatter such as slug, title, subdomain, type, and language, LitPage CLI can turn that Markdown file into a LitPage page in one command.
Why LitPage CLI
- Publish Markdown files directly to LitPage
- Upsert by
slug, so retries are safe - Use
subdomaininstead of internalsiteIdfor normal workflows - Default to JSON on
stdout, which works well for agents and automation - Pull remote content back into Markdown when you need to sync locally
Requirements
- Node.js
>= 18 - A LitPage workspace API key
- An existing LitPage site created in
https://lit.page
If you do not have a workspace API key yet, sign up at https://lit.page, create a site, then create or copy a key from your LitPage account.
At the current stage, the CLI publishes content to an existing LitPage site. It does not create sites or provision domains for you. Create the site first in the LitPage product UI, then use the CLI to publish Markdown into that site.
Before You Start: Create A Site In LitPage
Today the expected setup flow is:
- Go to
https://lit.page - Create a site in the product UI
- Choose or confirm its site address
- Create a workspace API key with access to that site
- Use LitPage CLI to publish content into that site
If you skip step 2, the CLI has nowhere to publish.
What subdomain Means
For normal workflows, LitPage CLI targets a site by subdomain.
subdomain is the site identifier that comes from the LitPage site you already created. If your site address is:
docs.lit.page, thensubdomainisdocsnews.lit.page, thensubdomainisnews
If you later bind a custom domain, the site still has an underlying LitPage site identity. In CLI usage, prefer the canonical LitPage subdomain unless you intentionally want to resolve by domain.
You can find the value from:
- the site creation flow in
https://lit.page - the site settings or dashboard where the LitPage address is shown
npx @litpage/cli site listnpx @litpage/cli site resolve <domain-or-subdomain>
Example:
npx @litpage/cli site list
npx @litpage/cli site resolve docs
npx @litpage/cli site resolve docs.lit.pageUse With npx
Run commands directly with:
npx @litpage/cli --helpQuick Start
1. Create or confirm the target site
Before using the CLI, make sure the target site already exists in https://lit.page.
If the site address is docs.lit.page, the subdomain you should use in CLI commands and frontmatter is docs.
2. Configure only the workspace key reference
The recommended setup is to save a non-secret reference for the key:
npx @litpage/cli config set workspaceKey env:LITPAGE_WORKSPACE_KEYResulting config:
{
"workspaceKey": "env:LITPAGE_WORKSPACE_KEY",
"defaultType": "BLOG",
"defaultLanguage": "EN"
}Then let the host shell, CI runner, or secret manager inject the real key value:
export LITPAGE_WORKSPACE_KEY=lp_live_xxxSaving a default subdomain in config is optional. For normal workflows, prefer either:
subdomainin Markdown frontmatter--subdomain <name>to override the file target explicitly
litpage.config.json may be prepared by a human, deploy script, or CI bootstrap step. The agent should consume existing config, not create or edit secrets.
For a local one-off manual test, a human can also store the literal key with:
npx @litpage/cli config set workspaceKey lp_live_xxxDo not use that plaintext pattern for agents, CI, or checked-in repositories.
3. Run doctor first
npx @litpage/cli doctordoctor is the first setup and diagnosis command:
- if the workspace key is missing, it explains how to create one and inject it
- if no sites are accessible, it tells you to create a site in
https://lit.page - if multiple sites are accessible, it points you to Markdown
subdomain,--subdomain,site list, andsite resolve
If you are not sure which site values are available to the current key, inspect them with:
npx @litpage/cli site list4. Create a Markdown file
---
title: Hello LitPage
slug: hello-litpage
subdomain: docs
type: BLOG
language: EN
excerpt: First post published from Markdown
author:
name: Codex
updateReason: Initial draft
---
# Hello LitPage
This page was published from a local Markdown file.5. Publish it to LitPage
npx @litpage/cli publish ./post.md --subdomain docsIf subdomain is already in the file frontmatter, this also works:
npx @litpage/cli publish ./post.mdThe Main Workflow
For most users, there are only two commands to remember:
publish <file>: upsert the Markdown file by slug, then publish itapply <file>: upsert the Markdown file by slug without publishing it
Examples:
npx @litpage/cli publish ./post.md --subdomain docs
npx @litpage/cli apply ./draft.md --subdomain docsIf you need low-level primitives, use the content command group.
To initialize a non-empty Markdown starter file instead of hand-writing frontmatter:
npx @litpage/cli content template ./post.md --title "Hello LitPage" --slug hello-litpage --subdomain docsHow Markdown Maps To LitPage
LitPage CLI reads Markdown with frontmatter and turns it into a LitPage content payload.
Frontmatter:
titleslugsubdomaintypelanguageexcerptauthorupdateReason
Rules:
titlemay be omitted if the first Markdown heading existscontent bodyis always requiredslugis required forapply,publish, andcontent upsertsubdomainshould match the existing LitPage site you want to publish into- the built-in frontmatter parser supports scalar fields and simple one-level nested objects such as
author
Example:
---
title: Shipping Notes
slug: shipping-notes
subdomain: docs
type: BLOG
language: EN
excerpt: Weekly release notes
author:
name: Team LitPage
---
# Shipping Notes
- Added new onboarding flow
- Fixed content sync edge caseCommon Examples
Publish a Markdown file
npx @litpage/cli publish ./post.md --subdomain docsPublish using frontmatter subdomain
npx @litpage/cli publish ./post.mdUpsert without publishing
npx @litpage/cli apply ./post.md --subdomain docsOverride the slug from the command line
npx @litpage/cli publish ./post.md --subdomain docs --slug launch-postUse a saved project default subdomain
npx @litpage/cli config set subdomain docs
npx @litpage/cli publish ./post.mdThis is optional. For normal content workflows, subdomain in Markdown or --subdomain on the command line is usually clearer.
Use a named profile
npx @litpage/cli --profile prod publish ./post.mdInspect accessible sites
npx @litpage/cli site listResolve a subdomain or domain to a site
npx @litpage/cli site resolve docs
npx @litpage/cli site resolve docs.lit.pageList content in a site
npx @litpage/cli content list --subdomain docs
npx @litpage/cli content list --subdomain docs --status PUBLISHED --limit 20Get a page by slug
npx @litpage/cli content get --slug hello-litpage --subdomain docsGet a page by id
npx @litpage/cli content get --id content_uuid --subdomain docsCreate content without a stable slug
npx @litpage/cli content create --file ./post.md --subdomain docsThis is available, but for agent-safe workflows publish, apply, or content upsert is usually better.
Update an existing page by content id
npx @litpage/cli content update --id content_uuid --file ./post.md --subdomain docsUpsert by slug with the low-level command
npx @litpage/cli content upsert --file ./post.md --subdomain docsPull remote content back into Markdown
npx @litpage/cli content pull --slug hello-litpage --subdomain docs --out ./post.mdPublish or unpublish an existing content item
npx @litpage/cli content publish --id content_uuid --subdomain docs
npx @litpage/cli content unpublish --id content_uuid --subdomain docsConfiguration
Configuration is resolved in this order:
- CLI flags
- Environment variables
- The first existing config file in this order:
./litpage.config.json./.litpagerc~/.litpagerc
Supported environment variables:
LITPAGE_WORKSPACE_KEYLITPAGE_SUBDOMAINLITPAGE_API_BASE_URLLITPAGE_BASE_URLLITPAGE_PROFILE
Supported config keys:
workspaceKeyapiBaseUrlbaseUrlsubdomaindefaultTypedefaultLanguage
Security Guidance
For agent and AI usage, treat the workspace key as a secret with the same handling standard as a deploy token.
Recommended:
- use a dedicated workspace key for each agent, CI environment, or deployment boundary
- pre-create
litpage.config.jsonor~/.litpagercbefore the agent runs - store
workspaceKeyasenv:LITPAGE_WORKSPACE_KEY, not as a literal key - inject
LITPAGE_WORKSPACE_KEYfrom the host environment, CI secret store, or container runtime - commit non-secret defaults such as
subdomain,defaultType, anddefaultLanguage - keep secret-bearing config outside the repository when possible
- rotate or revoke the key when an agent environment is retired or suspected to be exposed
Do not do this in agent workflows:
- do not paste
lp_live_...into the agent prompt - do not call
npx @litpage/cli --workspace-key lp_live_... ... - do not call
npx @litpage/cli config set workspaceKey lp_live_... - do not commit
workspaceKeyas plaintext inlitpage.config.json - do not place the key in Markdown frontmatter, shell scripts, issue comments, or screenshots
Why:
- command-line flags may be captured by shell history, process inspection, CI logs, or agent transcripts
- plaintext config may be committed, copied into caches, or exposed in workspace snapshots
- prompt-injected secrets tend to leak into chat history, tool traces, and debugging output
For local development, a human can still choose to store the key directly, but that is not the recommended model for automation or AI agents.
Example litpage.config.json:
{
"workspaceKey": "env:LITPAGE_WORKSPACE_KEY",
"subdomain": "docs",
"defaultType": "BLOG",
"defaultLanguage": "EN"
}Profiles are also supported:
{
"defaultProfile": "prod",
"profiles": {
"prod": {
"workspaceKey": "env:LITPAGE_WORKSPACE_KEY",
"subdomain": "docs",
"defaultType": "BLOG",
"defaultLanguage": "EN"
}
}
}Site Target Resolution
For normal file publishing workflows, LitPage CLI resolves the target site in this order:
- Explicit
--subdomain - File frontmatter
subdomain - Config or environment
subdomain - Automatic fallback when the workspace key can access exactly one site
If the key can access multiple sites and no target is provided, the CLI fails with a structured SITE_CONTEXT_REQUIRED error.
For most workflows, subdomain is the preferred target identifier:
npx @litpage/cli publish ./post.md --subdomain docsIn practice, docs should come from the site you already created in https://lit.page, where the site address is docs.lit.page.
Commands
Top-level commands
npx @litpage/cli doctor
npx @litpage/cli config current
npx @litpage/cli site list
npx @litpage/cli site resolve docs
npx @litpage/cli apply ./post.md --subdomain docs
npx @litpage/cli publish ./post.md --subdomain docsContent commands
npx @litpage/cli content list --subdomain docs
npx @litpage/cli content get --slug hello --subdomain docs
npx @litpage/cli content create --file ./post.md --subdomain docs
npx @litpage/cli content update --id content_uuid --file ./post.md --subdomain docs
npx @litpage/cli content upsert --file ./post.md --subdomain docs
npx @litpage/cli content pull --slug hello --subdomain docs --out ./post.md
npx @litpage/cli content publish --id content_uuid --subdomain docs
npx @litpage/cli content unpublish --id content_uuid --subdomain docsOutput Contract
Normal command output is JSON on stdout. Errors are JSON on stderr.
Success example:
{
"ok": true,
"command": "publish",
"data": {
"operation": "created",
"content": {
"id": "content_1",
"status": "PUBLISHED"
}
},
"meta": {
"siteId": "site_1",
"subdomain": "docs",
"requestId": "req_1"
}
}Error example:
{
"ok": false,
"error": {
"code": "SITE_CONTEXT_REQUIRED",
"message": "Target site is ambiguous."
}
}Recommended Workflow For Agents
For automation, CI, and coding agents, the recommended path is:
- A human or bootstrap process writes non-secret config such as
subdomainanddefaultType - The host injects
LITPAGE_WORKSPACE_KEYfrom a secret store before the agent starts - The agent runs
doctoronce to verify access without ever handling the raw key value - The agent publishes Markdown files with stable
slugvalues - The agent uses
subdomainas the normal site selector - The agent uses
content pullwhen remote content needs to be synced back to local Markdown
Minimal safe setup:
litpage.config.json
{
"workspaceKey": "env:LITPAGE_WORKSPACE_KEY",
"subdomain": "docs"
}host environment:
export LITPAGE_WORKSPACE_KEY=lp_live_xxxagent commands:
npx @litpage/cli doctor
npx @litpage/cli publish ./post.md