Docs as code

Pushing

If someone may have edited source-owned records in the dashboard, preview and apply a pull before editing locally:

bash
askvoro pull --dry-run
askvoro pull

Pull writes only records already owned by this project's sourceId, using their recorded paths. It does not claim dashboard-only records and it does not delete local files.

bash
askvoro push

Reads every Markdown file in the project and creates or updates the matching articles and FAQs in your workspace.

Always dry run first#

bash
askvoro push --dry-run

Shows exactly what would be created, updated and deleted, and changes nothing. Cheap, fast, and the only reliable way to find out that a section.json typo was about to move forty articles.

Pushes are safe to repeat#

Push is idempotent: running it twice does the same thing as running it once. Unchanged files produce no writes at all, so a push from CI on every merge is fine even when the docs didn't change.

What push will not touch#

Every record the CLI creates is marked as CLI-owned, including the file path it came from. A record created only in the dashboard has no such mark, and push never updates or deletes it. Editing an already CLI-owned record in the dashboard does not change its ownership; pull preserves that edit locally, or a later push replaces it with the repository copy.

So you can safely keep both creation paths as long as source-owned edits are pulled before the repository is pushed.

Deleting#

Deleting a file does not delete the article. Push only adds and updates unless you ask for more:

bash
askvoro push --prune

--prune deletes CLI-owned records whose file has disappeared. Dashboard-written records are still never touched.

Two things to know:

Renaming a file is a delete plus a create. Records are matched by path, so renaming 01-install.md to 02-install.md with --prune deletes the original article and creates a new one. The content survives; the article's identity and its URL do not. Rename deliberately, and prefer leaving numeric gaps over renumbering a whole folder.

Pruning an empty folder is blocked. If every file has vanished — a bad working directory, a failed checkout, a wrong --dir — the CLI refuses rather than emptying your help center. Pass --allow-empty if you genuinely meant it.

Options#

FlagWhat it does
--dry-runReport what would change, write nothing
--pruneDelete CLI-owned records whose file is gone
--allow-emptyPermit a prune from an empty folder
--dir <path>Run against a different project folder
--origin <url>Override the origin from .askvoro

login --token sk_... validates and stores a dashboard-created key. Pull and push read stored credentials or ASKVORO_TOKEN; they do not accept a --token flag.

In CI#

Publish docs when they land on your main branch:

The npm package is not public yet. In this monorepo, CI can run the checked-in source command:

yaml
- name: Publish documentation
  run: bun run askvoro -- push --dir path/to/docs --prune
  env:
    ASKVORO_TOKEN: ${{ secrets.ASKVORO_TOKEN }}

Add --dry-run on pull requests to see documentation changes in review alongside the code change that caused them.

When something goes wrong#

Not a member of that workspace. The key was minted for a different workspace than the one in .askvoro.

Credentials rejected after changing .askvoro. Credentials are stored per origin and workspace id. Change either and you log in again.

Nothing happened. Check you're in the right folder — the CLI looks for .askvoro in the current directory or above it, so a push from the wrong subtree can quietly target a different project.

Dashboard edits disappeared after push. The dashboard edit was on a record owned by this source. Pull before editing when you want to keep remote changes; push intentionally makes the repository copy authoritative.