Skip to content
Back to skills

Deploio Manage

ASecurity

Day-to-day operations on a running Deploio app — config changes, routine log monitoring, console/exec access, and redeployments. This skill should be triggered for: "change env vars", "scale app", "add worker", "cron job", "scheduled job", "custom domain", "retry build", "deploy new version", "tail logs", "show me the logs", "open rails console", "run a rake task", "exec into app", "run a command in the app", "health probe", "basic auth", "check app status", "what apps do I have", "rollback d...

  • 3 stars
  • 0 votes
  • 0 copies
  • 6 views
  • Added May 28, 2026
devopsgorubyshellbashsqlnoderailsgitapidatabase

Works with

  • cli
  • api

Security analysis

A92/100
  • mediumUses curl or wget to download content

Pro scans all 2 files and shows the line behind each finding

Scanned May 28, 2026

npx -y skills add renuo/deploio-claude-plugin --skill deploio-manage --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Deploio Manage?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Deploio Manage
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/renuo-deploio-manage/badge)](https://www.skillsdirectory.com/skills/renuo-deploio-manage)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: deploio-manage
description: Day-to-day operations on a running Deploio app — config changes, routine log monitoring, console/exec access, and redeployments. This skill should be triggered for: "change env vars", "scale app", "add worker", "cron job", "scheduled job", "custom domain", "retry build", "deploy new version", "tail logs", "show me the logs", "open rails console", "run a rake task", "exec into app", "run a command in the app", "health probe", "basic auth", "check app status", "what apps do I have", "rollback deploy", "restart app", "previous version", "revert to last working". Do NOT use for first-time app creation (use deploio-deploy), diagnosing a crash or error (use deploio-debug), or provisioning databases/storage (use deploio-provision).
license: MIT
metadata:
  version: 1.5.0
---

# Deploio: Managing a Running App

Your role is coordinator. You never run commands yourself — you spawn `deploio-cli` agents with `mode: bypassPermissions` for all execution. Identify the operation, inspect current state if needed, confirm impactful changes, then execute.

**Communication style:** Speak to the user in plain language — describe what you'll do, never show raw nctl commands. Say "I'll add the Sidekiq worker to your app" not "I'll run `nctl update app ... --worker-job-name=sidekiq`". Agents manage the CLI entirely on the user's behalf.

---

## Phase 0: Identify operation from context

**Autoinfer app and project before asking.** Run:
```bash
git remote get-url origin   # https://github.com/acme/myapp → repo name only (not the org)
  nctl auth whoami             # → active organization (marked with *)
git branch --show-current   # main → app=main
```
Derive: `app = <branch>` (e.g. `main`), `org` from the `*`-marked entry in `nctl auth whoami` (not the git URL), `project = <org>-<repo>` (e.g. `renuotest-myapp` — never just `<repo>`; nctl errors).

State your inference inline: *"Using app `main` in project `renuotest-myapp` (org `renuotest`) — let me know if that's different."* Proceed immediately. Only ask explicitly if there is no git remote configured, or if a subsequent nctl command fails because the organization doesn't exist.

From the conversation, also determine:
- **Operation** — from the table below

| User says | Operation | Go to |
|---|---|---|
| "show logs", "tail logs", "what do the logs say" | `logs-app` | → Logs |
| "build logs", "watch the build" | `logs-build` | → Logs |
| "rails console", "rails c", "open a shell", "run a command", "exec", "rake task" | `exec` | → Exec |
| "list apps", "what apps do I have", "check status", "is it running", "resource usage" | `inspect` | → Inspect |
| "basic auth credentials", "get the password" | `basic-auth-credentials` | → Inspect |
| "deploy new version", "change branch", "redeploy" | `git-revision` | → Execute |
| "retry build", "force rebuild" | `retry-build` | → Execute |
| "re-deploy", "retry release" | `retry-release` | → Execute |
| "add / change env var" | `env` | → Execute |
| "change build env", "change Ruby version", "change Node version" | `build-env` | → Execute |
| "scale", "more replicas" | `replicas` | → Execute |
| "upsize", "change size" | `size` | → Execute |
| "custom domain", "add host" | `hosts` | → Execute |
| "health check", "health probe" | `health-probe` | → Execute |
| "enable basic auth", "disable basic auth" | `basic-auth` | → Execute |
| "add worker", "Sidekiq", "good_job" | `worker-job` | → Execute |
| "remove worker", "delete worker" | `delete-worker-job` | → Execute |
| "add scheduled job", "add cron", "scheduled task" | `scheduled-job` | → Execute |
| "remove scheduled job", "remove cron" | `delete-scheduled-job` | → Execute |
| "run migrations on deploy", "deploy job" | `deploy-job` | → Execute |
| "disable deploy job", "remove deploy job" | `delete-deploy-job` | → Execute |
| "move repo", "change git URL" | `git-url` | → Execute |
| "rollback", "previous version", "revert deploy", "go back to last working" | `rollback` | → Execute |
| "restart app", "restart the app" | `restart` | → Execute |
| "pause app", "stop billing", "hibernate" | `pause` | → Execute |
| "resume app", "unpause", "start app" | `resume` | → Execute |
| "copy app", "duplicate app", "clone app" | `copy` | → Execute |

**For rollback:** explain the mechanism in plain terms: "I'll pull your release history, show you the available versions, then redeploy the one you choose."

---

## Logs

Routine log monitoring during operations. No confirmation needed — read-only.

Spawn the `deploio-cli` agent with `mode: bypassPermissions`:

```
task: logs
app: <app-name>
project: <project>
type: app | worker_job | deploy_job | scheduled_job  # "build" uses nctl logs build, not --type
follow: true | false
lines: <n>
since: <duration>  # format: 1s | 1m | 1h | 48h
```

### App logs

Log types for `--type`: `app` (default runtime output), `worker_job`, `deploy_job`, `scheduled_job`. Build logs use a separate `nctl logs build` command (see below).

```bash
# Follow live (most common)
nctl logs app <name> --project <project> -f

# Last N lines
nctl logs app <name> --project <project> -l 500

# Go back in time (1s, 1m, 1h, 48h)
nctl logs app <name> --project <project> -s 2h

# By type
nctl logs app <name> --project <project> -f --type worker_job
nctl logs app <name> --project <project> -f --type deploy_job
nctl logs app <name> --project <project> -f --type scheduled_job

# Clean output without metadata labels
nctl logs app <name> --project <project> -f --no-labels
```

### Build logs

Build logs live under `nctl logs build`, not `nctl logs app --type build`.

```bash
# Latest build for an app (-a = latest build for this app name)
nctl logs build <app-name> --project <project> -a
nctl logs build <app-name> --project <project> -a -l 5000

# Specific build by name
nctl get builds --project <project>               # find the build name
nctl logs build <build-name> --project <project>
nctl logs build <build-name> --project <project> -f
nctl logs build <build-name> --project <project> -l 5000
```

> Use `nctl logs build -a` when the user says "show me the build logs" — it fetches the latest automatically without needing to know the build name.

---

## Exec

Run commands or open a shell inside a running app container. Routine operational use — Rails console, rake tasks, env inspection. For *diagnosing a crash or error*, use deploio-debug instead.

Always ask before running anything destructive (`db:reset`, `db:drop`, `db:seed:replant`).

Spawn the `deploio-cli` agent with `mode: bypassPermissions`:

```
task: exec
app: <app-name>
project: <project>
command: <command>
```

The agent runs `nctl exec app <name> --project <project> -- <command>`.

> **Database connections:** When the user wants to connect to the database, the exec agent should:
> 1. Attempt `rails dbconsole` (or `psql`) inside the container
> 2. If the connection is refused due to an IP restriction, automatically:
>    - Retrieve the user's current IP: `curl -s https://api.ipify.org`
>    - Find the database name from the app's `DATABASE_URL` env var
>    - Add the IP to the allowlist: `nctl update postgresdatabase <db-name> --allowed-cidrs=<ip>/32`
>    - Retry the connection
> 3. Report the outcome in plain terms — no nctl syntax in the user-facing message

### Common patterns

```bash
# Rails console (most common)
nctl exec app <name> --project <project> -- bundle exec rails console
nctl exec app <name> --project <project> -- bin/rails c
nctl exec app <name> --project <project> -- rails c

# Interactive shell
nctl exec app <name> --project <project> -- bash

# Rails runner (non-interactive, good for quick queries)
nctl exec app <name> --project <project> -- bundle exec rails runner "puts User.count"
nctl exec app <name> --project <project> -- bundle exec rails runner "puts User.find(42).inspect"

# Rake tasks
nctl exec app <name> --project <project> -- bundle exec rake db:version
nctl exec app <name> --project <project> -- bundle exec rake db:seed
nctl exec app <name> --project <project> -- bundle exec rails db:seed:replant

# Check env vars
nctl exec app <name> --project <project> -- env | grep DATABASE
nctl exec app <name> --project <project> -- env | grep REDIS

# Destructive — always confirm explicitly before running
nctl exec app <name> --project <project> -- DISABLE_DATABASE_ENVIRONMENT_CHECK=1 bundle exec rails db:seed:replant
```

> `exec` connects to the **first available replica**. In multi-replica setups, use logs to correlate which replica is relevant.

---

## Inspect

Read-only checks. No confirmation needed.

Spawn the `deploio-cli` agent with `mode: bypassPermissions`:

```
task: inspect
app: <app-name>   # optional for list-apps
project: <project>
view: summary | yaml | stats | dns | basic-auth-credentials
```

```bash
# Status + URL
nctl get app <name> --project <project>

# Full config (env var keys, hosts, workers, jobs)
nctl get app <name> --project <project> -o yaml

# Check a specific env var value
nctl get app <name> --project <project> -o yaml | grep DATABASE_URL

# CPU, memory, restart counts per replica
# Columns: REPLICA, STATUS, CPU (millicores), CPU%, MEMORY (MiB), MEMORY%, RESTARTS, LASTEXITCODE
# Exit code 137 = OOM or storage limit exceeded
nctl get app <name> --project <project> -o stats

# DNS records for custom domain setup
nctl get app <name> --project <project> --dns

# Basic auth username + password
nctl get app <name> --project <project> --basic-auth-credentials

# All apps in a project
nctl get apps --project <project>

# All apps across every project (with stats)
nctl get apps -A
nctl get apps -A -o stats
```

---

## Phase 1: Inspect before changes

For update operations, inspect current state first to detect conflicts.

```
task: inspect
app: <app-name>
project: <project>
view: yaml
```

Returns:
```json
{
  "status": "Running | Pending | Failed",
  "current_revision": "main",
  "current_size": "mini",
  "replicas": 1,
  "env_var_keys": ["RAILS_ENV", "DATABASE_URL"],
  "hosts": ["myapp.deploio.app"],
  "workers": [{ "name": "sidekiq", "command": "bundle exec sidekiq", "size": "mini" }],
  "scheduled_jobs": [],
  "deploy_job": null,
  "health_probe_path": null,
  "basic_auth_enabled": false
}
```

---

## Phase 2: Confirm before executing

Use `AskUserQuestion` for any impactful operation (env var changes, scaling, size changes, rollbacks, worker/job mutations). Show the current → new value diff before asking:

**Env var change:**
```
Updating myapp:

| Variable | Current | New |
|---|---|---|
| RAILS_ENV | production | production (unchanged) |
| DATABASE_URL | *not set* | postgres://... |
```

```
question: "Apply this change?"
options:
  - "Yes, proceed"
  - "No, cancel"
```

**Scale / size change:**
```
Scaling myapp:

| Setting | Current | New |
|---|---|---|
| Replicas | 1 | 3 |
| Size | mini | standard-1 (billing impact) |
```

```
question: "Apply this change?"
options:
  - "Yes, proceed"
  - "No, cancel"
```

- **Retry build / retry release** — no confirmation needed.
- **Logs / exec / inspect** — no confirmation needed.
- **Destructive exec** (`db:reset`, `db:seed:replant`) — always use `AskUserQuestion` with an explicit "Yes, I understand this is destructive" option.

If the user says "No, cancel" — do not spawn the executor.

---

## Phase 3: Execute

Spawn the `deploio-cli` agent with `mode: bypassPermissions`:

```
task: update
app: <app-name>
project: <project>
operation: <operation>
values: <values>
```

### nctl commands by operation

**Deploy new version / change branch:**
```bash
nctl update app <name> --project <project> --git-revision=<branch|tag|sha>
# Pin to exact local commit:
nctl update app <name> --project <project> --git-revision=$(git rev-parse <branch>)
```

**Force rebuild** (after dependency changes or build env change):
```bash
nctl update app <name> --project <project> --retry-build
```

**Re-deploy existing build** (skip rebuild, re-run release):
```bash
nctl update app <name> --project <project> --retry-release
```
- `--retry-release`: migration failed transiently, config-only change, transient infra issue
- `--retry-build`: build failed, dependency changed, build-time env var changed

**Add / update runtime env vars** (additive — other keys untouched):
```bash
nctl update app <name> --project <project> \
  --env=KEY1=VALUE1 \
  --env=KEY2=VALUE2
```

**Add / update build-time env vars** (triggers a rebuild):
```bash
nctl update app <name> --project <project> \
  --build-env=RUBY_VERSION=3.3.3 \
  --build-env=NODE_VERSION=20
```

**Scale replicas:**
```bash
nctl update app <name> --project <project> --replicas=<n>
```

**Change instance size** (`micro` | `mini` | `standard-1` | `standard-2`):
```bash
nctl update app <name> --project <project> --size=<size>
```

**Add / update custom hostname:**
```bash
nctl update app <name> --project <project> --hosts=myapp.example.com,www.myapp.example.com
# Get DNS records to configure at the registrar:
nctl get app <name> --project <project> --dns
```

**Configure health probe** (Rails default is `/up`):
```bash
nctl update app <name> --project <project> \
  --health-probe-path="/up" \
  --health-probe-period-seconds=5
```

**Toggle basic auth** (HTTP basic auth in front of the app):
```bash
nctl update app <name> --project <project> --basic-auth=true
nctl update app <name> --project <project> --basic-auth=false
# Retrieve the generated credentials after enabling:
nctl get app <name> --project <project> --basic-auth-credentials
```

**Add / update background worker** (Sidekiq, GoodJob, etc.), up to 3 per app:
```bash
nctl update app <name> --project <project> \
  --worker-job-name=sidekiq \
  --worker-job-command="bundle exec sidekiq" \
  --worker-job-size=mini

# GoodJob:
nctl update app <name> --project <project> \
  --worker-job-name=good-job \
  --worker-job-command="bundle exec good_job start" \
  --worker-job-size=mini
```

**Remove a worker:**
```bash
nctl update app <name> --project <project> --delete-worker-job=<worker-name>
```

**Add / update scheduled job** (Deploio's term for time-triggered jobs — not "cron jobs"):
```bash
nctl update app <name> --project <project> \
  --scheduled-job-name=cleanup \
  --scheduled-job-command="rake cleanup:old_records" \
  --scheduled-job-schedule="0 2 * * *" \
  --scheduled-job-size=micro
```

**Remove a scheduled job:**
```bash
nctl update app <name> --project <project> --delete-scheduled-job=<job-name>
```

**Add / update deploy job** (runs before each release; default timeout 5m, max 30m; default retries 3, max 5):
```bash
nctl update app <name> --project <project> \
  --deploy-job-command="bundle exec rake db:prepare" \
  --deploy-job-name="migrate-database" \
  --deploy-job-timeout=10m \
  --deploy-job-retries=1
```

**Rollback to a previous version:**
```bash
# Find the last working git SHA from release history
nctl get releases <name> --project <project>

# Pin to the SHA of the last working release
nctl update app <name> --project <project> --git-revision=<sha>
```

> A rollback is just a redeploy to an earlier commit. Show the release history from Phase 1 inspect output and ask the user which release to roll back to.

**Restart the app** (re-deploy existing build without changes):
```bash
nctl update app <name> --project <project> --retry-release
```

**Remove a deploy job:**
```bash
nctl update app <name> --project <project> --delete-deploy-job=<job-name>
```
> If `--delete-deploy-job` is not accepted by your version of nctl, use `nctl edit app <name> --project <project>` and remove the `deployJob` field from the YAML.

**Rotate SSH deploy key:**
```bash
nctl update app <name> --project <project> \
  --git-ssh-private-key-from-file=<path-to-key>
```

**Move repo / change git URL:**
```bash
nctl update app <name> --project <project> --git-url=https://github.com/neworg/repo
```

**Pause app** (scales to 0 replicas — stops billing; app URL returns 503 while paused):
```bash
nctl update app <name> --project <project> --replicas=0
```

**Resume / unpause app:**
```bash
nctl update app <name> --project <project> --replicas=1
```

**Copy / duplicate app** (starts paused by default, allowing review before activation):
```bash
# Copy within same project
nctl copy application <name> --target-name=<new-name>

# Copy to a different project
nctl copy application <name> --target-name=<new-name> --target-project=<project>

# Copy and start immediately
nctl copy application <name> --target-name=<new-name> --start

# Copy and include custom hosts (must be re-verified on new app)
nctl copy application <name> --target-name=<new-name> --copy-hosts
```

The executor reports back:
- `{ "status": "triggered" }` — command accepted, release in progress
- `{ "status": "failed", "error": "<nctl output>" }` — command rejected

---

## Phase 4: Watch the release

> **App `Ready=True` ≠ latest build succeeded.** Deploio may attempt a rebuild against git HEAD on *any* update, including env-only changes. The app can stay Running on a prior successful build while the newest build fails silently. Always check `nctl get builds` after a release — even config-only ones — and verify the live release is pinned to the newest build.

Create a task with `TaskCreate` when the release starts:

```
title: "Deploying <app-name>"
status: in_progress
```

After the executor confirms, spawn a **monitor agent** with `mode: bypassPermissions`:

```
task: watch-release
app: <app-name>
project: <project>
termination: stop ONLY when ALL three hold —
  1. App Ready=True
  2. Latest build status is Succeeded
  3. Live release is pinned to that latest build
Otherwise stop on Failed or after 10 minutes.
```

The monitor polls all three signals every cycle, not just app status:

```bash
nctl get app <name> --project <project> --watch              # app readiness
nctl get builds --project <project> | head                    # latest build status (Succeeded / Failed / Errored)
nctl get releases <name> --project <project> | head           # which build the live release is pinned to
# If deploy job configured:
nctl logs app <name> --project <project> --type deploy_job -f
```

Surface these signals explicitly, not as parentheticals:

- **Latest build failed** — if the most recent entry from `nctl get builds` is Failed/Errored, flag it immediately, regardless of which release is live and regardless of whether the app is Running.
- **Version regression on release name** — if the new release's BUILDNAME numerically precedes the prior release's, report it: *"⚠ New release is on build `<older>`, but the previous release was on build `<newer>`. Platform fell back to an older build — the newer build attempt likely failed."*

Relay meaningful status changes:
> "[30s] Release in progress — running deploy job..."
> "[90s] App is Running ✓ — release pinned to build `<X>`, which succeeded."

On success, call `TaskUpdate` with `status: completed`.
On failure, call `TaskUpdate` with `status: failed`.

The final summary must always include a build-status line in plain language, on top of the HTTP sanity check:

> "App is Running (release `<X>` on build `<Y>`). Latest build attempt: `<Z>` — status: Succeeded/Failed."

On success:
```
Update applied. App is running.

What's next?
  → Tail the logs       — I can follow them for you
  → Open rails console  — I can exec in
  → Debug an issue      — use deploio-debug
  → Add a database      — use deploio-provision
```

On failure, translate the error and suggest a fix using the table below.

---

## Configuration layers

Deploio config flows: **Organization → Project → App** (lower layers override). For the full reference including how to set project-wide defaults, read `skills/deploio-manage/references/config-layers.md`.

---

## Common update issues

| Symptom | Likely cause | Fix |
|---|---|---|
| Update triggers rebuild unexpectedly | Using `--env` for a build-time var | Use `--build-env` for build-time vars, `--env` for runtime only |
| Deploy job not running | `--deploy-job-name` or `--deploy-job-command` missing | Both `--deploy-job-name` and `--deploy-job-command` are required |
| Deploy job times out | Slow migration | Increase `--deploy-job-timeout=15m` |
| App running but new code not live | Revision not changed | Check `nctl get app <name> -o yaml` for current SHA |
| Host not resolving after `--hosts` | DNS not configured | Run `nctl get app <name> --dns` and set CNAME/TXT at registrar |
| Worker not appearing after update | Name conflict | List existing workers with `nctl get app <name> -o yaml` |
| Worker not deleted | Wrong flag used | Use `--delete-worker-job` for workers, `--delete-scheduled-job` for crons |
| Health probe causing restart loop | Wrong path | Rails default is `/up` — verify it returns 200 |
| Scale command accepted but no new replicas | Project quota | Try a smaller size or contact Deploio support |
| `exec` connects to wrong replica | Multi-replica app | `exec` always uses the first available — use logs to correlate |

Files in this skill

  • SKILL.md20.7 KB
  • references/config-layers.md1.2 KB

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.