CLI reference
Every graft command, grouped by when you use it.
Look up a command here. In a terminal, graft --help lists the commands and
graft <command> --help shows one command's usage and flags. To read graft's
output from a script or an agent, see Script the CLI.
This page is generated from the table the CLI's own help reads, so the two
always match. graft migrate and graft merge only report what they would
change until you pass --apply.
Set up a project
graft create
Make a new site: a template, a database, Studio and (by default) a Next.js app, installed and ready. npm create graft runs this. It asks a few questions; flags answer them, and --yes takes the defaults for the rest.
graft create [dir] [--template <name>] [--edit online|code] [--database new|none|<url>] [--framework next|nuxt|sveltekit|none] [--yes] [--no-install] [--no-input]
| Flag | What it does |
|---|---|
--template <name> | blog, docs, shop, portfolio or blank (default: blog). |
--edit online|code | online keeps content in the database, edited in Studio (default); code keeps it as files in git. |
--database new|none|<url> | new makes a free Postgres to claim later; none compiles content to a file (with --edit code); or your own Postgres 13+ URL. |
--framework next|nuxt|sveltekit|none | next for a Next.js site that shows every collection (default); nuxt or sveltekit for the same site in Nuxt or SvelteKit; none for only the content. |
-y, --yes | Use the default for every question a flag did not answer. |
--no-install | Write the files and stop before installing. |
--no-input | Never stop to ask a question. Same as GRAFT_PROMPT_DISABLED. |
Needs no database. May ask questions on a terminal; --no-input never does.
graft create my-site --template docs --edit code --database none --yes
graft init
Scaffold a Graft project in dir (default: here). The static engine is the default: no database and no environment variables.
graft init [dir] [--static] [--postgres] [--json]
| Flag | What it does |
|---|---|
--static | Static engine: no database, no env (the default). |
--postgres | Postgres engine: operational data, typed functions, database branching. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
graft doctor
Check this project's setup: the database, its schema, content, the index and Studio sign-in. Prints a checklist and the one thing to do next.
graft doctor [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Uses DATABASE_URL when it is set, and works without it. Prints its answer as JSON with --json.
| Exit code | What it means |
|---|---|
0 | Everything is set up. |
1 | Something is missing; the output says what to do next. |
graft add
Copy an owned primitive (and the primitives it needs) from the registry into graft/, and regenerate the graft/ barrel. graft.config.ts needs no edit. With no item, list the primitives you can add.
graft add [item...] [--dry-run] [--overwrite] [--json]
| Flag | What it does |
|---|---|
--dry-run | Show what would change without changing it. |
--overwrite | Replace files that differ from the registry's. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
graft add comments --dry-run
Write and check content
graft compile
Check every content file and build the index, once.
graft compile [--branch <id>] [--prune-unknown] [--json]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--prune-unknown | Remove index entries in collections the schema no longer has (default: refuse, which protects a shared DATABASE_URL). |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft compile --json > changes.json
graft dev
Watch content/ and graft.config.ts, and compile on every change.
graft dev [--branch <id>]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Runs until you stop it.
graft check
Check every content file the way a compile or a publish would: the schema, slug uniqueness, MDX safety, and references to documents that don't exist. Needs no database.
graft check [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
| Exit code | What it means |
|---|---|
1 | At least one file has a problem; each is listed. |
graft content
List every document; the same as graft content list.
graft content [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft content list
List documents with their slug, title and file. Reads the content files, or the database in a project whose content is kept there.
graft content list [collection] [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft content get
Print one document: its frontmatter, then its body, the way the file reads. With --json, the collection, slug, file path, data and body.
graft content get <collection/slug> [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft content get posts/launch > launch.mdx
graft content search
Search with words, "quoted phrases", or and -exclusions. Searches the compiled index, so results are as fresh as the last compile.
graft content search <query...> [--branch <id>] [--collection <name>] [--limit <n>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--collection <name> | Search one collection (default: all). |
--limit <n> | Most matches to print, best first (default: 20). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft content search pricing "free tier" --collection pages
graft content write
Write a document from an MDX file (--file), or from frontmatter as JSON (--data) and an optional body (--body-file). It is checked against the collection's schema and compiled, exactly as an agent's write_content is. A project whose content is kept in the database saves it as a draft.
graft content write <collection/slug> [--branch <id>] [--file <doc.mdx|->] [--data <json>] [--body-file <file|->] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--file <doc.mdx|-> | The whole document as an MDX file; - reads it from stdin. |
--data <json> | The frontmatter as a JSON object; - reads it from stdin. |
--body-file <file|-> | The body, with --data; - reads it from stdin. |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft content get posts/launch > launch.mdx
graft content write posts/launch --file launch.mdx
graft content set
Set one frontmatter field on each document named, each written as graft content write would. One document that fails does not stop the others. --value null removes the field.
graft content set <collection> <slug...> [--branch <id>] [--field <name>] [--value <json>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--field <name> | The frontmatter field to set. |
--value <json> | The new value as JSON; text that is not JSON is taken as a string. |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
| Exit code | What it means |
|---|---|
1 | At least one document was not saved; each is listed. |
graft content set posts launch roadmap --field tags --value '["2026"]'
graft content delete
Delete a document. The first run files an approval and exits 3 with its id. After a person runs graft approve <id>, run it again with --approval <id>.
graft content delete <collection/slug> [--branch <id>] [--approval <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--approval <id> | The approval a person granted for this delete. |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft compilations
List recent compiles and what each one changed.
graft compilations [--branch <id>] [--json]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft asset put
Upload a binary to the asset store (S3_* env) and print the frontmatter reference. The key defaults to assets/<file name>. A key that already holds a file is refused with ASSET_EXISTS, because the store keeps no version history.
graft asset put <file> [key] [--overwrite] [--json]
| Flag | What it does |
|---|---|
--overwrite | Replace the file already stored under the key. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
graft asset put ./hero.png assets/hero.png
graft drafts
List unpublished drafts, for content kept in the database.
graft drafts [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft drafts publish
Publish drafts by path (from graft drafts). On a site that reviews changes, this asks for a review instead. A path someone else published since is refused with CONTENT_CONFLICT; --resolve <path>=mine or =theirs settles it.
graft drafts publish <path...> [--branch <id>] [--message <text>] [--resolve <path>=mine|theirs]... [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--message <text> | The commit or review title. |
--resolve <path>=mine|theirs | Settle a conflict on one path. Repeat it for more than one. |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft drafts discard
Throw away drafts, back to the published version.
graft drafts discard <path...> [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
Look into the project
graft schema
Print each collection's fields, and the typed functions.
graft schema [collection] [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft fn
List the typed functions.
graft fn [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft fn describe
Print one function's input schema and access rules.
graft fn describe <name> [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft fn run
Run a function through the same checks as POST /api/fn/<name>: input validation, access rules, rate limits, the audit log, and the approval a destructive function needs (exit 3, then --approval <id>).
graft fn run <name> [--branch <id>] [--input <json|->] [--approval <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--input <json|-> | The input as a JSON object; - reads it from stdin (default: {}). |
--approval <id> | The approval a person granted for this call. |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft explain
Explain an error code: what it means and how to recover.
graft explain <code> [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
graft explain SCHEMA_VALIDATION_FAILED
graft mcp tools
List the MCP tools an agent sees for this project.
graft mcp tools [--branch <id>] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft mcp call
Call any MCP tool by name, as an agent would.
graft mcp call <tool> [--branch <id>] [--input <json|->] [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--input <json|-> | The tool's input as a JSON object; - reads it from stdin (default: {}). |
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL on the Postgres engine; none on the static engine. Prints its answer as JSON with --json.
graft mcp call list_content --input '{"collection":"posts"}'
Run Graft
graft mcp
Serve the project MCP over stdio: content and function tools, for .mcp.json and other local agents. On the Postgres engine it needs DATABASE_URL.
graft mcp [--branch <id>] [--elicit-approvals]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--elicit-approvals | Ask this terminal's operator to decide a destructive call, instead of failing with an id for graft approve. |
Needs DATABASE_URL on the Postgres engine; none on the static engine.
graft serve
Run the headless Graft runtime over HTTP: POST /api/fn/<name>, POST /api/mcp, GET /api/content/v1/*, GET /healthz. This is what a self-hosted container runs.
graft serve [--branch <id>] [--port <n>] [--host <host>] [--studio] [--max-body-bytes <n>]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--port <n> | Port to listen on (default: 3903). Same as PORT. |
--host <host> | Host to listen on (default: 127.0.0.1, this computer only). Same as HOST. |
--studio | Serve Studio at /studio too. Same as GRAFT_STUDIO. |
--max-body-bytes <n> | Largest request body any route reads (default: 1 MiB, and 32 MiB for MCP). Same as GRAFT_MAX_BODY_BYTES. |
Needs DATABASE_URL. Runs until you stop it.
graft studio
Run Studio: edit content, approve or deny actions, and read the OpenAPI document. Without a database, saves go to your files.
graft studio [--branch <id>] [--port <n>] [--host <host>]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--port <n> | Port to listen on (default: 4983). Same as GRAFT_STUDIO_PORT. |
--host <host> | Host to listen on (default: 127.0.0.1, this computer only). Same as HOST. |
Uses DATABASE_URL when it is set, and works without it. Runs until you stop it.
graft studio invite
Print a sign-in link for someone without a GitHub account. It is signed with GRAFT_STUDIO_SECRET and expires after --days. To give someone an account instead, invite them from Studio's Settings.
graft studio invite <email> [--role <role>] [--name <name>] [--days <n>] [--url <url>] [--json]
| Flag | What it does |
|---|---|
--role <role> | viewer, contributor, editor (default) or admin. |
--name <name> | The name commits are attributed to. |
--days <n> | How long the link works, 1 to 30 (default: 7). |
--url <url> | Where Studio is served. Same as GRAFT_STUDIO_URL. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
graft studio setup-code
Print the code a hosted Studio asks for before it creates the owner account. It comes from GRAFT_STUDIO_SECRET, so run it with the site's settings.
graft studio setup-code
Needs no database.
Keep content in the database
graft content import
For a project with content = { source: "database" }: load the files under the content directory into the database. Every file is checked first. Only documents with nothing published come in: a published document is never overwritten, and a missing file deletes nothing. To change published content, use Studio or graft push.
graft content import [--branch <id>] [--dry-run] [--json]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--dry-run | Show what would change without changing it. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft pull
For a project with content = { source: "database" }: write what is published into the files under the content directory. A file you changed since your last pull is kept for graft push. One changed both here and in the database is left as it is and listed, unless --force takes the published version.
graft pull [doc...] [--branch <id>] [--only <doc>]... [--force] [--json]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--only <doc> | Only this document, like posts/launch (same as naming it as an argument). Repeat it for more than one. |
--force | Settle a conflict: pull takes the published version, push publishes yours. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft pull posts/launch
graft push
Publish the files you changed since your last graft pull, checked as graft compile checks them. Refused, with nothing written, if someone published one of those documents since your pull: pull first. --force publishes over it.
graft push [doc...] [--branch <id>] [--only <doc>]... [--dry-run] [--force] [--json]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--only <doc> | Only this document, like posts/launch (same as naming it as an argument). Repeat it for more than one. |
--dry-run | Show what would change without changing it. |
--force | Settle a conflict: pull takes the published version, push publishes yours. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft mirror
Commit everything published since the last run to the GitHub repository in GRAFT_GITHUB_REPO, as one commit. Run it on a schedule, or let graft serve do it when graft.config.ts sets content.mirror.
graft mirror [--branch <id>] [--json]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
Manage the database
graft db migrate
Apply the Postgres schema migrations that ship with @usegraft/db. This is the first command a Postgres-engine project runs.
graft db migrate [--dry-run] [--json]
| Flag | What it does |
|---|---|
--dry-run | List pending schema migrations without applying them. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft db claim
Keep the free database graft create --database new made. Prints the link to claim it (a free Neon account), waits until you have, then asks for the new connection string and saves it to .env. Claiming changes the password, so the old DATABASE_URL stops working.
graft db claim [--url <postgres-url>] [--no-input]
| Flag | What it does |
|---|---|
--url <postgres-url> | The claimed database's connection string, instead of the question. |
--no-input | Never stop to ask a question. Same as GRAFT_PROMPT_DISABLED. |
Needs no database. May ask questions on a terminal; --no-input never does.
graft migrate
Show pending content and data migrations. --apply runs them and records each in the ledger. A concurrent --apply on the same branch waits for this one and then skips what it applied.
graft migrate [--branch <id>] [--apply] [--json]
| Flag | What it does |
|---|---|
-b, --branch <id> | Content branch to work on (default: main). |
--apply | Make the change (without it, only report what would change). |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft harden
Grant an existing Postgres role the runtime privilege set: it can request and consume approvals but never decide them.
graft harden <role> [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
Approve actions
graft approvals
List actions waiting for a person to approve them.
graft approvals [--json] [--remote] [--local]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
--remote | Work on the hosted site in GRAFT_URL, or the one graft login saved. |
--local | Work on the project in this folder, even when GRAFT_URL is set. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft approve
Approve an action; the caller then repeats its call with the id.
graft approve <approval-id> [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft deny
Deny an action.
graft deny <approval-id> [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
Work with preview branches
graft branch
List branches.
graft branch [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft branch create
Create a preview branch.
graft branch create <name> [--from <parent>] [--backend overlay|neon] [--json]
| Flag | What it does |
|---|---|
--from <parent> | Branch to fork from (default: main). |
--backend overlay|neon | overlay (default) shares the parent's rows; neon forks a physical Neon branch. |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft branch drop
Delete a branch: purge an overlay's rows, or delete a Neon fork.
graft branch drop <name> [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
graft merge
Merge a branch: replay its migrations, move its data, recompile.
graft merge <branch> [--into <target>] [--apply] [--json]
| Flag | What it does |
|---|---|
--into <target> | Branch to merge into (default: main). |
--apply | Make the change (without it, only report what would change). |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs DATABASE_URL. Prints its answer as JSON with --json.
Keep CI cheap
graft ci changes
Print content-only=true when every changed file is content, and write it to $GITHUB_OUTPUT for later steps to read.
graft ci changes [--base <ref>] [--json]
| Flag | What it does |
|---|---|
--base <ref> | Git ref to compare against (default: the pull request's base, the host's previous deploy, or the commit a push started from). |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
graft ci skip-build
Exit 0 when the deploy can be skipped: only content changed, and the site already serves it from the database. Never skips on the previous commit alone.
graft ci skip-build [--base <ref>] [--json]
| Flag | What it does |
|---|---|
--base <ref> | Git ref to compare against (default: the pull request's base, the host's previous deploy, or the commit a push started from). |
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
| Exit code | What it means |
|---|---|
0 | Skip the build. |
1 | Build. |
graft ci init
Write a workflow that runs graft check on content changes.
graft ci init [--overwrite]
| Flag | What it does |
|---|---|
--overwrite | Replace the workflow file if it exists. |
Needs no database.
Work with a hosted site
graft login
Check a token against a hosted Graft site and save it, so commands that take --remote and graft api can use it. Make the token in Studio under Developer, Agents. It is read from stdin, or asked for without echoing it, never taken as an argument. No token can approve or deny an action.
graft login <url> [--with-token] [--json] [--no-input]
| Flag | What it does |
|---|---|
--with-token | Read the token from stdin (the default when stdin is not a terminal). |
--json | Print one JSON object on stdout; messages go to stderr. |
--no-input | Never stop to ask a question. Same as GRAFT_PROMPT_DISABLED. |
Needs no database. Prints its answer as JSON with --json. May ask questions on a terminal; --no-input never does.
printf %s "$TOKEN" | graft login https://cms.example.com --with-token
graft logout
Remove a site's saved token (default: the default site). The token itself keeps working until someone revokes it in Studio under Developer, Agents.
graft logout [url] [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
graft auth status
List every site the CLI can reach, from graft login and GRAFT_URL, and check each token against the site. Tokens are shown by their first characters only.
graft auth status [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
| Exit code | What it means |
|---|---|
0 | At least one token works, or --json was given. |
4 | No token works, or there is none. |
graft auth token
Print a site's saved token, for piping into another tool.
graft auth token [url]
Needs no database.
graft api
Call a route on the site in GRAFT_URL, or the one graft login saved. A path is under /api/studio/v1 unless it starts with /api/fn or /api/content/v1. Fields make the request a POST with a JSON body; with -X GET or --paginate they become the query string. Prints the answer; with no path, lists the routes.
graft api [path] [--method <method>] [--raw-field <key=value>]... [--field <key=value>]... [--header <name: value>]... [--input <file|->] [--include] [--paginate] [--slurp] [--yes] [--no-input]
| Flag | What it does |
|---|---|
-X, --method <method> | The HTTP method (default: GET, or POST when there are fields or --input, unless --paginate). |
-f, --raw-field <key=value> | A field whose value is sent as a string. Repeat it for more than one. |
-F, --field <key=value> | A field whose value is typed: true, false, null and numbers as JSON, @file and @- as the file's text. Repeat it for more than one. |
-H, --header name: value> | An extra request header. Repeat it for more than one. |
--input <file|-> | Send this file as the body; - reads stdin. |
-i, --include | Print the status line and headers before the body. |
--paginate | GET every page, following nextCursor, and print each one. |
--slurp | With --paginate, print every page as one JSON array once the last arrives. |
-y, --yes | Send -X DELETE without asking first. |
--no-input | Never stop to ask a question. Same as GRAFT_PROMPT_DISABLED. |
Needs no database. May ask questions on a terminal; --no-input never does.
graft api workspace
graft api entries -X GET -f collection=posts -F limit=20
graft api entries -f collection=posts --paginate
graft api entries --paginate --slurp
graft api -X PUT entry --input entry.json
Learn the CLI
graft help
Show help for a command or a topic.
graft help [command-or-topic...]
Needs no database.
graft help branch create
graft help exit-codes
graft commands
List every command; --json describes each one and its flags.
graft commands [--json]
| Flag | What it does |
|---|---|
--json | Print one JSON object on stdout; messages go to stderr. |
Needs no database. Prints its answer as JSON with --json.
Exit codes
Every command exits with one of these, unless its entry above lists its own.
| Exit code | What it means |
|---|---|
0 | It worked. |
1 | It failed; the error says why and what to do. |
2 | The command was called wrong: an unknown command or flag, or a missing argument. Nothing ran. |
3 | A person has to approve the action first. Run graft approve <id>, then repeat it. |
4 | The credential is missing, wrong, or lacks the access this needs. |
Environment variables
These change how the CLI behaves. Your project's own settings are on the Configuration page.
| Variable | What it does |
|---|---|
DATABASE_URL | The Postgres database. Read from the environment, or from .env in this folder or any folder above it. |
GRAFT_DEBUG | Set to 1 to print the stack trace of an unexpected error. |
GRAFT_URL | A hosted site for commands that take --remote; when set, they use it without the flag. Read from the environment only, never from .env. |
GRAFT_TOKEN | The token for GRAFT_URL, instead of the one graft login saved. |
XDG_CONFIG_HOME | Where graft login keeps tokens, under graft/hosts.json (default: ~/.config). |
GRAFT_PROMPT_DISABLED | Set to 1 to never ask a question, as --no-input does. |
GRAFT_NO_UPDATE_CHECK | Set to 1 to never check npm for a newer Graft. Also read from .env. |
CI | When set, the update check is off. |
NO_COLOR | When set, never print color. |
FORCE_COLOR | When set, print color even when the output is not a terminal. |
CLICOLOR | Set to 0 to turn color off on a terminal. |
CLICOLOR_FORCE | Same as FORCE_COLOR. |
TERM | dumb turns color off. |
XDG_CACHE_HOME | Where the update check caches its answer, under graft/ (default: ~/.cache). |
npm_config_registry | The npm registry the update check asks. |
Which commands need a database
Graft reads .env from the current folder or any folder above it.
- Always need
DATABASE_URL:graft compilations,graft drafts,graft drafts publish,graft drafts discard,graft serve,graft content import,graft pull,graft push,graft mirror,graft db migrate,graft migrate,graft harden,graft approvals,graft approve,graft deny,graft branch,graft branch create,graft branch drop,graft merge. - Need it on the Postgres engine only:
graft compile,graft dev,graft content,graft content list,graft content get,graft content search,graft content write,graft content set,graft content delete,graft schema,graft fn,graft fn describe,graft fn run,graft mcp tools,graft mcp call,graft mcp. - Use it when it is set:
graft doctor,graft studio. - Never need it:
graft create,graft init,graft add,graft check,graft asset put,graft explain,graft studio invite,graft studio setup-code,graft db claim,graft ci changes,graft ci skip-build,graft ci init,graft login,graft logout,graft auth status,graft auth token,graft api,graft help,graft commands.