npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@playaos/cli

v0.1.0

Published

PlayaOS CLI — operate your Burning Man camp from the terminal or an AI agent

Readme

PlayaOS CLI

Operate your Burning Man camp from the terminal — or from an AI agent.

CI npm version node license

@playaos/cli is a zero-runtime-dependency TypeScript CLI (playaos) for querying a Burning Man camp through the PlayaOS REST API — members, applications, dues, shifts, and org config. It ships alongside an AI-agent skill pack generated from the same source, so the same capabilities are available to humans at a terminal and to LLM agents.

Every data command emits a single line of JSON and signals its outcome via exit code — built to be driven programmatically. (The exception is playaos help / --help / -h, which prints the plain-text usage string to stdout.)

Status: M0 (read-only). Write actions (approve applicant, shift signup, collect dues, send email) are planned for M1 behind a PLAYAOS_ALLOW_WRITES gate.


Technology Stack

| Concern | Choice | |---------|--------| | Language | TypeScript (ESM, node20 target) | | Runtime | Node.js >= 20 | | Package manager | pnpm (frozen lockfile in CI) | | Bundler | tsup — single dist/index.js with shebang | | Tests | Vitest | | Runtime dependencies | none (Node built-ins only: node:util, fetch, node:fs) | | CI | GitHub Actions (self-hosted), Graphite CI optimizer |


Project Architecture

Two products are built from one source tree:

                 ┌─────────────────────────┐
   argv ───────► │  src/index.ts  route()  │  dispatch on argv[2]
                 └────────────┬────────────┘
                              ▼
                 ┌─────────────────────────┐
                 │  src/commands/<name>.ts  │  thin: validate → fetch → filter → print
                 └──┬────────┬────────┬─────┘
                    ▼        ▼        ▼
            lib/args.ts  lib/auth.ts  lib/http.ts ──► PlayaOS REST API (/api/v1)
                    │        │        │
                    └────────┴────► lib/output.ts  ──► JSON envelope + exit code

Per-invocation flow in each command:

  1. Validate subcommand, then parseFlags / parseStrict (src/lib/args.ts, strict)
  2. resolveAuth() (src/lib/auth.ts)
  3. apiFetch() (src/lib/http.ts)
  4. Optional client-side filter (M0 stopgap)
  5. printOk(data) on success; die(err) in the catch

The three lib/ helpers are the single choke-points for their concern:

  • lib/auth.ts — resolves PLAYAOS_API_KEY + PLAYAOS_API_URL; redacts the key from any serialized output.
  • lib/http.ts — the only code that knows the wire format (/api/v1 prefix, Bearer auth, { error, code } bodies, Retry-After). Throws ApiError.
  • lib/output.ts — owns the JSON envelope and the exit-code contract.

This repo intentionally does not depend on @playaos/api-client; http.ts/auth.ts re-implement only the slices they need.

Skill pack

Two hand-edited skills live under skills/:

  • playaos — the full camp skill (members, applications, dues, shifts + the public gift layer). Needs a camp key (PLAYAOS_API_KEY).
  • playaos-public — the no-key public gift-layer skill (requires_env: []): events, art, packing list + catalog, directory, marketplace search, plus the optional PLAYAOS_USER_KEY writes. Built for zero-setup distribution.

build/skill.ts parses their frontmatter, and build/export-hermes.ts / build/export-openclaw.ts re-emit per-harness variants of both into dist/hermes/... and dist/openclaw/.... The dist/ copies are generated — never edit them by hand.


Getting Started

Prerequisites

Install (as a tool)

npm install -g @playaos/cli

Configure

export PLAYAOS_API_KEY=pk_live_your_key_here
# optional — defaults to https://api.playaos.app
export PLAYAOS_API_URL=https://your-camp.api.playaos.app

Use

playaos org get                            # camp config
playaos members list --status active       # members by status / role
playaos members get <id>                   # one member
playaos applications list --status pending  # applications by status / year
playaos dues list --status unpaid          # dues rows
playaos shifts list --open                 # shifts with open slots
playaos help                               # full usage

Build from source

git clone https://github.com/playaos/ai-toolkit.git
cd ai-toolkit
pnpm install
pnpm build        # → dist/index.js
pnpm test

Distribution

Install a skill into an AI agent

Generate the per-harness bundles, then hand a skill folder to your agent:

pnpm export        # → dist/hermes/... and dist/openclaw/...
pnpm pack:skills   # → dist/bundles/<harness>-<skill>.tar.gz

Each bundle is a self-contained SKILL.md + references/. Drop the folder into your agent's skills directory:

| Agent | Skill | Bundle | |-------|-------|--------| | Hermes | camp (needs PLAYAOS_API_KEY) | dist/hermes/productivity/playaos | | Hermes | public (no key) | dist/hermes/productivity/playaos-public | | OpenClaw / ClawHub | camp | dist/openclaw/playaos | | OpenClaw / ClawHub | public | dist/openclaw/playaos-public |

