exe

Plan mode: If you are planning work, this entire skill is ONE plan step: "Invoke /vibes:exe". Do not decompose the steps below into separate plan tasks.

Safety Notice

This listing is imported from skills.sh public index metadata. Review upstream SKILL.md and repository scripts before running.

Copy this and send it to your AI assistant to learn

Install skill "exe" with this command: npx skills add popmechanic/vibes-cli/popmechanic-vibes-cli-exe

Plan mode: If you are planning work, this entire skill is ONE plan step: "Invoke /vibes:exe". Do not decompose the steps below into separate plan tasks.

Deploy to exe.dev

Deploy your Vibes app to exe.dev, a VM hosting platform with persistent storage and HTTPS by default.

Prerequisites

  • SSH key in ~/.ssh/ (id_ed25519, id_rsa, or id_ecdsa)

  • exe.dev account - run ssh exe.dev once to create your account and verify email

  • Generated Vibes app - an index.html file ready to deploy

Gather Config Upfront

Use AskUserQuestion to collect deployment config before running the deploy script.

Use the AskUserQuestion tool with these questions:

Question 1: "What VM name should we use? (becomes yourname.exe.xyz)" Header: "VM Name" Options: Suggest based on app name from context + user enters via "Other"

Question 2: "Which file should we deploy?" Header: "File" Options: ["index.html (default)", "Other path"]

Question 3: "Does this app need AI features?" Header: "AI" Options: ["No", "Yes - I have an OpenRouter key"]

Question 4: "Is this a SaaS app with subdomain claiming?" Header: "Registry" Options: ["No - simple static deploy", "Yes - need Clerk keys for registry"]

After Receiving Answers

  • If AI enabled, ask for the OpenRouter API key

  • If Registry enabled, ask for Clerk PEM public key and webhook secret

  • Proceed immediately to deploy - no more questions

Quick Deploy

cd "${CLAUDE_PLUGIN_ROOT}/scripts" && [ -d node_modules ] || npm install node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-exe.js" --name myapp --file index.html

What It Does

  • Creates VM on exe.dev via SSH CLI

  • Starts nginx (pre-installed on exeuntu image)

  • Uploads your index.html to /var/www/html/

  • Generates HANDOFF.md - context document for remote Claude

  • For Connect-enabled deployments, includes full Docker setup documentation (commands, troubleshooting, service endpoints)

  • Makes VM public via ssh exe.dev share set-public <vmname>

  • Verifies public access at https://myapp.exe.xyz

AI-Enabled Apps

For apps using the useAI hook, deploy with the --ai-key flag:

node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-exe.js" --name myapp --file index.html --ai-key "sk-or-v1-..."

