Skip to content
Automation
Skill

/forge-deploy

Deploy a site on Laravel Forge. Always surface-then-approve (preview-deploy first, then deploy with native approval). Watches via the hermit /watch registry and writes a deploy-incident on failure. Triggers on "deploy", "trigger deployment", "deploy site", "run deployment",

From plugin
hermitd
8489 skills14 agents

Claude Code

$ npx -y skills add gtapps/hermitd --skill forge-deploy --agent claude-code

SKILL.md

forge-deploy.SKILL.md
name: forge-deploy
description: Deploy a site on Laravel Forge. Always surface-then-approve (preview-deploy first, then deploy with native approval). Watches via the hermit /watch registry and writes a deploy-incident on failure. Triggers on "deploy", "trigger deployment", "deploy site", "run deployment", "check deployment status".

Forge Deploy

Trigger a deployment on a Forge site. **Always preview before deploying.** A wrong deploy targets the wrong site — preview eliminates that risk.

---

Surface-then-approve flow

Step 1 — Preview (read-only, never mutates)

php ${CLAUDE_PLUGIN_ROOT}/php/forge.php preview-deploy <server> <site>

Resolves `<server>` and `<site>` to their canonical SDK records and prints:

{"server":{"id":12345,"name":"prod-web-01","ip_address":"1.2.3.4"},"site":{"id":67890,"name":"myapp.com"}}

No network write. A `status` of `no_match` or `ambiguous` instead lists `choices`: ask the operator which one they meant.

Step 2 — Relay canonical target to operator

Show the canonical server name, IP, site name, and IDs.

Step 3: Deploy

php ${CLAUDE_PLUGIN_ROOT}/php/forge.php deploy <server> <site>

This triggers the deployment and returns immediately (no blocking wait):

{"deploy_id":991,"server_id":12345,"site_id":67890,"deploy_status":"queued"}

Capture `deploy_id`, `server_id`, and `site_id`: Step 4 needs them.

Step 4 — Watch via the hermit watch registry (non-blocking)

Do **not** poll in a foreground Bash call: a real deploy can outlast the Bash tool timeout, which would kill the wait and skip the incident. Arm a hermit watch instead: it runs detached, notifies you on each status change and on the terminal state at zero token cost while quiet, and is tracked in `monitors.runtime.json` (visible via `/hermitd:watch status`, cancellable via `/hermitd:watch stop`, and cleaned up when the watch finishes or is stopped).

**Requires a running resident.** If the resident is unavailable, run `deploy-status <server-id> <site-id> <deploy-id>` manually; it prints `{"deploy_status":"..."}`.

Resolve `${CLAUDE_PLUGIN_ROOT}` to its **absolute path now** (at skill-execution time): the variable is NOT available inside the watch subprocess. Then arm the watch by invoking `/hermitd:watch` with this command (substitute the absolute path and the three IDs):

php /ABS/php/forge.php deploy-watch <server-id> <site-id> <deploy-id>

The `TERMINAL` line carries only numeric IDs (never display names) — Forge server names can contain spaces, which would break the space-delimited fields.

`/hermitd:watch` registers this as an ad-hoc watch. The loop stops itself after 180 polls or at the 15-minute deadline, whichever comes first, and ends with a `timeout` terminal line. It is otherwise quiet, emitting only on status change. On any `TERMINAL` line the command exits and core clears the registry entry automatically; that line carries everything Step 5 needs.

Step 5 — On the terminal watch event

When the `TERMINAL …` notification arrives:

  • **`status=finished`** → tell the operator the deploy succeeded, via the **Operator Notification protocol** (core resolves the channel; falls back to a push). No artifact.
  • **`status=failed` / `failed-build` / `cancelled`** → (1) fetch the log with `deploy-log <server-id> <site-id> <deploy-id>` using the numeric IDs from the `TERMINAL` line, **scrub it**, and write a `deploy-incident` artifact (template below); (2) notify the operator of the failure via the **Operator Notification protocol**, including the incident path.
  • **`status=timeout`** → the watch hit its ~15 min cap without reaching a terminal state. Notify the operator (via the **Operator Notification protocol**) that the deploy is still unresolved and point them at `deploy-history` / `deploy-status` to follow up. No incident — a timeout is not a confirmed failure.

Scrubbing happens here, in this step — never in the watch command. The watcher only emits metadata, so no raw log line is ever written by the unattended subprocess.

---

Deployment history

