Skip to content

Packdog CLI

Framework-agnostic CLI for uploading, publishing, and managing packs against the Packdog API at api.packdog.dev/v1.

Setup

1. Set your API token

Log in globally (recommended — works from any directory):

bash
packdog login dev_<your-developer-token>

The token is stored in ~/.config/packdog/config.json and is never at risk of being committed to GitHub.

Alternatively, put PACKDOG_TOKEN in .env at the project root:

PACKDOG_TOKEN=dev_<your-developer-token>

Developer tokens (dev_...) provide scoped access to the packages you have been assigned. Get the token from your admin.

Token resolution order: environment variable → .env / .env.development~/.config/packdog/config.json

For local development against wrangler dev, also set:

PACKDOG_URL=http://localhost:8787

2. Create packdog.json

In your pack's project root, run packdog init --id=<packageId> or create the file manually:

json
{
  "packageId": "uuid-from-packdog"
}

Commands

packdog login

Save a developer token globally. Run once — it then works from any directory.

bash
packdog login dev_<token>

packdog logout

Remove the saved token.

bash
packdog logout

packdog whoami

Show who you are logged in as and which packages you have access to.

bash
packdog whoami
# Logged in as: finnolav
# Packages:
#   shooter-game           be027d3c-...
#   quiz-pack              9f3a1b2c-...

packdog --version

Show the CLI version.

bash
packdog --version   # or: packdog -v

packdog list

List the packages you have access to (name + ID). Run this first to find the ID for packdog init.

bash
packdog list
# Packages:
#   shooter-game                   be027d3c-747d-4080-a854-d9f12aa32a2f
#   quiz-pack                      9f3a1b2c-...

packdog init

Set up packdog.json for an existing package. Validates that your token has access before writing the file.

bash
packdog init --id=<packageId>

packdog info

Show package name, ID, version count and active channels. Fetches the name from the registry.

bash
packdog info

packdog upload

Upload all files from dist/ as a new version. Your build tool (Vite, webpack, etc.) must produce dist/ with an index.js entry point.

Automatically publishes to the stage channel after upload — no extra step needed.

bash
packdog upload
# → Uploads files and publishes to stage

packdog publish

Publish a version to a channel. Defaults to the latest version and the stable channel.

bash
packdog publish                          # latest → stable
packdog publish --channel=beta           # latest → beta
packdog publish --version=<id>           # specific version → stable
packdog publish --channel=beta --version=<id>

Requires can_publish permission when using a developer token.

packdog rollback

Roll back a channel to its previous version. Each call steps one version back. --channel is required.

bash
packdog rollback --channel=stable        # rollback stable
packdog rollback --channel=stage         # rollback stage

Requires can_publish permission when using a developer token.

packdog versions

List all versions for the pack (newest first). Shows which channels are active on each version.

bash
packdog versions
#   abc-123...  1 file   45.2 KB  2026-04-04 10:22  [stable, stage]
#   def-456...  1 file   44.8 KB  2026-03-28 14:05

packdog channels

List all active channels and their current versions.

bash
packdog channels

Typical workflow

bash
# See which packages you have access to
packdog list

# Set up the local repo for a package
packdog init --id=<packageId>

# Build your pack (project-specific)
npm run build

# Upload — auto-publishes to stage
packdog upload
# → Uploaded: abc-123-def
# → Published to stage: abc-123-def

# Test on stage, then promote to stable
packdog publish
# → Published to stable: abc-123-def

# Something wrong? Roll back (--channel required)
packdog rollback --channel=stable

Exit codes

CodeMeaning
0Success
1Usage error (missing argument, missing dist/, etc.)
2Client error from the API (4xx other than 429)
3Network error after retries exhausted
4Upload succeeded but auto-publish to stage failed (the version id is still in the output)
5Server error after retries (5xx) or unparseable response

Network errors and 5xx/429 responses are retried up to 3 times with exponential backoff before the CLI gives up. Use these codes in CI scripts to distinguish transient infra issues (3, 5) from configuration mistakes (1, 2) from partial successes (4).


npm strategy

PackagePurposeStatus
packdogCLIPublishednpm install -g packdog
@packdog/*Future packages (vite-plugin, create, etc.)Planned

Install globally: npm install -g packdog


Monorepo / multi-pack setup

If you have several packs in the same repo (e.g. a packs monorepo), use this pattern:

Structure

my-monorepo/
  src/packs/
    shooter/
      packdog.json    ← pack-specific (committed)
      config.json     ← build config (Vite, etc.)
      index.svelte
    quiz/
      packdog.json
      config.json
      index.svelte
  dist/               ← gitignored, one pack at a time
  packdog.json        ← gitignored, copied from the active pack at build time

Principle

The CLI is "dumb" — it always reads packdog.json and dist/ from the current working directory. The build script sets context by copying the chosen pack's packdog.json to the project root.

packdog.json per pack

Each pack has its own packdog.json in its directory:

json
{
  "packageId": "05f90bb1-9d93-41b6-8ad3-0995ac2fef3d"
}

Workflow

bash
# Build copies packdog.json to the root and produces dist/
npm run build -- --pack=shooter

# CLI reads packdog.json from the root
packdog upload
packdog publish

# Dev server
npm run serve -- --pack=shooter

.gitignore

The root-level packdog.json should be gitignored in monorepos (it is generated by the build). The pack-specific src/packs/*/packdog.json files are committed.

Packdog runs on Cloudflare Workers, D1, and R2.