CLI reference
The OpenDocs CLI is the supported integration layer for AI agents, scripts, and humans working from Markdown files.
npm install -g @opendocs.cc/cli
opendocs login --browser
For non-interactive agents and CI, prefer:
export OPENDOCS_API_KEY=od_live_xxxxx
opendocs whoami --json
Global options
| Option | Applies to | Notes |
|---|---|---|
--json | All commands | Machine-readable stdout. Errors are written to stderr as JSON when possible. |
--api-url <url> | All commands | Override the default API host, https://api.opendocs.cc. |
-h, --help | All commands | Show command help. |
-V, --version | Root command | Show CLI version. |
Environment variables:
| Variable | Notes |
|---|---|
OPENDOCS_API_KEY | API key used by opendocs login and commands in headless environments. |
OPENDOCS_API_URL | Default API URL override for local/staging environments. |
OPENDOCS_WEB_URL | Web app URL override for opendocs login --browser. |
Exit behavior
| Exit code | Meaning |
|---|---|
0 | Command succeeded. For batch commands, all items succeeded. |
| Non-zero | Command failed, or a batch completed with at least one failed item. |
In --json mode, successful commands write one JSON object to stdout. Errors
write a JSON object to stderr when the CLI can classify the failure:
{ "error": "document_limit", "message": "Your free plan has 0 slots left." }
opendocs login
Authenticate and store local config in ~/.config/opendocs/config.json.
opendocs login --browser
opendocs login --key od_live_xxxxx
OPENDOCS_API_KEY=od_live_xxxxx opendocs login
opendocs login --browser opens OpenDocs in your browser and creates a
normal API key after you approve the CLI. If you are already signed in, the
browser shows the current account and workspace so you can confirm you are not
authorizing the wrong account. Use --key or OPENDOCS_API_KEY for agents,
CI, SSH sessions, and other headless environments.
Do not run bare opendocs login from an agent. Without --key or
OPENDOCS_API_KEY, it waits for an interactive hidden prompt.
Useful flags:
| Flag | Notes |
|---|---|
--browser | Open a browser and authorize the CLI from your signed-in OpenDocs account. |
--key <key> | API key to validate and store. |
--web-url <url> | Override the web app used by --browser; useful for local/staging. |
--json | Print the saved account/workspace state as JSON. |
JSON shape:
{
"success": true,
"apiUrl": "https://api.opendocs.cc",
"userId": "usr_123",
"username": "ada",
"workspaceId": "ws_123",
"workspaceName": "Acme Docs",
"workspaceSlug": "acme-docs"
}
opendocs whoami
Show the authenticated account, active workspace, active project, API URL, and quota.
opendocs whoami --json
JSON shape:
{
"userId": "usr_123",
"onboarding": {
"username": "ada",
"workspace": {
"id": "ws_123",
"name": "Acme Docs",
"slug": "acme-docs"
}
},
"quota": {
"documents": {
"plan": "pro",
"limit": null,
"used": 42,
"remaining": null
}
}
}
Agents should use this before publishing when they need to confirm the active workspace, active project, or quota.
opendocs project
Manage projects in the active workspace. Projects let agents keep a related batch of documents separate from the workspace Default project.
opendocs project list --json
opendocs project current --json
opendocs project create "Launch docs" --slug launch-docs --use --json
opendocs project use launch-docs --json
opendocs project rename launch-docs --name "Launch documentation" --json
opendocs project delete launch-docs --yes --json
Default project documents use /workspace/slug. Non-default projects use
/workspace/projects/project/slug. Deleting a project only works when it is
non-default and empty.
opendocs publish
Publish one or more Markdown files.
opendocs publish doc.md --json
opendocs publish docs/*.md --tags api-docs --json
opendocs publish ./vault --tags obsidian-import --json
opendocs publish report.md --export pdf --json
Flags:
| Flag | Notes |
|---|---|
--title <title> | Override title. Single-file only. |
--slug <slug> | Request a custom slug. Single-file only. |
--visibility <level> | private, workspace, or public. Defaults to workspace. |
--confirm-public | Required with --visibility public. |
--tags <tags> | Comma-separated tags. Max 20 tags per post. |
--project <slug-or-id> | Publish to a specific project instead of the active project. |
--export <format> | Export successful publishes to pdf or docx. |
--json | Recommended for agents. |
Limits:
| Limit | Value |
|---|---|
| Markdown size per file | 1 MB |
| Files per CLI invocation | 500 |
| Documents per publish API batch | 25, auto-chunked by the CLI |
| Local images per document | 30 |
| Local image size | 10 MB each |
Folder inputs are scanned recursively. The CLI publishes .md files and skips
.obsidian, .trash, .git, and node_modules, which makes Obsidian vault
imports a single command.
Single-file JSON:
{
"postId": "post_123",
"slug": "launch-note",
"url": "/acme-docs/launch-note",
"title": "Launch note",
"projectSlug": "default",
"tags": ["launch"]
}
Batch JSON:
{
"total": 2,
"succeeded": 2,
"failed": 0,
"results": [
{
"success": true,
"file": "docs/intro.md",
"postId": "post_123",
"slug": "intro",
"url": "/acme-docs/intro",
"title": "Intro"
}
]
}
Publish-plus-export JSON includes an export block with local output paths:
{
"postId": "post_123",
"url": "/acme-docs/report",
"export": {
"format": "pdf",
"path": "report.pdf"
}
}
opendocs update
Create a new version of an existing published post while keeping the same URL.
opendocs update revised.md --post-id launch-note --json
--post-id accepts either the UUID or slug. Slug inputs are resolved inside the
active project.
Flags:
| Flag | Notes |
|---|---|
--post-id <id-or-slug> | Required. |
--title <title> | Override the title. |
--visibility <level> | Optional. Omit to preserve current visibility. |
--confirm-public | Required when changing to public. |
--tags <tags> | Replace tags with this comma-separated list. Omit to preserve current tags. |
JSON shape:
{
"postId": "post_123",
"versionId": "ver_456",
"versionNumber": 4,
"slug": "launch-note",
"title": "Launch note",
"visibility": "workspace",
"tags": ["release"]
}
opendocs list
List posts authored by the signed-in user.
opendocs list --json
opendocs list --all --limit 100 --json
opendocs list --tag api-docs --json
Flags:
| Flag | Notes |
|---|---|
--page <n> | Defaults to 1. |
--limit <n> | Defaults to 20, max 100. |
--tag <tag> | Filter by normalized tag. |
--all | List across all workspaces. Default is active workspace only. |
JSON shape:
{
"posts": [
{
"id": "post_123",
"title": "Launch note",
"slug": "launch-note",
"visibility": "workspace",
"isPublished": true,
"workspaceId": "ws_123",
"workspaceSlug": "acme-docs",
"tags": ["release"],
"updatedAt": "2026-04-25T12:00:00.000Z"
}
],
"pagination": {
"page": 1,
"limit": 20,
"total": 1,
"totalPages": 1
},
"scope": "workspace",
"workspaceSlug": "acme-docs"
}
opendocs get
Inspect one post by UUID or slug.
opendocs get launch-note --json
JSON shape:
{
"post": {
"id": "post_123",
"slug": "launch-note",
"title": "Launch note",
"url": "/acme-docs/launch-note",
"visibility": "workspace",
"isPublished": true,
"versionNumber": 4,
"tags": ["release"]
}
}
opendocs pull
Download raw Markdown for one post, one project, or the active workspace.
opendocs pull launch-note
opendocs pull launch-note --output docs/launch-note.md
opendocs pull launch-note --stdout
opendocs pull --project --output ./docs
opendocs pull --project launch-docs --tag release
opendocs pull --workspace --output ./opendocs
opendocs pull --workspace --dry-run
For single-post pulls, --output is a file path. For bulk pulls, --output
is a directory. Project pulls write files directly into that directory.
Workspace pulls write Default project docs at the root and non-default project
docs under projects/<project-slug>/.
Bulk pulls refuse to overwrite existing files unless --overwrite is passed.
Use --dry-run to preview the file plan before writing.
Flags:
| Flag | Notes |
|---|---|
--output <path> | Destination file for one post, or destination directory for bulk pulls. |
--stdout | Print one post's Markdown to stdout. Useful for agents. |
--project [slug-or-id] | Pull the active project, or a specific project. |
--workspace | Pull every project in the active workspace. |
--tag <tag> | Filter bulk pulls by tag. |
--overwrite | Replace existing files during bulk pulls. |
--dry-run | Preview a bulk pull without writing files. |
opendocs export
Export one or more published posts to PDF or DOCX.
opendocs export launch-note --format pdf
opendocs export intro guide api --format pdf --output ./exports
Flags:
| Flag | Notes |
|---|---|
-f, --format <format> | pdf or docx. |
-o, --output <path> | File path for one export; directory for batch export. |
--stdout | Binary stdout. Single post only. |
--landscape | Landscape PDF. |
--accent-color <hex> | Override export accent color. |
Batch export accepts up to 10 post IDs/slugs per command.
opendocs visibility
Change who can read a post without uploading new Markdown.
opendocs visibility launch-note private
opendocs visibility launch-note workspace
opendocs visibility launch-note public --confirm-public
Levels: private, workspace, public.
opendocs unpublish
Hide a post without deleting its content or version history.
opendocs unpublish launch-note
Unpublishing is reversible by publishing again, and it frees a Free-plan document slot because quota counts only currently published posts.
opendocs delete
Permanently delete a post.
opendocs delete launch-note --yes
Use --yes or -y from agents and scripts. Without it, non-interactive
contexts fail with confirm_required before making a network call.
opendocs workspace list
List workspaces the account belongs to.
opendocs workspace list --json
opendocs workspace ls --json
JSON shape:
{
"workspaces": [
{
"id": "ws_123",
"name": "Acme Docs",
"slug": "acme-docs",
"role": "owner"
}
],
"activeSlug": "acme-docs"
}
opendocs workspace use
Switch the active workspace in local CLI config.
opendocs workspace use acme-docs --json
opendocs workspace switch acme-docs --json
JSON shape:
{
"success": true,
"workspaceId": "ws_123",
"workspaceName": "Acme Docs",
"workspaceSlug": "acme-docs"
}
Switching is local only. It does not affect the dashboard's active workspace.
opendocs agent
Print static, package-bundled instructions for AI agents. This command does not require login and does not fetch remote content.
opendocs agent # concise, high-signal reference
opendocs agent --full # full bundled SKILL.md
opendocs agent --api # API-only reference
opendocs agent --cli # CLI-only reference
With --json, the response shape is:
{
"variant": "api",
"version": "0.1.x",
"content": "# OpenDocs Public API Agent Reference\n..."
}
opendocs logout
Remove local credentials.
opendocs logout
Common CLI errors
| Error | Recovery |
|---|---|
auth_expired | Create a new API key and run opendocs login --key .... |
document_limit | Upgrade, unpublish old docs, or publish only the files that fit. |
doc_too_large | Split the Markdown file. |
too_many_files | Split a >500-file publish into multiple invocations. |
too_many_posts | Split export batches into groups of 10. |
confirm_public_required | Re-run with --confirm-public only after explicit consent. |
confirm_required | Add --yes for delete in non-interactive contexts. |
not_a_member | Run opendocs workspace list --json, choose an available slug, then switch. |
image_upload_failed | Fix or remove the local image reference and retry. |
export_failed | Retry opendocs export; the publish usually already succeeded. |