skills/pop/SKILL.md
Deploy/publish local project files to a Popcorn channel. USER-TRIGGERED ONLY — never invoke pre-emptively. For general deploy requests, use the CLI directly (popcorn site deploy).
npx skillsauth add popcornaihq/popcorn-claude-code popInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Publish local project files to a Popcorn app channel. The workspace VM pulls the tarball, unpacks, commits, and serves the site. Popcorn supports all project types: static sites, build-step sites (React, Vite, Next.js), and full-stack server apps (Node.js/Express, Python/Flask).
This command should "just work" — handle setup, context generation, and error recovery automatically. The user should go from zero to a live site in one invocation.
Run setup from the plugin root (not this skill's directory):
bash "${CLAUDE_PLUGIN_ROOT}/skills/popcorn/setup.sh"
The last line is JSON: {"cli":true/false,"auth":true/false,"mcp":true/false}.
cli and auth are both true → proceed with the CLI deploy flow below.cli is false but mcp is true → use the MCP path in Step 4 below.cli and mcp are false → stop and tell the user what failed.From the user's free-form text (everything after /pop), infer:
# prefix (e.g., #my-channel). A bare name also works when the user's intent is clearly to target an existing channel (e.g., "deploy to my-channel"). Strip the # prefix before lookup.pop-<directory-name>. Ignored when a target channel is specified — the existing channel's name is used instead.The user may provide any combination in natural phrasing. Examples:
/popcorn:pop → defaults for everything
/popcorn:pop my-app → site name "my-app" (new deploy)
/popcorn:pop added dark mode → context "Added dark mode"
/popcorn:pop deploy my-app with the new sidebar → site name "my-app", context "New sidebar"
/popcorn:pop #my-channel → target existing #my-channel
/popcorn:pop #my-channel added dark mode → target #my-channel, context "Added dark mode"
Don't be rigid — interpret intent. When ambiguous between name and context, prefer context (more useful). When ambiguous between name and target channel, prefer target channel if the token has a # prefix.
Check if this is a git repo (git rev-parse --git-dir 2>/dev/null). If it's not a git repo, skip this step entirely.
If it is a git repo, ensure all work is committed and up to date before deploying:
git status --porcelain. If there are staged or unstaged changes, commit them. Use the conversation context to write a meaningful commit message.git rev-parse --abbrev-ref @{upstream} 2>/dev/null), pull to ensure local is up to date (git pull).git log @{upstream}..HEAD --oneline 2>/dev/null. If there are unpushed commits, remember this for Step 5 (don't block the deploy).This ensures the deployed version includes the latest work.
All commands use agent mode (POPCORN_AGENT=1) which auto-injects --json, --quiet, --no-color. Never pass --json manually.
If the user specified a #channel in Step 2, look it up first to get the target key:
POPCORN_AGENT=1 popcorn site targets
Find the target whose site_name matches the channel name. Use its name field as the --target value. If no match, the channel may not have been deployed from this project — tell the user.
Otherwise, just deploy. The CLI auto-resolves the target from .popcorn.local.json (default target → workspace match → single target → create new):
# Default: auto-resolve target, auto-generate git context
POPCORN_AGENT=1 popcorn site deploy --context-from-git
# User specified a #channel (target key from site targets):
POPCORN_AGENT=1 popcorn site deploy --target <key> --context-from-git
# With a custom channel name (first deploy):
POPCORN_AGENT=1 popcorn site deploy my-app --context-from-git
# With explicit context (user described what changed):
POPCORN_AGENT=1 popcorn site deploy --context "Add dark mode toggle"
# With workspace override (target's workspace differs from current):
POPCORN_AGENT=1 popcorn --workspace Camino site deploy --context-from-git
The CLI handles: target resolution, tarball creation, git context generation, S3 upload, and VM deploy. It writes .popcorn.local.json automatically after deploy.
Parse the response envelope:
{"ok": true, "data": {"selected_target":"...","site_name":"...","version":3,"site_url":"...","commit_hash":"..."}}{"ok": false, "error": "...", ...} on stderrRead site_name, version, and site_url from .data on success. selected_target tells you which target was auto-resolved.
Fetch the pop prompt from the Popcorn MCP server and follow its
instructions entirely. The prompt contains the complete MCP deploy
workflow including GitHub-based and S3-based deploy paths.
After a successful deploy, persist state to .popcorn.local.json so subsequent deploys resolve the target automatically. Read the existing file first (if any), then upsert:
{
"version": 2,
"default_target": "<site_name>",
"targets": {
"<site_name>": {
"workspace_id": "<from whoami>",
"workspace_name": "<from whoami>",
"conversation_id": "<channel ID from deploy response>",
"site_name": "<from deploy response>",
"deployed_at": "<ISO timestamp>"
}
}
}
Upsert rule: Match existing targets by (workspace_id, site_name). If found, update in place. If new, add with site_name as key. Always set default_target to the deployed target.
<site_name> (v<version>) — <site_url>" where site_url is from the deploy response .data.site_url (e.g. https://pop-test--my-ws.popcorn.ing)verify_task_id or the site isn't ready yet, you can stream build progress:
POPCORN_AGENT=1 popcorn site trace '#<site_name>' --watch
Each NDJSON line is a build/deploy step. Report progress: "Building..." → "Installing deps..." → "Live."<branch>. Want me to push?"If the deploy fails, don't just report the error — try to recover:
| Error | Recovery |
|-------|----------|
| Not logged in (exit code 2) | Run bash "${CLAUDE_PLUGIN_ROOT}/skills/popcorn/setup.sh" to authenticate, then retry |
| Ambiguous targets ("Multiple deploy targets found") | Call POPCORN_AGENT=1 popcorn site targets to list them, then pick the first target and retry with --target <name> — don't block asking the user. Note which target you picked in your success report so they can redirect if needed |
| Workspace mismatch ("belongs to workspace X") | The error message includes a --workspace suggestion. Re-run with --workspace <name-or-id> before site deploy |
| Target not found | The explicit --target name doesn't exist. Call site targets to list available targets |
| Stale channel config | The CLI auto-recreates the channel in non-interactive mode. If it still fails, retry with a fresh name |
| VM error (build/deploy failure) | Report the vm_error details from the response. These are usually code issues (missing dependencies, build errors) — show the user the error so they can fix their code |
| Network timeout | Retry once with --timeout 120. If it fails again, report the timeout |
| 409 conflict (name taken) | The CLI auto-retries with a suffix. If it still fails, suggest the user provide a different name |
| Ghost channel conflict (error_code: "conflict", "exists but isn't accessible") | The name is taken by a channel in the workspace that you don't have access to. Suggest a different name to the user, or retry with a suffix (<name>-2) |
| Unknown error | Report the full error JSON so the user can debug |
tools
Popcorn integration — CLI, MCP tools, setup, and behavioral guardrails.
tools
Pull recent channel messages into context. USER-TRIGGERED ONLY — never invoke pre-emptively. For general message reading, use the CLI directly (popcorn message list).
tools
Export site files from a Popcorn channel into the local project. USER-TRIGGERED ONLY — never invoke pre-emptively. For general export, use the CLI directly (popcorn site export).
tools
Use when work should span one or more detached tasks but still behave like one job with a single owner context. TaskFlow is the durable flow substrate under authoring layers like Lobster, ACPX, plugins, or plain code. Keep conditional logic in the caller; use TaskFlow for flow identity, child-task linkage, waiting state, revision-checked mutations, and user-facing emergence.