php ${CLAUDE_PLUGIN_ROOT}/php/forge.php deploy-history <server> <site>

Prints `{"deployments":[...]}`, each entry with `id`, `status`, and `commit` (the message, truncated).

Fetch a specific deployment log

php ${CLAUDE_PLUGIN_ROOT}/php/forge.php deploy-log <server> <site> <deploy-id>

---

deploy-incident artifact (written in Step 5 on a failed terminal status)

**File**: `compiled/deploy-incident-<site-name>-<YYYY-MM-DD>.md`

**Content template**:

---
title: Deploy incident — <site-name> <YYYY-MM-DD>
created: <ISO timestamp>
type: deploy-incident
tags: [deploy, failure, <site-name>]
---

## Incident

- Site: <site-name> (ID: <site-id>)
- Server: <server-name> (ID: <server-id>, IP: <ip>)
- Deployment ID: <deploy-id>
- Status: <failed|failed-build|cancelled>
- Detected: <timestamp>

## Commit

<commit message, if available>

## Log tail (scrubbed)

<last ~50 lines of the deployment log, **scrubbed of any credentials, env vars, or secrets**>

## Resolution

(fill in after incident is resolved)

**Secret hygiene (critical):** deployment logs frequently contain env dumps, DB connection strings, and API keys. **Never paste raw log content** — always scrub before writing. Fetch the log with `deploy-log`, review it, then excerpt only the error-relevant lines with any credential values redacted (`[REDACTED]`).

---

Notes

  • `<server>` and `<site>` accept name, hostname, URL hostname, or numeric ID. An unmatched or ambiguous name returns `status` `no_match` or `ambiguous` with `choices`, and nothing runs.
  • Claude Code requests native approval before deploy and reboot execution.
  • For reading logs without a deploy action, use `/hermitd-laravel-forge:forge-logs`.
Read more
@gtapps
Ships withhermitd

Run an always-on Claude Code agent on your own machine, for you or your team. Start and orchestrate sessions from chat in any project it can reach. Take over the same session in the Claude app or the CLI.

8489 skills14 agents
Get the whole plugin

Stars on GitHub

Momentum

stars in total
84
Star history of gtapps/claude-code-hermit on GitHub, a chart by star-history.com

Other skills on hermitd.

bump-core-req

bump-core-req

Updates the minimum core version requirement for a fleet plugin in all three canonical places: `required_core_version` and…

@gtapps@gtappsInstall Skill
commit

commit

Changelog and commit — lightweight motion for day-to-day plugin dev work in the monorepo. One commit per plugin scope; CHANGELOG…

@gtapps@gtappsInstall Skill
docs-drift

docs-drift

Documentation-drift audit for the plugin monorepo. Audits either each scoped plugin's unreleased changelog claims or its latest…

@gtapps@gtappsInstall Skill
downstream-impact

downstream-impact

Explain in plain language what a fix, feature, PR, or plan will actually change for downstream hermits and the operators chatting…

@gtapps@gtappsInstall Skill
fleet-release

fleet-release

Use this skill whenever the user wants to release, ship, prep, or cut versions for two or more plugins together on the current…

@gtapps@gtappsInstall Skill
pipeline-digest

pipeline-digest

Daily release-pipeline digest with a change gate — reports which plugins are pending release, whether main's CI is green, which…

@gtapps@gtappsInstall Skill

More skills from other plugins.

agent-builder

agent-builder

Load immediately after an Agent intent, before the first agent_builder_* call. Governs how you create, configure, test, and…

n8n12d209k
@n8n-io@n8n-ioInstall Skill
browser-use

browser-use

Direct browser control via CDP for web interaction: automation, scraping, testing, screenshots, and site/app work. Also covers…

@browser-use@browser-useInstall Skill
agent-browser

agent-browser

Browser automation CLI for AI agents. Use when the user needs to interact with websites, including navigating pages, filling…

@vercel-labs-2@vercel-labs-2Install Skill
add-anydoc

add-anydoc

Add local office-document-to-Markdown conversion to NanoClaw agent containers with the pinned Firecrawl AnyDoc CLI. Use when…

@nanocoai@nanocoaiInstall Skill

Questions about forge-deploy.

Which coding agents can use forge-deploy?
forge-deploy installs in Claude Code, Codex, Cursor, Gemini CLI, GitHub Copilot, OpenCode and Windsurf with the skills CLI, using each agent's flag shown on this page. Flowy's auto-invocation, which fires a skill when your prompt matches, runs in Claude Code only.