plugins/laravel-forge-hermit/skills/hatch/SKILL.md
One-time Laravel Forge hermit setup. Installs the Forge PHP SDK, verifies credentials, and wires the estate scan into config.json. Run once per project after /claude-code-hermit:hatch.
npx skillsauth add gtapps/claude-code-hermit hatchInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Idempotent setup wizard for the Laravel Forge plugin. Run after /claude-code-hermit:hatch has been completed.
Check whether .claude-code-hermit/config.json exists.
If it does not:
"The base hermit is not set up yet. Run
/claude-code-hermit:hatchfirst, then return here."
Use AskUserQuestion: "Would you like to run /claude-code-hermit:hatch now? (yes / no)"
claude-code-hermit:hatch):
.claude-code-hermit/state/hatch-resume.json with { "skill": "laravel-forge-hermit:hatch" }./laravel-forge-hermit:hatch.)"/claude-code-hermit:hatch via the Skill tool — terminal action, stop after the call.If it does exist, run .claude-code-hermit/bin/hermit-run domain-hatch preflight laravel-forge-hermit and parse the JSON verdict. Branch on action:
upgrade-core-package / upgrade-core-applied → relay the remedy string verbatim to the operator and stop.
verify → say:
"laravel-forge-hermit {self_version} is already installed. Reply 'verify' to re-run checks only, or 'full' to re-run the full wizard."
Use AskUserQuestion: "(verify / full)" — verify → skip to Step 4; full → continue from Step 2.
full → continue from Step 2.
ok: false → relay message and stop.
Check PHP version. Run php -r 'echo PHP_VERSION;' via Bash. Parse the output. If php is not found or the version is below 8.5.0, relay this and stop:
"PHP 8.5+ is required but not found (got: {version or 'not found'}).
- Docker: re-run
/docker-setupafter the core base image is updated to Ubuntu 26.04 (which ships PHP 8.5 natively). If the core base is still 24.04, the Docker path is blocked pending that upgrade.- Bare-metal: install
php8.5-cliandphp8.5-curl(or your distro's equivalent)."
Check Composer. Run composer --version. If not found, relay this and stop:
"Composer is not found. Install it from https://getcomposer.org/."
Install the Forge SDK into project space. The SDK goes into .claude-code-hermit/forge-runtime/ (hermit-owned, isolated from your app's own composer.json/vendor/).
Run these Bash commands:
mkdir -p .claude-code-hermit/forge-runtime
cp "${CLAUDE_PLUGIN_ROOT}/php/composer.json" .claude-code-hermit/forge-runtime/composer.json
cp "${CLAUDE_PLUGIN_ROOT}/php/composer.lock" .claude-code-hermit/forge-runtime/composer.lock
Idempotent install check: if .claude-code-hermit/forge-runtime/vendor/ exists and the staged composer.lock content matches ${CLAUDE_PLUGIN_ROOT}/php/composer.lock, skip the install. Otherwise run:
composer install --no-dev --no-interaction --working-dir=.claude-code-hermit/forge-runtime
If composer exits non-zero, surface the error. Common cause: egress blocked — packagist.org, repo.packagist.org, api.github.com, codeload.github.com must be reachable. In Docker, verify the DNS allowlist in DOCKER.md is present.
Do NOT use cat, grep, echo, or any Bash command to read .env. The FORGE_API_TOKEN key name contains TOKEN, which triggers the base hermit's deny-pattern hook on Bash args. Use the Read tool only — and only to check the file exists / has the key, never to relay the value.
Tell the operator:
"Add your Forge API credentials to
.envin the project root:FORGE_API_TOKEN=your-forge-api-token FORGE_ORG=your-org-slug # optional if you have exactly one orgGet your token at https://forge.laravel.com/profile/api. Reply 'done' when set, or 'skip' to continue (credential check happens in Step 4)."
Use AskUserQuestion: "(done / skip)"
Read the consumer's .gitignore (this file is not a secret — only the .env content is). Check if .env and .env.* patterns are present. If missing, offer to add them:
.env
.env.*
Append any missing patterns via Edit.
Run: php ${CLAUDE_PLUGIN_ROOT}/php/forge.php check
missing → tell the operator to add FORGE_API_TOKEN to .env and re-run Step 3.invalid → token found but API rejected it; tell the operator to check the token at https://forge.laravel.com/profile/api.unreachable → token present but the API could not be reached (network/egress blocked). In Docker, verify the DNS allowlist in DOCKER.md (forge.laravel.com). Re-run once connectivity is confirmed.ok → continue.If php is not found at this point: re-run Step 2.
Resolve target file: Step 1's preflight already returned target, target_file, target_default and needs_target_question.
If needs_target_question is true, ask with AskUserQuestion (header: "Visibility") — target_default at position 0 with (recommended): .local files (gitignored, operator-personal) / Committed files (shared with teammates). Then record it:
.claude-code-hermit/bin/hermit-run domain-hatch ensure-target laravel-forge-hermit --target <choice>
Then write the block:
.claude-code-hermit/bin/hermit-run domain-hatch sync-block laravel-forge-hermit
It appends the <!-- laravel-forge-hermit: Forge Workflow --> block when the marker is absent and skips when it is already present; hermit-evolve handles replacement on upgrade.
Read .claude-code-hermit/knowledge-schema.md.
Check for deploy-incident: in the file. If absent, append under ## Work Products:
- deploy-incident: per-failure deployment record with scrubbed log tail and resolution. Producer: forge-deploy skill on a failed terminal deploy status. location: compiled/deploy-incident-<site>-<YYYY-MM-DD>.md
Use Edit. Skip if already present (idempotent).
Re-read .claude-code-hermit/config.json now — the wizard has been running since Step 1 and the on-disk file may have changed. Apply the merges below to that fresh copy.
Stamp version: set _hermit_versions["laravel-forge-hermit"] to self_version from Step 1's preflight.
Merge scheduled check: check config.scheduled_checks for id: "forge-failed-deploys". If absent, append:
{"id": "forge-failed-deploys", "plugin": "laravel-forge-hermit", "skill": "laravel-forge-hermit:forge-failed-deploys", "enabled": true, "trigger": "interval", "interval_days": 1}
If present: skip (do not clobber).
Register runtime dir: ensure config.storage_drift exists and config.storage_drift.ignore is an array that includes "forge-runtime". If the key is absent, add "storage_drift": {"ignore": ["forge-runtime"]}. If the array exists but does not include "forge-runtime", append it. Skip if already present.
Write the updated config.json via Write tool (full file replacement for valid JSON).
laravel-forge-hermit {version} setup complete.
Installation summary:
✓ Prerequisite: claude-code-hermit {base_version} confirmed
✓ PHP 8.5+ found: {php_version}
✓ Composer found
✓ Forge SDK installed → .claude-code-hermit/forge-runtime/vendor/
✓ .env: FORGE_API_TOKEN present, API check: ok
✓ .gitignore: .env covered
✓ CLAUDE.md: Forge Workflow block injected (or already present)
✓ knowledge-schema.md: deploy-incident type added (or already present)
✓ config.json: _hermit_versions stamped, forge-failed-deploys check registered
Next steps:
- Restart Claude Code so the updated CLAUDE.md loads.
- Run /claude-code-hermit:hermit-routines load to activate the daily estate scan.
- In Docker: the forge-runtime/ vendor is in your project tree (bind-mounted/persistent) — it survives container restarts.
Installed skills:
/laravel-forge-hermit:forge-servers — list / detail / reboot servers
/laravel-forge-hermit:forge-sites — list / detail sites
/laravel-forge-hermit:forge-deploy — preview → approve → deploy
/laravel-forge-hermit:forge-logs — read site / server / deployment logs
/laravel-forge-hermit:forge-failed-deploys — daily estate scan (scheduled, interval_days: 1)
Security reminder: FORGE_API_TOKEN is in .env — verify it is gitignored before any git push.
Read by /claude-code-hermit:docker-security when the operator enables LAN containment + DNS policy.
tools
Composes and delivers the daily fitness brief — a forward-looking morning read (readiness + today's plan) or a backward-looking evening read (today's training, or an earned-rest note, + tomorrow's setup) — in the operator's configured voice. Invoke with /claude-code-fitness-hermit:fitness-brief --morning|--evening|--slot <name>. Becomes the plugin's two daily beats — the morning Strava connectivity check and the evening activity sync, RPE binding, and Run deep-dive.
development
Renew the hermit's long-lived Claude login token over the channel, before it expires. Relays a one-time sign-in link to the operator, takes the code back, installs the new token, and restarts. Activates on messages like 'relogin', 'renew my login', 'reauth', 'the login is expiring', or when doctor's credential-expiry check flags setup-token.
development
Synthesizes the past 7 days of archived briefs into a weekly digest — top stories, emerging vs faded themes, category activity, and per-source performance built from archive frontmatter. Delivers to the operator's configured channel and archives a weekly note. Designed as a weekly routine. Invoke with /feed-hermit:weekly-digest.
development
Manage developing story arcs tracked across briefs — add, resolve, and list active arcs in compiled/story-arcs-*.md. Arc Watch keywords drive the feed-brief arc-tagging enrichment. Invoke with /feed-hermit:story-arcs add|resolve|list.