Skip to content

Commit 2b036d7

Browse files
committed
feat: add github and forge Claude Code skills
Add GitHub Issues/Projects management skill and Laravel Forge server management skill for use with Claude Code agents.
1 parent 6d104b7 commit 2b036d7

2 files changed

Lines changed: 791 additions & 0 deletions

File tree

.claude/skills/forge/SKILL.md

Lines changed: 317 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,317 @@
1+
---
2+
name: forge
3+
description: Manage Laravel Forge servers, sites, deployments, environment variables, SSL, daemons, scheduled jobs, and nginx config via the Forge REST API. Use when the user wants to deploy, check deployment status, manage .env, or perform any Forge server/site operation.
4+
origin: custom
5+
---
6+
7+
# Laravel Forge
8+
9+
Manage Laravel Forge infrastructure via the REST API (`curl`) or `forge-cli`.
10+
11+
## When to Activate
12+
13+
- User wants to deploy a site or check deployment status/logs
14+
- User wants to view/edit `.env` variables on a Forge-managed server
15+
- User wants to manage SSL certificates, daemons, cron jobs, nginx config
16+
- User mentions "forge" in the context of server management
17+
- User shares a `forge.laravel.com` URL
18+
19+
## Configuration
20+
21+
### API Token
22+
23+
The skill requires a Forge API token. Check for it in this order:
24+
25+
1. Environment variable: `FORGE_API_TOKEN`
26+
2. Ask the user to provide it (generated at Forge Dashboard > Account > API Tokens)
27+
28+
Store the base URL and headers as variables for reuse:
29+
30+
```bash
31+
FORGE_API="https://forge.laravel.com/api/v1"
32+
FORGE_TOKEN="${FORGE_API_TOKEN}"
33+
```
34+
35+
Every request MUST include:
36+
```
37+
Authorization: Bearer $FORGE_TOKEN
38+
Accept: application/json
39+
Content-Type: application/json
40+
```
41+
42+
### Parsing Forge URLs
43+
44+
When the user provides a Forge URL like:
45+
```
46+
https://forge.laravel.com/{username}/{server-name}/{serverId}/deployments
47+
```
48+
49+
Extract the `serverId` from the URL path (the numeric segment). You still need the `siteId` — list sites on that server to find it.
50+
51+
## API Reference
52+
53+
### Servers
54+
55+
```bash
56+
# List all servers
57+
curl -s "$FORGE_API/servers" -H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json" | jq '.servers[] | {id, name, ip_address, type, provider}'
58+
59+
# Get server details
60+
curl -s "$FORGE_API/servers/$SERVER_ID" -H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json" | jq '.server'
61+
62+
# Reboot server (DANGEROUS - confirm with user first)
63+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/reboot" -H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json"
64+
```
65+
66+
### Sites
67+
68+
```bash
69+
# List sites on a server
70+
curl -s "$FORGE_API/servers/$SERVER_ID/sites" -H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json" | jq '.sites[] | {id, name, directory, repository, deployment_status}'
71+
72+
# Get site details
73+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID" -H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json" | jq '.site'
74+
```
75+
76+
### Deployments
77+
78+
```bash
79+
# Trigger deployment
80+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment/deploy" \
81+
-H "Authorization: Bearer $FORGE_TOKEN" \
82+
-H "Accept: application/json"
83+
84+
# Get latest deployment log
85+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment/log" \
86+
-H "Authorization: Bearer $FORGE_TOKEN" \
87+
-H "Accept: application/json"
88+
89+
# List deployment history
90+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployments" \
91+
-H "Authorization: Bearer $FORGE_TOKEN" \
92+
-H "Accept: application/json" | jq '.deployments[] | {id, status, commit_hash, commit_author, started_at, ended_at}'
93+
94+
# Get specific deployment output
95+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployments/$DEPLOYMENT_ID/output" \
96+
-H "Authorization: Bearer $FORGE_TOKEN" \
97+
-H "Accept: application/json"
98+
99+
# Get deployment script
100+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment/script" \
101+
-H "Authorization: Bearer $FORGE_TOKEN" \
102+
-H "Accept: application/json"
103+
104+
# Update deployment script
105+
curl -s -X PUT "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment/script" \
106+
-H "Authorization: Bearer $FORGE_TOKEN" \
107+
-H "Accept: application/json" \
108+
-H "Content-Type: application/json" \
109+
-d '{"content": "cd /home/forge/site\ngit pull origin main\ncomposer install --no-dev\nphp artisan migrate --force\nphp artisan config:cache\nphp artisan route:cache\nphp artisan view:cache"}'
110+
111+
# Enable quick deploy (auto-deploy on git push)
112+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment" \
113+
-H "Authorization: Bearer $FORGE_TOKEN" \
114+
-H "Accept: application/json"
115+
116+
# Disable quick deploy
117+
curl -s -X DELETE "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment" \
118+
-H "Authorization: Bearer $FORGE_TOKEN" \
119+
-H "Accept: application/json"
120+
```
121+
122+
### Environment Variables (.env)
123+
124+
```bash
125+
# Get .env content
126+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/env" \
127+
-H "Authorization: Bearer $FORGE_TOKEN" \
128+
-H "Accept: application/json"
129+
130+
# Update .env (replaces the ENTIRE file - always GET first, modify, then PUT)
131+
curl -s -X PUT "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/env" \
132+
-H "Authorization: Bearer $FORGE_TOKEN" \
133+
-H "Accept: application/json" \
134+
-H "Content-Type: application/json" \
135+
-d '{"content": "APP_NAME=MyApp\nAPP_ENV=production\n..."}'
136+
```
137+
138+
**WARNING:** The .env PUT replaces the entire file. Always read the current .env first, modify the specific values, then write back the full content.
139+
140+
### SSL Certificates
141+
142+
```bash
143+
# List certificates
144+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/certificates" \
145+
-H "Authorization: Bearer $FORGE_TOKEN" \
146+
-H "Accept: application/json"
147+
148+
# Request Let's Encrypt certificate
149+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/certificates/letsencrypt" \
150+
-H "Authorization: Bearer $FORGE_TOKEN" \
151+
-H "Accept: application/json" \
152+
-H "Content-Type: application/json" \
153+
-d '{"domains": ["example.com", "www.example.com"]}'
154+
155+
# Activate certificate
156+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/certificates/$CERT_ID/activate" \
157+
-H "Authorization: Bearer $FORGE_TOKEN" \
158+
-H "Accept: application/json"
159+
160+
# Delete certificate
161+
curl -s -X DELETE "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/certificates/$CERT_ID" \
162+
-H "Authorization: Bearer $FORGE_TOKEN" \
163+
-H "Accept: application/json"
164+
```
165+
166+
### Databases
167+
168+
```bash
169+
# List databases
170+
curl -s "$FORGE_API/servers/$SERVER_ID/databases" \
171+
-H "Authorization: Bearer $FORGE_TOKEN" \
172+
-H "Accept: application/json"
173+
174+
# Create database
175+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/databases" \
176+
-H "Authorization: Bearer $FORGE_TOKEN" \
177+
-H "Accept: application/json" \
178+
-H "Content-Type: application/json" \
179+
-d '{"name": "my_database", "user": "my_user", "password": "secret"}'
180+
181+
# Delete database (DANGEROUS - confirm with user)
182+
curl -s -X DELETE "$FORGE_API/servers/$SERVER_ID/databases/$DB_ID" \
183+
-H "Authorization: Bearer $FORGE_TOKEN" \
184+
-H "Accept: application/json"
185+
```
186+
187+
### Daemons (Supervisor)
188+
189+
```bash
190+
# List daemons
191+
curl -s "$FORGE_API/servers/$SERVER_ID/daemons" \
192+
-H "Authorization: Bearer $FORGE_TOKEN" \
193+
-H "Accept: application/json"
194+
195+
# Create daemon
196+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/daemons" \
197+
-H "Authorization: Bearer $FORGE_TOKEN" \
198+
-H "Accept: application/json" \
199+
-H "Content-Type: application/json" \
200+
-d '{"command": "php /home/forge/site/artisan queue:work --sleep=3 --tries=3", "user": "forge", "directory": "/home/forge/site", "processes": 1, "startsecs": 1}'
201+
202+
# Restart daemon
203+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/daemons/$DAEMON_ID/restart" \
204+
-H "Authorization: Bearer $FORGE_TOKEN" \
205+
-H "Accept: application/json"
206+
207+
# Delete daemon
208+
curl -s -X DELETE "$FORGE_API/servers/$SERVER_ID/daemons/$DAEMON_ID" \
209+
-H "Authorization: Bearer $FORGE_TOKEN" \
210+
-H "Accept: application/json"
211+
```
212+
213+
### Scheduled Jobs (Cron)
214+
215+
```bash
216+
# List jobs
217+
curl -s "$FORGE_API/servers/$SERVER_ID/jobs" \
218+
-H "Authorization: Bearer $FORGE_TOKEN" \
219+
-H "Accept: application/json"
220+
221+
# Create job
222+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/jobs" \
223+
-H "Authorization: Bearer $FORGE_TOKEN" \
224+
-H "Accept: application/json" \
225+
-H "Content-Type: application/json" \
226+
-d '{"command": "php /home/forge/site/artisan schedule:run", "frequency": "minutely", "user": "forge"}'
227+
228+
# Delete job
229+
curl -s -X DELETE "$FORGE_API/servers/$SERVER_ID/jobs/$JOB_ID" \
230+
-H "Authorization: Bearer $FORGE_TOKEN" \
231+
-H "Accept: application/json"
232+
```
233+
234+
Frequency values: `minutely`, `hourly`, `nightly`, `weekly`, `monthly`, `reboot`, `custom`.
235+
236+
### Nginx Configuration
237+
238+
```bash
239+
# Get nginx config
240+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/nginx" \
241+
-H "Authorization: Bearer $FORGE_TOKEN" \
242+
-H "Accept: application/json"
243+
244+
# Update nginx config (replaces entire config - GET first, modify, PUT back)
245+
curl -s -X PUT "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/nginx" \
246+
-H "Authorization: Bearer $FORGE_TOKEN" \
247+
-H "Accept: application/json" \
248+
-H "Content-Type: application/json" \
249+
-d '{"content": "server { ... }"}'
250+
```
251+
252+
## Workflow Patterns
253+
254+
### Deploy and Watch
255+
256+
```bash
257+
# 1. Trigger deployment
258+
curl -s -X POST "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment/deploy" \
259+
-H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json"
260+
261+
# 2. Check site status for deployment_status
262+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID" \
263+
-H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json" | jq '.site.deployment_status'
264+
# null = idle, "deploying" = in progress
265+
266+
# 3. Once done, check deployment log
267+
curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/deployment/log" \
268+
-H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json"
269+
```
270+
271+
### Safe .env Update
272+
273+
```bash
274+
# 1. Read current .env
275+
CURRENT_ENV=$(curl -s "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/env" \
276+
-H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json")
277+
278+
# 2. Show user current values, confirm changes
279+
280+
# 3. Write updated .env (full content)
281+
curl -s -X PUT "$FORGE_API/servers/$SERVER_ID/sites/$SITE_ID/env" \
282+
-H "Authorization: Bearer $FORGE_TOKEN" -H "Accept: application/json" \
283+
-H "Content-Type: application/json" \
284+
-d "{\"content\": \"$UPDATED_ENV\"}"
285+
```
286+
287+
## Safety Rules
288+
289+
- **Server reboot**: ALWAYS confirm with user before executing
290+
- **Database delete**: ALWAYS confirm with user before executing
291+
- **Site delete**: ALWAYS confirm with user before executing
292+
- **.env update**: ALWAYS read current .env first, show diff to user, then write
293+
- **Nginx update**: ALWAYS read current config first, show diff to user, then write
294+
- **Deployment script update**: ALWAYS show current script and proposed changes before writing
295+
- **Deploy**: Safe to execute when user explicitly requests it
296+
297+
## Rate Limiting
298+
299+
Forge allows ~30 requests/minute per token. Headers: `X-RateLimit-Limit`, `X-RateLimit-Remaining`. If you get `HTTP 429`, wait before retrying.
300+
301+
## Forge CLI Alternative
302+
303+
If `forge-cli` is installed (`composer global require laravel/forge-cli`):
304+
305+
```bash
306+
forge login # Auth with API token
307+
forge server:list # List servers
308+
forge site:list {server} # List sites
309+
forge deploy {server} {site} # Deploy
310+
forge deploy:log {server} {site} # Deployment log
311+
forge env:get {server} {site} # Get .env
312+
forge env:set {server} {site} # Set .env
313+
forge nginx:get {server} {site} # Get nginx config
314+
forge daemon:list {server} # List daemons
315+
forge job:list {server} # List cron jobs
316+
forge certificate:list {server} {site} # List SSL certs
317+
```

0 commit comments

Comments
 (0)