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):
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:87872. Create packdog.json
In your pack's project root, run packdog init --id=<packageId> or create the file manually:
{
"packageId": "uuid-from-packdog"
}Commands
packdog login
Save a developer token globally. Run once — it then works from any directory.
packdog login dev_<token>packdog logout
Remove the saved token.
packdog logoutpackdog whoami
Show who you are logged in as and which packages you have access to.
packdog whoami
# Logged in as: finnolav
# Packages:
# shooter-game be027d3c-...
# quiz-pack 9f3a1b2c-...packdog --version
Show the CLI version.
packdog --version # or: packdog -vpackdog list
List the packages you have access to (name + ID). Run this first to find the ID for packdog init.
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.
packdog init --id=<packageId>packdog info
Show package name, ID, version count and active channels. Fetches the name from the registry.
packdog infopackdog 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.
packdog upload
# → Uploads files and publishes to stagepackdog publish
Publish a version to a channel. Defaults to the latest version and the stable channel.
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.
packdog rollback --channel=stable # rollback stable
packdog rollback --channel=stage # rollback stageRequires 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.
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:05packdog channels
List all active channels and their current versions.
packdog channelsTypical workflow
# 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=stableExit codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Usage error (missing argument, missing dist/, etc.) |
2 | Client error from the API (4xx other than 429) |
3 | Network error after retries exhausted |
4 | Upload succeeded but auto-publish to stage failed (the version id is still in the output) |
5 | Server 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
| Package | Purpose | Status |
|---|---|---|
packdog | CLI | Published — npm 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 timePrinciple
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:
{
"packageId": "05f90bb1-9d93-41b6-8ad3-0995ac2fef3d"
}Workflow
# 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.