Skip to content
150 changes: 110 additions & 40 deletions plugins/upsun/skills/upsun/SKILL.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,27 @@ Upsun is a git-driven cloud application platform. Key concepts:

---

## Detect tooling availability first

**Before doing anything**, silently determine which tools are reachable:

1. Try `upsun --version` — if it succeeds, **CLI is available**.
2. Try `mcp__upsun__list-project` — if it succeeds, **MCP is available**.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think agent harnesses may already be told which MCPs are available?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I guess it can be simplified. I just added one liner for tooling preference now and removed all the other changes.

3. If neither works, assume **console-only** (guide via https://console.upsun.com).

Store the result as the active mode for the rest of the conversation:

| Mode | CLI | MCP | Notes |
|------|-----|-----|-------|
| `cli` | ✓ | – | Full capability |
| `mcp` | – | ✓ | No git-push / tunnel / SSH — use console or source integration for deploys |
| `cli+mcp` | ✓ | ✓ | **Always prefer CLI** — use MCP only as a fallback when CLI lacks the specific capability |
| `console` | – | – | Guide user through https://console.upsun.com UI |

**CLI takes priority over MCP whenever it is available.** MCP is a fallback for environments where the CLI cannot be installed. Only suggest CLI installation when the user explicitly wants a capability that MCP cannot provide (see [CLI-only operations](#cli-only-operations)).

---

## Detect context first

Before doing anything, determine which situation applies:
Expand All @@ -35,7 +56,14 @@ Before doing anything, determine which situation applies:

Walk the developer through these steps in order. Do one at a time; confirm each before moving on.

### 1. Install CLI
### 1. Establish access (CLI or MCP — pick one)

**If MCP is already available** (e.g. browser-based editor, cloud IDE, Cursor with MCP configured):
- Skip CLI installation entirely.
- Use `mcp__upsun__list-project` to verify authentication and list existing projects.
- Note upfront: git-push deploys and SSH tunnels require CLI or a connected source integration (GitHub/GitLab/Bitbucket). Advise connecting a source integration (step 6) so the developer can deploy by pushing to their Git host instead.

**If CLI is available / preferred**:

```bash
# macOS
Expand Down Expand Up @@ -75,56 +103,77 @@ upsun project:set-remote <PROJECT_ID>

### 2. Create project

Via CLI or the console (https://console.upsun.com/projects/create-project):
```bash
upsun project:create
```
| Tooling | Command / Action |
|---------|-----------------|
| CLI | `upsun project:create` |
| MCP | `mcp__upsun__create-project` (if available) |
| Console | https://console.upsun.com/projects/create-project |

Comment thread
ganeshdipdumbare marked this conversation as resolved.
Outdated
### 3. Add Upsun config

Run `upsun init` in the project root — it generates `.upsun/config.yaml` (runtime, services, routes) and an `.environment` script if services are detected.
**CLI**: Run `upsun init` in the project root — it generates `.upsun/config.yaml` (runtime, services, routes) and an `.environment` script if services are detected.

See [references/config.md](references/config.md) for a minimal working template and common service examples.
**MCP / console**: Generate the config file manually. See [references/config.md](references/config.md) for a minimal working template and common service examples. Offer to write the file directly via the editor.

Key points for the config:
- For Node.js and PHP apps, set `build.flavor: none` and manage dependencies explicitly in the build hook.
- Start hooks with `set -ex` so failures are visible.

### 4. Deploy

```bash
git add .upsun/config.yaml
git commit -m "Add Upsun configuration"
upsun push
```
| Tooling | Command / Action |
|---------|-----------------|
| CLI | `git add .upsun/config.yaml && git commit -m "Add Upsun configuration" && upsun push` |
| MCP (no CLI) | Push via source integration (GitHub/GitLab/Bitbucket push triggers deploy). If no integration, guide through console: https://console.upsun.com |
| Console | Use the **Deploy** button in the Upsun console after committing config to the linked repo |

Default resources are allocated automatically on first deploy. To control initial sizing, pass `--resources-init=minimum` (cheapest) or `--resources-init=parent` (match parent environment) on `upsun push` or `upsun branch`.

After deploy: `upsun url` to open the environment, `upsun logs --tail` to check for issues.
After deploy: check logs via `upsun logs --tail` (CLI) or `mcp__upsun__get-logs` (MCP). Open the environment URL from console or `upsun url` (CLI).

Review and calibrate resources after running with `upsun metrics` and `upsun resources:set`.
Review and calibrate resources after running with `upsun metrics` (CLI) or `mcp__upsun__get-metrics` (MCP), then `upsun resources:set` (CLI) or `mcp__upsun__set-resources` (MCP).

### 5. Local development with tunnel

Open a tunnel to connect your local environment to live Upsun services:
**CLI only** — MCP does not support local tunnels:
```bash
upsun tunnel:open
# Then run your local dev server as normal
```
Show the connection string so the developer can configure their local `.env`.

### 6. Connect Git provider (optional)
If CLI is unavailable, the alternative is to deploy a development environment (`upsun branch` / branch on the source repo) and work against the remote services directly.

Auto-deploy on every push; every PR gets a live preview environment:
```bash
upsun integration:add --type github --repository myorg/myapp
# Also supported: gitlab (use --server-project instead of --repository), bitbucket
```
### 6. Connect Git provider (optional but recommended for MCP-only users)

Connecting a source integration makes `git push` to GitHub/GitLab/Bitbucket trigger a Upsun deploy automatically, **enabling full deploy workflows without the Upsun CLI**:
Comment thread
ganeshdipdumbare marked this conversation as resolved.
Outdated

| Tooling | Command / Action |
|---------|-----------------|
| CLI | `upsun integration:add --type github --repository myorg/myapp` |
| MCP | `mcp__upsun__add-integration` (if available) |
| Console | https://console.upsun.com -> project -> Integrations |

Also supported: `gitlab` (use `--server-project` instead of `--repository`), `bitbucket`.

Note: once a source integration is active, the external repo becomes the source of truth. `upsun push` still works but pushes to the source repo (not directly to Upsun), so advanced git-push options like `--activate` or `--deploy-strategy` are not available. Branching and merging must happen on the external repo.

---

## CLI-only operations

These operations require the Upsun CLI and cannot be performed via MCP alone. When in `mcp` or `console` mode, inform the developer and suggest the best workaround:

| Operation | Workaround without CLI |
|-----------|------------------------|
| `upsun push` / `upsun deploy` | Push to source repo with active source integration |
| `upsun tunnel:open` | Use a remote dev environment branch instead |
| `upsun ssh` | Use Upsun console Web SSH: https://console.upsun.com |
| `upsun mount:download` / `mount:upload` | Use `rsync` over SSH once CLI is available, or console file manager |
| `upsun db:sql` / `db:dump` | Console web terminal or SSH (see above) |
Comment thread
ganeshdipdumbare marked this conversation as resolved.
Outdated

---

## Step 1 — Resolve project and environment

Never assume a project or environment. Resolve in this order:
Expand All @@ -133,39 +182,51 @@ Never assume a project or environment. Resolve in this order:
2. **Upsun CLI available** -> run `upsun project:list` / `upsun environment:list` and present options
3. **Neither available** -> ask for PROJECT_ID and environment name

If inside a linked Git repo, run `upsun project:info` to auto-detect first. If that fails, suggest `upsun project:set-remote <PROJECT_ID>` to link the repo to a project.
If inside a linked Git repo and CLI is available, run `upsun project:info` to auto-detect first. If that fails, suggest `upsun project:set-remote <PROJECT_ID>` to link the repo to a project.

---

## Step 2 — Developer workflows

For every workflow below, use the active mode determined in [Detect tooling availability first](#detect-tooling-availability-first). **Prefer CLI whenever it is available**; fall back to MCP only when CLI is not installed.
Comment thread
ganeshdipdumbare marked this conversation as resolved.
Outdated

### Deploy / Redeploy

- Never assume `main` is production — confirm with `upsun environment:info`
- Never assume `main` is production — confirm with `upsun environment:info` (CLI) or `mcp__upsun__get-environment` (MCP).
- If a source integration is active, `upsun push` still works but pushes to the source repo, so advanced git-push options (`--activate`, `--deploy-strategy`) are not available.
- **Deployment strategy matters for migrations.** Default is `stopstart`: the old version stops before the new starts, causing brief downtime but no constraint on schema compatibility. With `rolling` (opt-in), old and new app versions run simultaneously sharing the same database, so schema changes must be backwards-compatible but there is no downtime. Use `upsun push --deploy-strategy=rolling` or, for manual deploy types, `upsun deploy --strategy=rolling`.
- After deploy, offer to tail logs: `upsun logs --tail`
- After deploy, offer to tail logs: `upsun logs --tail` (CLI) or `mcp__upsun__get-logs` (MCP).
- **MCP-only**: trigger deploys via `mcp__upsun__deploy` if available, otherwise push to the source repo.

### Branch / Merge (feature environments)

- New branch inherits config from parent; ask: sync data from parent? (`upsun sync` supports code, data, and resources independently)
- New branch inherits config from parent; ask: sync data from parent?
- CLI: `upsun sync` supports code, data, and resources independently
- MCP: `mcp__upsun__sync-environment` (if available)
- After branching, show the environment URL so the developer can test immediately
- Every PR auto-deploys to a live preview if a source integration (GitHub/GitLab/Bitbucket) is active
- Merge: ask whether to delete the child environment after merge (require explicit yes/no)
- CLI: `upsun environment:merge` then optionally `upsun environment:delete`
- MCP: `mcp__upsun__merge-environment` / `mcp__upsun__delete-environment`

### Logs + SSH (debugging)

- Prefer `upsun logs --tail` as the first debugging step — fastest signal
- SSH: if the developer wants to investigate further, ask what they're looking for:
- Prefer logs as the first debugging step — fastest signal:
- CLI: `upsun logs --tail`
- MCP: `mcp__upsun__get-logs`
- SSH: **CLI only** (`upsun ssh`). If CLI is unavailable, direct the developer to the console Web SSH terminal at https://console.upsun.com. Ask what they're looking for:
- App crashes / OOM -> `ps aux`, `free -h`
- Disk full -> `df -h`
- Cache issues -> ask which layer to clear
- Multiple app containers? List them before connecting
- Multiple app containers? List them before connecting.

### Database / Tunnel

- List relationships from `upsun relationships` (or MCP) before asking which service
- List relationships first:
- CLI: `upsun relationships`
- MCP: `mcp__upsun__get-relationships`
- Goal options: interactive shell / export dump (recommend `.sql.gz`) / local tunnel for GUI tools / run migration
- **Tunnel is CLI-only** (`upsun tunnel:open`). MCP alternative: spin up a branch environment and connect tools to its public endpoint.
- Migration: suggest testing on a staging branch first; the default `stopstart` strategy is safe for non-backwards-compatible schema changes (don't opt in to `rolling` unless the schema change is backwards-compatible)
- Tunnel: show the full connection string after opening so the developer can paste it into their tool

Expand All @@ -177,38 +238,47 @@ If inside a linked Git repo, run `upsun project:info` to auto-detect first. If t
- Environment variables are runtime-only by default. To make available at build time, use `--visible-build true`.
- `upsun deploy` vs `upsun redeploy`: `deploy` deploys **staged changes** (e.g. environment-level variable changes on a manual-deploy environment, or code pushes). `redeploy` re-deploys the **current** state — use it when there are no staged changes but a new deployment is still needed (e.g. after setting project-level variables).
- After setting variables, a deployment is required for changes to take effect -> ask if they want to trigger one now.
- MCP: use `mcp__upsun__set-variable` / `mcp__upsun__delete-variable` equivalents where available.

### Backup / Restore

- **Standard backup** causes a momentary pause (~15-30s) but guarantees data consistency across all containers.
- **Live backup** (`--live`): zero downtime, but services continue accepting writes during the snapshot, so data may be inconsistent across containers. Automated backups are always live.
- Restore: list available backups -> confirm target environment -> "This will overwrite [env] with backup [ID]. Proceed?"
- CLI: `upsun backup:create` / `upsun backup:restore`
- MCP: `mcp__upsun__create-backup` / `mcp__upsun__restore-backup` (if available)

### Scale / Resources

- Run `upsun resources:get` to show current allocations for all apps, workers, and services
- Show current allocations:
- CLI: `upsun resources:get`
- MCP: `mcp__upsun__get-resources`
- `upsun resources:set --size <name>:<cpu>` sets the CPU value for an app or service (e.g. `--size myapp:0.25,db:1`); RAM is derived from the container profile. Run `upsun resources:sizes` to list available sizes.
- Profiles (`HIGH_CPU`, `BALANCED`, `HIGH_MEMORY`, `HIGHER_MEMORY`) determine the RAM-per-CPU ratio and are set via `container_profile:` in `.upsun/config.yaml`, not via CLI.
- Horizontal scaling: `upsun resources:set --count <name>:<n>`. Each instance gets the full selected resources (not divided).
- Horizontal scaling: `upsun resources:set --count <name>:<n>` (CLI) or `mcp__upsun__set-resources` (MCP). Each instance gets the full selected resources (not divided).

### Domain

- SSL: auto (Let's Encrypt, default) or custom certificate?
- After adding: remind to update DNS records; propagation can take up to 48h
- CLI: `upsun domain:add` / `upsun domain:delete`
- MCP: `mcp__upsun__add-domain` / `mcp__upsun__delete-domain` (if available), otherwise use console.

---

## Confirm before any write operation

Show the exact CLI command and wait for explicit confirmation before running:

- `upsun push`, `upsun deploy`, `upsun redeploy`
- `upsun backup:restore`, `upsun backup:delete`
- `upsun environment:merge`, `upsun environment:deactivate`, `upsun environment:delete`, `upsun environment:pause`
- `upsun resources:set`, `upsun autoscaling:set`
- `upsun variable:create`, `upsun variable:update`, `upsun variable:delete`
- `upsun domain:add`, `upsun domain:delete`
- `upsun integration:add`, `upsun integration:delete`
Show the exact command (CLI or MCP tool call) and wait for explicit confirmation before running:

| Operation | CLI | MCP equivalent |
|-----------|-----|----------------|
| Push / deploy / redeploy | `upsun push`, `upsun deploy`, `upsun redeploy` | `mcp__upsun__deploy` |
| Backup restore / delete | `upsun backup:restore`, `upsun backup:delete` | `mcp__upsun__restore-backup` |
Comment thread
ganeshdipdumbare marked this conversation as resolved.
Outdated
| Environment merge / deactivate / delete / pause | `upsun environment:merge`, `:deactivate`, `:delete`, `:pause` | `mcp__upsun__merge-environment`, etc. |
| Resources | `upsun resources:set`, `upsun autoscaling:set` | `mcp__upsun__set-resources` |
| Variables | `upsun variable:create`, `:update`, `:delete` | `mcp__upsun__set-variable`, `:delete-variable` |
| Domain | `upsun domain:add`, `upsun domain:delete` | `mcp__upsun__add-domain` |
| Integration | `upsun integration:add`, `upsun integration:delete` | `mcp__upsun__add-integration` |

Read-only operations (`list`, `info`, `get`, `logs --tail`) do not require confirmation.

Expand Down
Loading