deploy
Deploy Julian to an exe.xyz VM (new instance or update existing)
git clone --depth 1 https://github.com/popmechanic/VibesOS /tmp/deploy && cp -r /tmp/deploy/plugins/julian/skills/deploy ~/.claude/skills/deploySKILL.md
# Deploy Julian
Deploy Julian to an exe.xyz VM. Two paths: **provision** a new VM or **update** an existing one. The instance registry at `deploy/instances.json` tracks which VMs have been provisioned.
## Target VM
Determine the target VM name:
1. If `$ARGUMENTS` is provided, use it as the VM name (e.g., `/julian:deploy screen-test`)
2. If no arguments, derive from current git branch: `julian-<branch>` (e.g., branch `screen` → `julian-screen`)
3. Strip any characters not valid in hostnames (keep alphanumeric and hyphens)
**PRODUCTION SAFETY**: If the resolved VM name is exactly `julian` (the production instance), STOP and warn the user before proceeding. Only proceed after explicit confirmation.
## Routing: Provision or Update?
Read `deploy/instances.json`. If the target VM name exists in the registry, run the **Update** path. Otherwise, run the **Provision** path.
If `deploy/instances.json` doesn't exist, create it as `{}`.
---
## Path A: Provision (New VM)
Full first-time setup. Run all steps in order.
### Pre-flight
1. Get current git branch: `git rev-parse --abbrev-ref HEAD`
2. Pull Julian's changes locally: `git pull` (stop on merge conflicts)
3. Check for uncommitted changes: `git status --porcelain` (warn but don't block)
4. Push to GitHub: `git push`
5. Print target: VM name and URL (`https://<vmname>.exe.xyz/`)
#### OIDC Pre-flight
Read the local `.env` file and check for `VITE_OIDC_AUTHORITY`:
- **If present** (HTTPS URL): Extract the value for later. Proceed.
- **If missing or invalid**: STOP and guide the user:
- Option A: Run `/vibes:connect` to set up Connect + Pocket ID end-to-end
- Option B: Manually add `VITE_OIDC_AUTHORITY=https://studio.exe.xyz/auth` and `VITE_OIDC_CLIENT_ID=<id>` to `.env`
### Step P1: Create VM
**IMPORTANT**: All SSH commands targeting the VM must include `-o StrictHostKeyChecking=accept-new`.
```bash
ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 <vmname>.exe.xyz echo ok
```
If unreachable, create it:
```bash
ssh exe.dev new --name=<vmname>
ssh exe.dev share set-public <vmname>
```
Wait for boot (up to 90 seconds):
```bash
for i in $(seq 1 9); do
ssh -o StrictHostKeyChecking=accept-new -o ConnectTimeout=5 <vmname>.exe.xyz echo ok && break
echo "Attempt $i failed, retrying in 10s..."
sleep 10
done
```
### Step P2: Install system dependencies
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "curl -fsSL https://bun.sh/install | bash && sudo apt-get update -qq && sudo apt-get install -y npm inotify-tools"
```
### Step P3: Set up directory structure
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "sudo mkdir -p /opt/julian && sudo chown exedev:exedev /opt/julian && mkdir -p /home/exedev/mailbox"
```
### Step P4: Generate deploy key and clone repo
Generate an SSH key for push access:
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "ssh-keygen -t ed25519 -f ~/.ssh/julian-deploy -N '' -C '<vmname>-deploy'"
```
Configure SSH to use it for GitHub:
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "mkdir -p ~/.ssh && cat >> ~/.ssh/config << 'SSHEOF'
Host github.com
IdentityFile ~/.ssh/julian-deploy
StrictHostKeyChecking accept-new
SSHEOF"
```
Add the deploy key to GitHub with write access:
```bash
DEPLOY_KEY=$(ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "cat ~/.ssh/julian-deploy.pub")
gh repo deploy-key add - --repo popmechanic/Julian --title "<vmname>-deploy" --allow-write <<< "$DEPLOY_KEY"
```
If the key title already exists, skip — it's fine.
Clone the repo and configure git identity:
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "git clone git@github.com:popmechanic/Julian.git /opt/julian"
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "cd /opt/julian && git config user.name 'Julian' && git config user.email 'julian@exe.xyz'"
```
### Step P5: Install dependencies
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "cd /opt/julian && /home/exedev/.bun/bin/bun install"
```
### Step P6: Create .env
Use the `VITE_OIDC_AUTHORITY` and `VITE_OIDC_CLIENT_ID` from pre-flight (do NOT hardcode):
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "cat > /opt/julian/.env << 'ENVEOF'
VITE_OIDC_AUTHORITY=<value from local .env>
VITE_OIDC_CLIENT_ID=<value from local .env>
ALLOWED_ORIGIN=https://<vmname>.exe.xyz
ENVEOF"
```
### Step P6b: Configure Claude Code settings
Enable Agent Teams (disabled by default) so Julian can spawn and manage agent teammates:
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "mkdir -p /home/exedev/.claude && cat > /home/exedev/.claude/settings.json << 'SETTINGSEOF'
{
"env": {
"CLAUDE_CODE_EXPERIMENTAL_AGENT_TEAMS": "1"
}
}
SETTINGSEOF"
```
### Step P7: Install and start systemd services
```bash
scp deploy/julian.service <vmname>.exe.xyz:/tmp/
scp deploy/julian-screen.service <vmname>.exe.xyz:/tmp/
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "sudo cp /tmp/julian.service /etc/systemd/system/ && \
sudo cp /tmp/julian-screen.service /etc/systemd/system/ && \
sudo systemctl daemon-reload && \
sudo systemctl enable --now julian julian-screen"
```
### Step P8: Register instance
Add the VM to `deploy/instances.json`:
```json
{
"<vmname>": {
"url": "https://<vmname>.exe.xyz",
"provisioned": "<ISO 8601 timestamp>",
"branch": "<git branch used for first deploy>"
}
}
```
Read the existing file, merge the new entry, write it back. **Commit and push** the updated registry so other machines know about it:
```bash
git add deploy/instances.json
git commit -m "Register <vmname> instance"
git push
```
### Step P9: Verify
```bash
ssh -o StrictHostKeyChecking=accept-new <vmname>.exe.xyz "systemctl is-active julian julian-screen"
curl -sf https://<vmname>.exe.xyz/ | head -5
curl -sf https://<vmname>.exe.xyz/api/health
```
Report: URL, service status, and remind user that Anthropic credentials neSelf-contained deploy automation — invoke directly, do not decompose. Deploys a Vibes app to Cloudflare Workers via the Deploy API. Use when deploying, publishing, going live, pushing to production, or hosting on the edge. Authenticates with Pocket ID.
Self-contained design transformer — invoke directly, do not decompose. Transforms a design reference HTML file into a Vibes app. Use when user provides a design.html, mockup, or static prototype to match exactly.
Self-contained SaaS pipeline — invoke directly, do not decompose. Generates a factory app with landing page, Stripe subscription checkout, Vibe Token economics, and deploys to Cloudflare Workers. Use when the user wants to monetize an app, add billing, create token-backed revenue sharing, or turn an app into a business.
Self-contained SaaS pipeline — invoke directly, do not decompose.
Self-contained parallel generator — invoke directly, do not decompose. Generates 3-10 app variations in parallel for comparing ideas. Use when user says "explore options", "give me variations", "riff on this", "brainstorm approaches", or wants to see multiple interpretations of a concept.
Lightweight requirements gathering before app generation. Asks non-technical multiple-choice questions to understand user intent, then produces a brief for the generate prompt.
Self-contained app generator — invoke this skill directly, do not decompose into sub-steps. Generates React web apps with TinyBase reactive data store. Use when creating new web applications, adding components, or working with real-time data. Ideal for quick prototypes and single-page apps that need real-time data sync.
>