Public noninteractive ScreenRig CLI and deterministic static-application packer.
Agents run the CLI bundled by screenrig/plugin from current main; developers
can build this checkout. This repository does not own plugin
installation, Players, backend services or the site. It is a public maintainer
guide: the optional workspace-parent AGENTS.md adds shared operational rules but
is not required to contribute.
src/and its tests define commands and behavior. Native Commander command definitions own arguments, choices and validation; help-only notes and examples live insrc/cli-commands/guidance.ts.src/media/owns the ffmpeg probe, transcode planner and progress reporter.package.jsondefines the executable, Node engine and scripts. The committed version stays0.1.0; CI stamps CalVer on the artifact (RELEASING.md).contracts.tomlnames the backend OpenAPI/protocol inputs;contracts.sha256pins their bytes, including the builtassets/screenrig.runtime.js. The OpenAPI is backend's public document (api/public/), which leaves out the staff routes;check:publicfails on any staff route in the tree.scripts/package-release.shbuilds the deterministicscreenrig-cli.tgz: readable, unminifieddist/bin.jsand the flatdist/*.jschunks it loads per command bundle (the plugin directory's security scan reviews the code as text), with the runtime dependencies inside (recorded inruntime-dependencies.lock.json), plusassets/. No bundled file may exceed 256 KiB (the Claude plugin directory reads no more), and the bundler fails on one. It cuts any chunk over 235,000 bytes into pieces by module path (scripts/bundle-release.mjs); a single module over the limit has to be split in source.scripts/check-release-artifact.mjsstates its inventory.- The bundler also fails on any pattern
scripts/directory-scan.mjslists: the Claude directory reads script text as shell and holds a plugin that seems to read a credential. Template literals ship as.concat()for that reason. In source: register asetorexportsubcommand withsubcommand(), never start a clause of a message with "pass" (write "name a file"), and read the environment only by name insrc/host-settings.ts. - Commands load on demand:
src/cli-commands/index.tsmaps each top-level command to a bundle insrc/bundles/, which registers its commands and imports their handlers fromsrc/handlers/;src/commands.tskeeps what bundles share. A new registration module joins a bundle there (the catalog test fails otherwise); help guidance loads only for help. .github/workflows/ci.ymlruns the public, test, package and secret gates;npm-release.ymlis the only npm publication path. Never publish from a laptop.
- Edit
src/, neverdist/. Never hand-editvendor/,assets/orsrc/generated/; refresh them from the workspace root withrig contracts sync cli.npm run vendor:checkis the offline gate andrig contracts check clicompares against backend origin/main. - Read
assets/only throughsrc/assets.ts. - Preserve unrelated work. Do not commit, push, tag or publish unless asked.
- Never PATH-swap a local checkout into an installed agent, and never
npm i -g screenrigas the agent path. cli/is public: no internal hosts, private origins or customer data, and never write MCP. The README must keep the exact[security policy](SECURITY.md)link.
- Fleet commands accept any number of screen ids or tag matches, follow the backend's bounded continuations under one action key, honor budget pauses and return every per-screen result. Never add a screen-count or fleet-page cap.
showinspects a resource,listreads a collection, K/V usesget/set, display names use--name, selectors use--screen-id,--app-id,--playlist-id,--release-id, revision guards use--expect-rev, event cursors use--after. The group isapp; prose says "application". Aliases and compatibility shims for old spellings or old servers are removed, not kept; only code that reads credentials or config files saved by released CLIs stays. Never rename backend fields to match flags.- Declare option relationships with
requireOptionGroupso human help, JSON help and preflight validation agree. Every command gets a working example, and help states write scope, waiting and recovery where relevant. Document stdin only where implemented. - Output is one envelope per invocation; progress goes to stderr.
agent enroll --email ADDRESS --organization NAMEis the only enrolling command. Other authenticated commands fail withnot_enrolled(exit 3); keep that code stable.- No part of a stored credential reaches stdout. Report presence through
hasToken/describeTokenPresence(present/(none)). media uploadtranscodes by default and requires external ffmpeg/ffprobe, which the CLI never bundles. H.264 is the default with no per-client fallback;--codec hevcis opt-in. Do not retune quality, bitrate or GOP values: they are a product decision.--no-transcodeuploads accepted source bytes unchanged but does not bypass the lossy-WebP delivery policy.doctorcheck status ispass,warnorfail; onlyfailmoves the exit code. A missing credential iswarnwithnext.command.- Playlist authoring: existing file,
media upload; presentable page,media generateas the whole page; live text, built-in cards; live objects, playlist primitives. Never emit nativetext,boxorline. - Server admission decides whether billed work (
media generate) proceeds, not the displayed balance; respectpayment_required. Add no pay, Stripe or x402 commands. - Optional
log_socketlives in the 0600 user config; there is no flag or env override, and a connect failure never fails the command.
npm ci
npm run check:public
npm run vendor:check
npm run check
npm run smoke:mock
npm run pack:dry
npm run pack:release
npm run check:npm-installnpm run smoke:server needs an explicitly owned local backend. To run this
checkout: npm run build && node ./dist/bin.js version.