This sets up a secure AI proxy:

  • Installs Bun runtime

  • Creates /home/exedev/proxy.js

  • proxies /api/ai/* to OpenRouter

  • Configures systemd service for the proxy

  • Adds nginx reverse proxy from port 80/443 to Bun (port 3001)

IMPORTANT: Do not manually set up AI proxying. Manual nginx config changes can overwrite SSL settings and miss the Bun/proxy.js service. Always use the deploy script with --ai-key .

Multi-Tenant AI Apps

For SaaS apps with per-tenant AI:

node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-exe.js" --name myapp --file index.html --ai-key "sk-or-v1-..." --multi-tenant

Registry Server

For SaaS apps using subdomain claiming (from /vibes:sell ), deploy with Clerk credentials:

node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-exe.js" --name myapp --file index.html
--clerk-key "cat clerk-public-key.pem"
--clerk-webhook-secret "whsec_xxx"
--reserved "admin,api,billing"

This sets up a subdomain registry server:

  • Installs Bun runtime to /usr/local/bin/bun

  • Creates /var/www/registry-server.ts with Clerk JWT verification

  • Configures systemd service (port 3002)

  • Adds nginx proxy for /registry.json , /check/* , /claim , /webhook

Registry Endpoints

Endpoint Method Auth Description

/registry.json

GET None Public read of all claims

/check/{subdomain}

GET None Check availability

/claim

POST Bearer JWT Claim subdomain for user

/webhook

POST Svix sig Clerk subscription events

Getting the Clerk Public Key

The registry server needs Clerk's PEM public key to verify JWTs for the /claim endpoint.

Option 1: From Clerk Dashboard

  • Go to Clerk Dashboard → API Keys

  • Scroll to "PEM Public Key" or click "Show JWT Public Key"

  • Copy the full key (starts with -----BEGIN PUBLIC KEY----- )

Option 2: From JWKS endpoint

Get your Clerk frontend API domain from dashboard

curl https://YOUR_CLERK_DOMAIN/.well-known/jwks.json

Then convert the JWK to PEM format using an online tool or jose CLI.

Passing to deploy script:

From a file

node deploy-exe.js --clerk-key "cat clerk-public-key.pem" ...

Inline (escape newlines)

node deploy-exe.js --clerk-key "-----BEGIN PUBLIC KEY-----\nMIIB...\n-----END PUBLIC KEY-----" ...

Manual configuration on server:

ssh myapp.exe.dev sudo nano /etc/registry.env

Add: CLERK_PEM_PUBLIC_KEY="-----BEGIN PUBLIC KEY-----\n...\n-----END PUBLIC KEY-----"

sudo systemctl restart vibes-registry

Continue Development on the VM

Claude is pre-installed on exe.dev VMs. After deployment, you can continue development remotely:

ssh myapp.exe.dev -t "cd /var/www/html && claude"

The HANDOFF.md file provides context about what was built, so Claude can continue meaningfully.

Manual Public Access

If the deploy script doesn't make the VM public automatically, run:

ssh exe.dev share set-public myapp

Multi-Tenant Apps

For apps that need tenant isolation (e.g., alice.myapp.com , bob.myapp.com ):

Client-Side Isolation

The same index.html serves all subdomains. JavaScript reads the hostname and uses the subdomain as a Fireproof database prefix:

// In your app: const hostname = window.location.hostname; const subdomain = hostname.split('.')[0]; const dbName = myapp-${subdomain};

// Each subdomain gets its own Fireproof database const { database } = useFireproof(dbName);

Custom Domain Setup

Add --domain flag:

node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-exe.js" --name myapp --domain myapp.com

Configure wildcard DNS at your DNS provider:

*.myapp.com CNAME myapp.exe.xyz myapp.com ALIAS exe.xyz

Set up wildcard SSL on the VM:

ssh myapp.exe.dev sudo apt install certbot sudo certbot certonly --manual --preferred-challenges dns
-d "myapp.com" -d "*.myapp.com"

CLI Options

Option Description

--name <vm>

VM name (required)

--file <path>

HTML file to deploy (default: index.html)

--domain <domain>

Custom domain for wildcard setup

--ai-key <key>

OpenRouter API key for AI features

--multi-tenant

Enable subdomain-based multi-tenancy

--tenant-limit <$>

Credit limit per tenant in dollars (default: 5)

--clerk-key <pem>

Clerk PEM public key for JWT verification

--clerk-webhook-secret <secret>

Clerk webhook signing secret

--reserved <list>

Comma-separated reserved subdomain names

--preallocated <list>

Pre-claimed subdomains (format: sub:user_id )

--dry-run

Show commands without executing

--skip-verify

Skip deployment verification

Redeployment

After making changes, redeploy with:

node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-exe.js" --name myapp

SSH Access

Access your VM directly:

ssh myapp.exe.dev

Architecture

exe.dev VM (exeuntu image) ├── nginx (serves all subdomains via server_name _) ├── claude (pre-installed CLI) ├── /usr/local/bin/bun ← Bun runtime (system-wide) ├── /var/www/html/ │ ├── index.html ← Your Vibes app │ └── HANDOFF.md ← Context for remote Claude ├── (with --ai-key) │ ├── /opt/vibes/proxy.js ← AI proxy service (port 3001) │ └── vibes-proxy.service ← systemd unit └── (with --clerk-key) ├── /var/www/registry-server.ts ← Registry service (port 3002) ├── /var/www/html/registry.json ← Subdomain claims data └── vibes-registry.service ← systemd unit

Port Assignments

Service Port Purpose

AI Proxy 3001 OpenRouter proxy for useAI hook

Registry 3002 Subdomain claim/check API

  • No server-side logic - pure static hosting (unless using AI proxy)

  • Persistent disk - survives restarts

  • HTTPS by default - exe.dev handles SSL for *.exe.xyz

  • Claude pre-installed - continue development on the VM

Post-Deploy Debugging

After deployment, always work with local files - they are the source of truth. SSHing to read deployed files is slow and wastes tokens.

Task Use Local Use SSH

Editing/debugging code ✅ Always ❌ Never

Checking console errors ✅ Local file ❌ No need

Verifying deploy ❌ ✅ curl https://vm.exe.xyz

Server-specific issues ❌ ✅ Only if local works but remote doesn't

To redeploy after local fixes:

node "${CLAUDE_PLUGIN_ROOT}/scripts/deploy-exe.js" --name <vmname> --file index.html

SSL Configuration

The deploy script preserves existing SSL by using include files for AI proxy config. When manually editing nginx:

  • Never replace the entire config - only add/modify specific blocks

  • Check for SSL first: Look for listen 443 ssl in the config

  • Use includes: Put new configs in /etc/nginx/conf.d/ or separate files

  • Test before reload: sudo nginx -t

Manual File Transfer to VMs

When manually transferring files (outside the deploy script), use the two-stage pattern.

Key distinction:

  • exe.dev = orchestrator (for VM management: ssh exe.dev new , ssh exe.dev share )

  • <app>.exe.xyz = actual VM (for file operations, SSH access)

Reliable pattern:

Upload: SCP to server temp → sudo move to /var/www/html/

scp index.html myapp.exe.xyz:/tmp/ ssh myapp.exe.xyz "sudo cp /tmp/index.html /var/www/html/"

Download: Direct SCP works fine

scp myapp.exe.xyz:/var/www/html/index.html ./downloaded.html

Why server-side temp?

  • Direct SCP to /var/www/html/ fails (permission denied - owned by www-data)

  • Server /tmp/ is world-writable, so SCP succeeds

  • sudo cp moves file with correct ownership

Common mistakes:

Mistake Error Fix

ssh exe.dev cat /var/www/...

"No VMs found" Use ssh <app>.exe.xyz

scp file vm:/var/www/html/

Permission denied Use temp + sudo pattern

Forgetting sudo for /var/www Permission denied Always sudo cp for www-data dirs

Quick reference commands:

Connect to VM

ssh <app>.exe.xyz

Read file

ssh <app>.exe.xyz "cat /var/www/html/index.html"

Upload file (two-stage)

scp index.html <app>.exe.xyz:/tmp/ ssh <app>.exe.xyz "sudo cp /tmp/index.html /var/www/html/"

Download file

scp <app>.exe.xyz:/var/www/html/index.html ./downloaded.html

Verify

ssh <app>.exe.xyz "head -20 /var/www/html/index.html"

What's Next?

After successful deployment, present these options using AskUserQuestion:

Question: "Your app is live at https://${name}.exe.xyz! What's next?" Header: "Next" Options:

  • Label: "Share my URL" Description: "Get the shareable link for your app. I'll confirm the public URL and you can send it to anyone - they'll see your app immediately with full functionality."

  • Label: "Make changes and redeploy" Description: "Continue iterating locally. Edit your files here, then run deploy again to push updates. The VM keeps running so there's zero downtime during updates."

  • Label: "Continue development on VM" Description: "Work directly on the server. SSH in and use the pre-installed Claude to make changes live. Great for server-specific debugging or when you want changes to persist immediately."

  • Label: "I'm done for now" Description: "Wrap up this session. Your app stays live at the URL - it runs 24/7 on exe.dev's persistent VMs. Come back anytime to make updates."

After user responds:

  • "Share URL" → Confirm "Your app is live at https://${name}.exe.xyz - share this link!"

  • "Make changes" → Acknowledge, stay ready for local edits

  • "Continue on VM" → Provide: ssh ${name}.exe.dev -t "cd /var/www/html && claude"

  • "I'm done" → Confirm app stays live, wish them well

Source Transparency

This detail page is rendered from real SKILL.md content. Trust labels are metadata-based hints, not a safety guarantee.

Related Skills

Related by shared tags or category signals.

Coding

riff

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

launch

No summary provided by upstream source.

Repository SourceNeeds Review
Coding

vibes

No summary provided by upstream source.

Repository SourceNeeds Review