CLI workflows
Use the CLI yourself or let your coding agent run it. Start with an authoring project to change an app, or a writable .pop document to work with its data.
Responses below use example paths and compact JSON. Versions, timings, generated IDs, installed templates and palettes vary. Larger responses are explicitly marked as excerpts. Shell commands such as cd succeed without printing a response.
Choose how to run commands
Section titled “Choose how to run commands”Install Bun 1.4.2 or newer. To open document windows, install the pop Mac app. The examples below use bunx @hitslop/pop.
| Entry point | When to use it |
|---|---|
bunx @hitslop/pop COMMAND |
Run the authoring CLI without a global install. |
pop COMMAND |
After bun install -g @hitslop/pop, with Bun’s bin directory on your PATH. |
Use bunx or pop for the examples below. Authoring builds, registering, browser preview, document creation and document edits run on macOS or Linux. On both platforms the CLI also renders template artwork and exports closed documents as PNG/PDF itself. Opening a window uses the installed Mac app, which need not already be running.
The npm package includes its document engine, which does that rendering. open finds the Mac app automatically in /Applications or ~/Applications.
Append --help to any command to see its arguments.
Create, preview, and register an app
Section titled “Create, preview, and register an app”bunx @hitslop/pop init weekend-kitcd weekend-kitbun installbun run checkbun run devExpected terminal responses (build-tool progress omitted):
| Command | Response |
|---|---|
init weekend-kit |
After the brief and author questions: Created /Users/you/weekend-kit. Run bun install in that directory, then bun run dev. Then choose an agent. |
cd weekend-kit |
No output on success. |
bun install |
Bun’s dependency installation summary; package counts and timing vary. |
bun run check |
svelte-check found 0 errors and 0 warnings for a valid starter. |
bun run dev |
Disposable preview: http://localhost:5173/ (port may differ); the process stays running. |
init asks what you want to build and who the author is. The agent you launch next sets the app’s title, description, and categories in pop.ts to match what it builds; you can edit them there anytime. Your description is saved in BRIEF.md alongside the checklist starter and local agent guidance.
At the end, choose which agent CLI should build your pop. The picker offers detected Codex, Claude Code, Gemini CLI, and OpenCode installations. Choose Other CLI… for Grok or another installed tool: enter its executable name or path, then its prompt option (leave blank if it accepts a positional prompt). The agent opens in the new project and is asked to read the brief and pop guidance before implementing your app. It uses its existing account, model, and permission settings.
Choose Finish without launching to work manually. If an agent fails or you cancel the launch, your project remains ready to use. No agent is installed automatically.
For an agent or script that is already running, create the project without another interactive session:
bunx @hitslop/pop init budget-book --yes \ --brief 'Track spending by category with a monthly summary.' \ --title 'Budget Book' \ --category finance --category personal --author Jordan \ --description 'A simple monthly spending tracker.'Response (with your chosen destination):
Created /Users/you/budget-book. Run bun install in that directory, then bun run dev.This invocation has no interactive questions or agent launch.
Flags set metadata explicitly; --brief and --author also skip their questions. --yes, CI, and non-interactive terminals never prompt or launch an agent. Missing values default to the directory name, productivity, Anonymous, and A pop mini app.; an omitted brief uses that description. The wizard initializes the explicit slug from the directory name: 2–64 lowercase letters or digits, separated by single hyphens. Metadata is validated before files are created, and an existing destination is never overwritten.
Read pop.ts, AGENTS.md, and BRIEF.md before editing. Preview data resets on refresh, and an invalid edit shows a diagnostic until you fix it. Vite watches source changes. Component and CSS updates preserve accepted edits; a change to pop.ts, schema.ts, commands.ts, their dependencies (including skin or artwork), or the role inventory resets disposable state.
Stop the preview, then package the app and add it to your local catalog:
bun run buildbun run registerResponses, respectively (additional build progress omitted):
/Users/you/weekend-kit/dist/weekend-kit.pop/Users/you/.pop/templates/weekend-kit.popBuild writes dist/weekend-kit.pop on macOS or Linux, with Finder artwork rendered on either platform. Register builds it the same way and adds it to the Mac app’s template catalog. Existing documents keep their app version.
From outside the project, the equivalent commands take its source directory: pop check ./weekend-kit, pop dev ./weekend-kit --port 5174 (the preview port defaults to 5173), pop build ./weekend-kit, and pop register ./weekend-kit. See create your first pop for the authoring tutorial.
Create and open a writable document
Section titled “Create and open a writable document”In the Mac app, choose a template and select Create. For the terminal equivalent, run these commands from your authoring project:
bunx @hitslop/pop create --from dist/weekend-kit.pop --output "$HOME/Documents/Weekend.pop"bunx @hitslop/pop open "$HOME/Documents/Weekend.pop"Both commands print the same resolved path after success:
/Users/you/Documents/Weekend.popCreate makes a new document with the template’s starting data; choose a destination that does not already exist, and .pop is added if you leave it off. Open launches it in pop. Both print the document’s path. Keep writable documents out of synced folders such as iCloud Drive.
To start from a template in the Mac app’s catalog instead, list them and pass a slug to --from:
bunx @hitslop/pop templatesbunx @hitslop/pop create --from weekend-kit --output "$HOME/Documents/Weekend.pop"The templates response is a catalog object. Example excerpt:
{ "templates": [ { "slug": "weekend-kit", "title": "Weekend Kit", "source": "installed", "path": "/Users/you/.pop/templates/weekend-kit.pop" } ]}The following create prints /Users/you/Documents/Weekend.pop. Run one of the two creation examples, or choose a different output path for a second copy.
templates prints each template’s slug, title, description, categories, path and source: bundled with the app, or installed by register. If you register a template with the same slug as a bundled one, the slug names yours.
Read and edit data
Section titled “Read and edit data”For a complete numbered example with every response, follow
edit installed documents. For an existing document,
replace My.pop with its path and quote paths containing spaces:
bunx @hitslop/pop describe My.pop # fields, commands and current values (add --json for tools)bunx @hitslop/pop call My.pop addTask --args '{"text":"Buy coffee"}'bunx @hitslop/pop schema My.pop # the stored descriptorbunx @hitslop/pop get My.pop # saved valuesbunx @hitslop/pop apply My.pop --op '{"type":"set","path":["title"],"value":"Ready"}'bunx @hitslop/pop batch My.pop --ops '[...]'call runs one of the commands describe lists, as one undo step. apply takes one
operation and batch an array committed all-or-nothing; both print {"ids":[...]}, the
inserted row IDs. An operation is {"type":..., "path":[...]}, where type is set,
clear, insert, remove, move, increment or replace. A path walks the schema
from the root: field names and record keys are strings, rows are {"id":"<$id>"}, and
elements of a scalar list are {"index":n}. Use row IDs, never list positions. Each
kind’s merge behavior is in data and schemas.
get prints the saved value, while get --snapshot also includes the schema, the template’s colors (defaults), the version and the effective colors (theme).
A refused batch exits 1 and prints Refused ops[N] (reason): message on stderr, naming
the zero-based index of the operation to fix and whether anything was applied. Successful
edits are saved. On a Mac, Edit ▸ Undo can revert agent edits in the open window. If a
command’s outcome is uncertain, run get before retrying. Document creation and editing
work on macOS and Linux; opening a window needs the Mac app.
Move data between documents
Section titled “Move data between documents”import writes a JSON file’s value into a document, changing only what differs. Rows are matched by $id, so rows and text that stay keep their identity, and fields the import leaves unchanged are not written at all; an open window keeps working on them. Pass --path to replace one part, such as '["rows"]':
bunx @hitslop/pop get Old.pop > data.jsonbunx @hitslop/pop import New.pop data.jsonbunx @hitslop/pop import New.pop rows.json --path '["rows"]'Responses:
| Command | Response |
|---|---|
get Old.pop > data.json |
JSON is written to data.json; nothing is printed in the terminal. |
import New.pop data.json |
{"ids":[]} when no rows are inserted; inserted rows appear in ids. |
import New.pop rows.json --path '["rows"]' |
The same {"ids":[...]} shape, with the IDs inserted by this edit. |
Both documents must come from the same template, so the data fits its schema; a value that doesn’t fit is refused and nothing changes. For a document of another template, map the data to one batch of insert and set operations, giving each insert an id so a retried command is refused as a duplicate. Copy attachments with the commands below, then write their references. Edit ▸ Undo in the window reverts an import as one step.
Change theme colors
Section titled “Change theme colors”theme get, set, reset, export and import read and change a document’s palette.
Their commands and example responses are in
styling.
Work with attachments
Section titled “Work with attachments”bunx @hitslop/pop attachments ref ./photo.png# Store the printed reference where the app expects it, attaching the file in the same edit.bunx @hitslop/pop apply My.pop --attach ./photo.png \ --op '{"type":"set","path":["photo"],"value":{"id":"ATTACHMENT_ID","byteLength":48213,"name":"photo.png","mimeType":"image/png"}}'bunx @hitslop/pop attachments list My.popbunx @hitslop/pop attachments export My.pop ATTACHMENT_ID \ --output ./photo-copy.pngExample responses (ATTACHMENT_ID stands for the file’s actual content hash):
| Command | Response |
|---|---|
attachments ref ./photo.png |
{"id":"ATTACHMENT_ID","byteLength":48213,"name":"photo.png","mimeType":"image/png"} |
apply My.pop --attach ./photo.png … |
{"ids":[]} |
attachments list My.pop |
[{"id":"ATTACHMENT_ID","byteLength":48213,"mimeType":"image/png"}] |
attachments export My.pop ATTACHMENT_ID --output ./photo-copy.png |
/Users/you/Documents/photo-copy.png |
attachments ref prints a file’s reference (its ID, size, name and type) without reading the document. --attach on apply or batch saves the file in the same edit that stores the reference, so both succeed or neither does; repeat it for more files. Ask your agent to store the reference where the app expects it. A file nothing references any more is removed when the document closes, and a duplicate or shared copy carries only the files its document references. List shows saved attachment IDs and sizes.
Attachment export refuses existing output files and the document itself. After an uncertain edit, run get before another command.
Export PNG or PDF
Section titled “Export PNG or PDF”bunx @hitslop/pop export My.pop --format png --output My.pngbunx @hitslop/pop export My.pop --format pdf --output My.pdfExport saves your edits and prints the output path. Choose a new output path other than the .pop itself; an existing destination is refused. Both open and closed documents render saved data independently, using Export.svelte. Pop without this optional view refuse PNG/PDF export. PNG and selectable vector PDF use the Rust renderer. On macOS and Linux the CLI exports a closed document itself; an open one is exported by the Mac app that has it open. See icons and exports for capture layouts.
Successful exports print their resolved output paths, respectively:
/Users/you/Documents/My.png/Users/you/Documents/My.pdfInstall agent skills
Section titled “Install agent skills”Agent skills link to your global CLI, so they update whenever you upgrade it. Install the CLI globally, then run the interactive installer to choose skills and agents:
bun install -g @hitslop/poppop skills installOr, from a project directory, install for all detected agents at project scope:
pop skills install --all --scope projectAfter the skill and agent selections, install prints each installed skill and its agent directories. Example excerpt:
Installed "pop-authoring"--all prints the same installation results without selection prompts. The preceding
bun install -g @hitslop/pop prints Bun’s installation summary, including the pop executable.
Skills install for every project by default (global scope); add --scope project to link them into the current project only. Select skills once, then agents once. Installation only adds or repairs selected links; deselecting an item does not remove it. Bare skills is shorthand for skills install. Global links require a global install. Project links use the project’s pinned node_modules/@hitslop/pop, including when installed through bunx.
Upgrading the global CLI updates linked skills in place. If a link breaks or points somewhere else, repair it; add --scope project for project links:
pop skills repairExample repair response when a link already points to the right place:
No repairs needed [pop-authoring] (global).A repaired link instead reports Repaired "pop-authoring" for … (global), naming its agents.
To install skills for a new agent, run skills install again.
Remove installed links explicitly. Any copy of the CLI can do this:
pop skills uninstall --scope project# Remove every installed pop skill at this scope without prompts:pop skills uninstall --all --scope projectBoth uninstall forms report each removed skill and its agent directories. Example excerpt:
Removed "pop-authoring"With nothing installed, the response is No installed skills (project). Use either
interactive uninstall or --all; the second invocation will find no remaining links
if the first removed everything.
The guides linked by init follow the project’s pinned node_modules/@hitslop/pop install. Upgrading that dependency updates the linked guides; upgrading the global CLI leaves them unchanged.
Upgrade the CLI
Section titled “Upgrade the CLI”The Mac app and the pop package share a release version. Within a project, update its one pinned pop dependency and continue using its bun run scripts. A global CLI update does not change project dependencies. If the command protocol differs, the CLI names which installation needs updating before touching a document. Updating either installation preserves the app already saved inside every document.
Update the global CLI with bun install -g @hitslop/pop@VERSION, replacing VERSION with the matching released version. Installed agent skills point at the global CLI, so they update with it.
Interactive commands may show an update notice on stderr with that command, checked at most daily. Network failures do not fail your command. CI and piped commands skip these checks; set POP_NO_UPDATE_CHECK=1 to disable them in a terminal as well.
Local browser copies
Section titled “Local browser copies”pop open --browser ./MyDocument.poppop open --browserExample responses (copy and import IDs vary):
http://127.0.0.1:41238/?copy=COPY_ID#import=IMPORT_IDLocal browser host is running. Keep this terminal open; Ctrl-C stops it.Opening the list prints http://127.0.0.1:41238. The host message appears only when
this invocation starts the host; one that reuses it prints the URL and exits.
The first command opens an independent copy in desktop Google Chrome. The second opens your saved browser copies. Keep the host terminal running; Ctrl-C stops it. Later invocations reuse the same host. No account or server upload is involved.
Edits autosave in this browser profile on this device. Download .pop includes the current app, data, theme and referenced attachments for opening in the desktop client. The original file stays unchanged. Browser storage can be cleared or evicted: download copies you want to keep. Reload requires the local host to be running.
Chrome on desktop is supported. Safari, private browsing and mobile browsers remain unqualified. Hosted edit links use the separate
live sharing. Fullscreen appears for apps declaring
fullscreenable; Keep awake is a separate, initially off toggle.