The -public bundle needs no API key — it works the moment the playaos CLI is installed. At launch, the same bundles are attached to each GitHub release (below) so users can install without cloning.

Publishing (maintainers)

Releases are cut by pushing a version tag; .github/workflows/release.yml does the rest:

git tag v0.1.0
git push origin v0.1.0

The workflow re-runs typecheck/test/build/export, publishes @playaos/cli to npm (--access public --provenance), and creates a GitHub release with the skill bundles attached. It is dormant until a tag is pushed and requires one repo secret:

  • NPM_TOKEN — an npm automation token with publish rights to the @playaos scope.

Output Contract

Stable — agents depend on it. Success goes to stdout, failure to stderr:

{ "ok": true,  "data": <array|object> }
{ "ok": false, "error": { "code": "<string>", "message": "<string>", "status"?: <number>, "retryAfter"?: <number> } }

error.status and error.retryAfter are optional: status is omitted for usage and network errors (no HTTP response), and retryAfter (seconds) is only set on rate_limit (429) responses.

| Exit | Meaning | code | Action | |------|---------|--------|--------| | 0 | success | — | parse stdout JSON | | 1 | network / generic API error | network / api_error | surface to user | | 2 | usage (bad flags, missing key) | usage | fix command / set PLAYAOS_API_KEY | | 3 | auth 401/403 | auth | check PLAYAOS_API_KEY | | 4 | not found 404 | not_found | verify the ID | | 5 | rate limit 429 | rate_limit | wait error.retryAfter s, retry once |


Project Structure

.
├── src/
│   ├── index.ts            # entrypoint + route() + USAGE
│   ├── commands/           # org, members, applications, dues, shifts (+ *.test.ts)
│   └── lib/                # auth, http, args, output, errors (+ *.test.ts)
├── skills/playaos/
│   ├── SKILL.md            # canonical agent skill (source of truth)
│   └── references/         # full command + flag reference
├── build/                  # skill.ts + export-hermes.ts + export-openclaw.ts
├── docs/plans/             # design + milestone implementation notes
├── install/                # hermes.sh, openclaw.sh installers
├── .github/workflows/ci.yml
├── CLAUDE.md               # guidance for AI coding agents
└── package.json

Key Features

  • Read-only camp queries — members, applications, dues, shifts, org config.
  • JSON-only, exit-code-driven output — first-class for scripting and AI agents.
  • Strict flag parsing — an unknown/valueless flag or stray positional is a usage error, never silently coerced.
  • Secret-safe — the API key is redacted from all serialized output.
  • Zero runtime dependencies — small, auditable, fast to install.
  • Dual-harness skill pack — one canonical skill exported for Hermes and OpenClaw.

Development Workflow

pnpm dev              # tsup --watch
pnpm typecheck        # tsc --noEmit
pnpm test             # vitest run
pnpm test:watch
pnpm build            # bundle to dist/
pnpm export           # regenerate skill pack (hermes + openclaw)

Run a single test:

pnpm vitest run src/commands/dues.test.ts
pnpm vitest run -t "filters by status"

CI gate (self-hosted, in order): typecheck → test → build → export. Reproduce locally by running those four. Branching uses Graphite-style stacks; the CI optimizer skips runs already covered by a parent PR.


Coding Standards

  • ESM with .js import specifiers in TypeScript source (from "./lib/auth.js") — required.
  • No console.log — all output flows through lib/output.ts.
  • Keep commands thin; concern ownership lives in the three lib/ choke-points.
  • M0 stopgaps carry Linear ticket refs in comments (client-side dues --status & shifts --open → PLA-777/778; no pagination → PLA-779). Keep these notes in sync across code, USAGE, and SKILL.md.

See CLAUDE.md for the full architecture and conventions reference.


Testing

Vitest, with tests co-located next to source (*.test.ts). Tests mock fetch and assert on both the JSON body and the exit code. The entrypoint checks VITEST=1 so importing route in a test never fires the CLI against the runner's argv.

pnpm test

Known Limitations (M0)

  • dues list --status and shifts list --open filter client-side — the full list crosses the wire (the API does not yet expose these filters; PLA-777 / PLA-778).
  • No pagination — list commands return the entire set; no --limit / --cursor yet (PLA-779).
  • Read-only — write actions land in M1 behind PLAYAOS_ALLOW_WRITES.

Contributing

  1. Follow the 5-step command shape above and the Coding Standards.
  2. Adding a command: create src/commands/<name>.ts, register it in route() and the USAGE string in src/index.ts, add src/commands/<name>.test.ts, and document it in skills/playaos/SKILL.md + references/commands.md.
  3. Ensure the CI gate passes locally: pnpm typecheck && pnpm test && pnpm build && pnpm export.
  4. Use existing commands (e.g. src/commands/dues.ts, src/commands/shifts.ts) as exemplars for structure, error handling, and client-side filtering.

License

MIT