@scribe-platform/cli
v0.7.0
Published
Command-line interface for Scribe CMS — scaffold sites, edit content, and triage form submissions from the terminal
Downloads
1,503
Maintainers
Readme
@scribe-platform/cli
The scribe command line interface for Scribe CMS —
provision sites, edit content, manage schemas, and triage form submissions from a terminal.
Scribe stores every site's content in its own GitHub repo as Markdown plus a
.scribe.yml schema. The CLI talks to a Scribe admin instance, which does the
GitHub work on your behalf.
Install
npm install -g @scribe-platform/cliRequires Node.js 20 or newer.
Log in
You need an API key from a Scribe admin instance: sign in to the admin UI → account menu → API Tokens → New token.
scribe login --token <key>This writes ~/.scribe/config.json (mode 600); every other command reads it.
It defaults to the hosted admin at https://scribe.weaverdigital.io — pass
--api-url (or set SCRIBE_API_URL) to point at a different one:
scribe login --token <key> --api-url http://localhost:3000Update
scribe updateInstalls the latest @scribe-platform/cli and copies the bundled
scribe-site-builder Claude Code skill into ~/.claude/skills/, so the CLI and
the instructions Claude reads move together. Restart Claude Code afterwards — it
only discovers skills at session start.
Requires a global npm install; it refuses to guess for a checkout, npx, or
another package manager. A symlinked ~/.claude/skills/scribe-site-builder is
left untouched, so a dev checkout's live skill isn't replaced by a copy.
Commands
Run scribe <group> --help for the full options on any of these.
Sites
scribe site list [--archived] [--json]
scribe site add --slug <slug> [--domain <domain>] [--name <name>]
[--turnstile-key <key>] [--form-collection <name>]
scribe site update <slug> [--domain <domain>] [--turnstile-key <key>]
scribe site clone <slug> [directory]
scribe site deploy <slug> [--skip-verify] [--timeout <minutes>]
scribe site verify <slug> [--json]
scribe site archive <slug>
scribe site restore <slug>
scribe site delete <slug> [--yes]site add creates the GitHub repo, pushes a minimal valid scaffold, and
registers the site with the admin in one step. There is no starter template to
fill in — the site is authored against the recipes in the scribe-site-builder
skill. site clone is a plain git clone of the resulting repo, so you can work
on the design locally.
site deploy dispatches the build, waits for GitHub Pages to finish, then checks
what actually shipped. site verify runs those checks on their own against
whatever is live, and exits non-zero if any fail — so it works in a script. The
five things they check are a contract between a site and Scribe, and every one of
them fails silently:
| Check | What it costs when it's missed |
|---|---|
| analytics | No visitor data, and it cannot be backfilled |
| turnstile | The endpoint rejects real submissions, or the form is open to abuse |
| retry | A visitor is told their enquiry sent when it didn't. A lost lead |
| dispatch | An editor publishes, the admin says saved, the site never updates |
| basepath | Every link and asset 404s |
Forms are optional: a site with none skips turnstile and retry rather than
failing them. A site with nothing deployed yet skips everything and exits zero.
--skip-verify exists and prints what it gave up.
site archive is how a site comes down: it turns GitHub Pages off and makes the
repo read-only, and deletes nothing. site restore brings it back and starts a
deploy. site list shows live sites, and site list --archived shows only the
archived ones. Both need a key belonging to Agency staff.
site delete permanently removes the repo and every record of the site, and only
works on a site that is already archived. It cannot be undone, and prompts for
confirmation unless you pass --yes. With no terminal to prompt on, it exits
instead.
Content
scribe content list <site> [--collection <name>] [--json]
scribe content read <site> <path> [--json]
scribe content publish <site> <file>
scribe content delete <site> <path>
scribe content versions <site> <path> [--json]
scribe content revert <site> <path> --sha <commitSha>Paths are repo-relative (e.g. content/posts/hello.md). content publish
reads the identically-named file from your working directory and commits it to
that path.
Schema
scribe schema show <site> [collection-name] [--json]
scribe schema apply <site> --file <spec|->
scribe schema add <site> <collection-name> [--path <path>]
scribe schema remove <site> <collection-name>schema show prints the site's collections and their fields; --json gives the
raw schema, for piping into another tool.
schema apply creates or replaces one whole collection from a YAML or JSON
spec, matched by name. It validates before committing anything, so a reserved
field name, an image field on a form collection, or a malformed workflow comes
back as an error rather than a broken site. Pass --file - to read from a pipe.
# rsvps.yml — then: scribe schema apply my-site --file rsvps.yml
name: rsvps
label: Event RSVPs
path: content/rsvps
format: yaml
form: true
fields:
- { name: fullName, type: string, required: true }
- { name: email, type: string, required: true }
- { name: guests, type: number }
- { name: attending, type: boolean, label: I'll be there }
workflow:
states:
- { name: pending, label: Awaiting reply, kind: needs-you }
- { name: confirmed, label: Confirmed, kind: closed }A site can have as many form: true collections as it likes; each gets its own
inbox and workflow. schema apply replaces the collection wholesale, so include
every field you want to keep.
schema add appends a bare collection stub with no fields — use it to start a
content collection interactively. For anything with fields, prefer
schema apply.
Form submissions
scribe submission list <site> <collection> [--status <status>] [--page <n>] [--json]
scribe submission update <site> <collection> <id> [--status <status>] [--note <note>]
scribe submission export <site> <collection> [--format csv|json] [--status <status>] [--out <file>]
scribe submission delete <site> <collection> <id> [--yes]<id> is the submission's id as printed by submission list. --note appends to
the submission's history; notes are an append-only log, so nothing overwrites an
earlier one.
export writes to stdout unless --out is given, so it pipes:
scribe submission export daves-exotic-cars inquiries > leads.csvCSV is for a spreadsheet and is lossy on purpose — its columns come from the
collection's schema (so the header row is identical between exports, even when a
batch left a field blank), and it carries no history and no visitor IP or user
agent. --format json is the lossless one: every field, with each submission's
events nested under it.
delete is permanent and cascades the submission's history. It needs a staff
role — a site user's API key gets a 403 — and it prompts for the id unless you
pass --yes. There is no equivalent in the admin UI, on purpose.
Builds
scribe build trigger <site>Dispatches the site's build workflow and returns immediately. Debounced to once
every five minutes. Prefer scribe site deploy, which waits for the build and
then checks the result.
Programmatic use
The API client and config helpers are exported for scripting:
import { ScribeClient, ScribeApiError } from '@scribe-platform/cli/client';
import { loadConfig } from '@scribe-platform/cli/config';
const config = loadConfig();
if (!config) throw new Error('Run `scribe login` first.');
const client = new ScribeClient(config);
const sites = await client.listSites();License
MIT
