You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
You are helping a user deploy their Turbine trading bot to Locus for 24/7 cloud operation.
11
11
12
-
This skill authenticates with Locus using the user's existing Turbine wallet via x402 (Polygon USDC payment). No separate Locus API key is needed — the user's TURBINE_PRIVATE_KEY handles everything.
12
+
This skill authenticates with Locus using the user's existing Turbine wallet via x402 (Polygon USDC payment). No separate Locus account or API key is needed — the wallet payment creates a workspace and returns a JWT that works for all API calls.
13
13
14
14
Locus is a container platform that deploys services via a REST API. Each service costs $0.25/month from workspace credits. New workspaces start with $6.00 in credits (x402 sign-up costs 0.001 USDC). Services get an auto-subdomain at `svc-{id}.buildwithlocus.com` with HTTPS.
15
15
16
+
**Auth flow:** x402 wallet payment (0.001 USDC) → creates workspace + JWT → use JWT for all API calls (projects, services, source upload, deployments).
17
+
16
18
**API Documentation for Locus**`https://buildwithlocus.com/SKILL.md`
17
19
18
20
**Base URL:**`https://api.buildwithlocus.com/v1`
@@ -197,39 +199,51 @@ Run the x402 sign-up script:
197
199
python scripts/locus_x402.py sign-up
198
200
```
199
201
200
-
The script:
201
-
1. POSTs to Locus's x402-sign-up endpoint
202
-
2. Gets 402 response with payment requirements
203
-
3. Signs an EIP-3009 USDC payment authorization with TURBINE_PRIVATE_KEY
204
-
4. Retries with the signed payment
202
+
The script performs the x402 handshake:
203
+
1. POSTs to Locus's `/auth/x402-sign-up` endpoint with empty body `{}`
204
+
2. Gets 402 response with `PAYMENT-REQUIRED` header (base64-encoded JSON with x402 V2 payment requirements in `accepts` array: scheme, network `eip155:137`, amount `1000`, USDC asset address, recipient `payTo` address)
205
+
3. Signs an EIP-3009 `TransferWithAuthorization` typed-data message using TURBINE_PRIVATE_KEY (no on-chain tx needed)
206
+
4. Retries the POST with the signed payment in the `PAYMENT-SIGNATURE` header (base64-encoded V2 PaymentPayload with `payload`, `accepted` echoing back the requirements)
205
207
5. Returns a JWT (saved to /tmp/locus-token.txt) and workspace info
206
208
207
-
**Parse the JSON output** to extract: `jwt`, `workspaceId`, `isNewWorkspace`, `claimUrl`, `creditBalance`.
209
+
**Parse the JSON output** to extract: `jwt`, `workspaceId`, `isNewWorkspace`, `claimUrl`.
208
210
209
211
Tell the user the result:
210
212
- If `isNewWorkspace: true`: "Created new Locus workspace: {workspaceId}. Starting credit balance: $6.00."
211
213
- If `isNewWorkspace: false`: "Reconnected to existing workspace: {workspaceId}."
212
214
213
-
If the response includes a `claimUrl`, tell the user:
214
-
"You can optionally link an email to your Locus workspace for a permanent API key:
215
-
{claimUrl}
216
-
This isn't required — your wallet works for authentication."
215
+
If the response includes a `claimUrl`, mention it as optional:
216
+
> "You can optionally link an email to your workspace for free token refreshes and a permanent API key:
217
+
> {claimUrl}
218
+
> This is NOT required — your wallet handles everything."
217
219
218
220
If the script fails:
219
221
- Check that TURBINE_PRIVATE_KEY is set correctly in .env
220
222
- Ensure the wallet has at least 0.001 USDC on Polygon
- If they claimed their workspace: use `POST /v1/auth/exchange` with the `claw_` API key (free)
264
+
244
265
---
245
266
246
267
## Step 4: Create Project, Environment, and Service
247
268
248
-
Run these API calls sequentially, communicating each step to the user:
269
+
**IMPORTANT:** The claimed workspace may already have projects from a previous deployment. Always check for existing projects first before creating new ones.
If the project creation fails, check the error. If a project named "turbine-bot" already exists, list projects and ask the user whether to reuse it or create a new one with a different name.
265
-
266
-
**Create an environment:**
307
+
### Create an environment (only if none exists):
267
308
268
309
```bash
269
-
ENV=$(curl -s -X POST $BASE_URL/projects/$PROJECT_ID/environments \
310
+
ENV=$(curl -s -X POST https://api.buildwithlocus.com/v1/projects/$PROJECT_ID/environments \
If service creation returns `"Service \"trading-bot\" already exists in this environment"`, the service already exists. You'll need the service ID for env vars and monitoring. Since there's no direct list-services endpoint, the service ID can be obtained from the deployment output in Step 6 (the git push response includes deployment details with `serviceId`). Alternatively, try creating the service and if it already exists, proceed to Step 5.
279
322
280
323
```bash
281
-
SERVICE=$(curl -s -X POST $BASE_URL/services \
324
+
SERVICE=$(curl -s -X POST https://api.buildwithlocus.com/v1/services \
git remote add locus "https://x:${TOKEN}@git.buildwithlocus.com/${WORKSPACE_ID}/${PROJECT_ID}.git"
460
+
DEPLOYMENT_ID=$(echo $DEPLOY| jq -r '.id')
461
+
echo"Deployment triggered: $DEPLOYMENT_ID"
407
462
```
408
463
409
-
**Important:** The deployment files (`locus_runner.py`, `Dockerfile`) and the bot file need to be committed before pushing — only tracked files are included in the git push archive. Create a commit with these files:
410
-
464
+
Clean up:
411
465
```bash
412
-
git add locus_runner.py Dockerfile {BOT_FILE}
413
-
git commit -m "Add Locus deployment files"
466
+
rm /tmp/turbine-bot-source.tar.gz
414
467
```
415
468
416
-
**Push to deploy:**
469
+
### Fallback: Git Push (requires `claw_` API key)
470
+
471
+
If source upload fails with 403, the user needs a `claw_` API key for git push deployment. This requires claiming their workspace.
472
+
473
+
Tell the user:
474
+
> "Source upload isn't available for your account. To deploy via git push, you'll need to claim your Locus workspace.
475
+
> Visit your claim URL: {claimUrl}
476
+
> After claiming, you'll get a `claw_` API key. Paste it back here."
477
+
478
+
Once they have the `claw_` key:
479
+
480
+
```bash
481
+
# Exchange claw_ key for JWT to get the workspace ID
482
+
CLAW_KEY="<user's key>"
483
+
CLAW_TOKEN=$(curl -s -X POST https://api.buildwithlocus.com/v1/auth/exchange \
484
+
-H "Content-Type: application/json" \
485
+
-d '{"apiKey": "'"$CLAW_KEY"'"}'| jq -r '.token')
486
+
487
+
# IMPORTANT: The claimed workspace may differ from the x402 workspace.
488
+
# Use the claw_ key's workspace and re-check for existing projects.
Tell the user: "Pushing code to Locus. This will upload the source and trigger a build. Builds typically take 3-7 minutes."
492
+
# If workspace differs, save the new JWT and re-run Steps 4-5 with it
493
+
echo"$CLAW_TOKEN"> /tmp/locus-token.txt
494
+
```
495
+
496
+
Set up git remote and push:
419
497
420
498
```bash
499
+
git remote remove locus 2>/dev/null
500
+
git remote add locus "https://x:${CLAW_KEY}@git.buildwithlocus.com/${CLAW_WORKSPACE}/${PROJECT_ID}.git"
501
+
502
+
# Deployment files must be committed
503
+
git add locus_runner.py Dockerfile {BOT_FILE}
504
+
git commit -m "Add Locus deployment files"
505
+
421
506
git push locus main
422
507
```
423
508
424
-
If the push fails:
425
-
- Authentication error → Your JWT may have expired. Refresh it:
426
-
```bash
427
-
python scripts/locus_x402.py sign-up
428
-
TOKEN=$(cat /tmp/locus-token.txt)
429
-
git remote set-url locus "https://x:${TOKEN}@git.buildwithlocus.com/${WORKSPACE_ID}/${PROJECT_ID}.git"
430
-
git push locus main
431
-
```
432
-
- Branch error → Try `git push locus HEAD:main`if on a different branch
433
-
- Remote error → Verify workspace and project IDs
509
+
Extract the deployment ID from the push output:
510
+
```
511
+
-> trading-bot [deploy_xxxxx]
512
+
```
434
513
435
-
After the push, note the deployment IDs from the push output.
514
+
**IMPORTANT for redeployments:** When using git push, always push via `git push locus main` to redeploy. Do NOT use `POST /v1/deployments` alone — it does not include source code and will fail.
436
515
437
516
---
438
517
@@ -465,25 +544,42 @@ Keep the user informed at each check:
465
544
-`building` → "Building Docker image from source..."
466
545
-`deploying` → "Container is starting, running health checks..."
467
546
-`healthy` → "Deployment is live!"
468
-
- `failed` → Check logs and report the error
547
+
-`failed` → **Don't panic — check the service runtime status first (see below)**
548
+
549
+
**IMPORTANT: "failed" deployment does NOT always mean the bot isn't running.** The ECS health check may time out during the initial credential registration and USDC approval phase (which can take 30-60 seconds), causing the deployment to be marked as "failed" even though the container is running successfully.
550
+
551
+
**If deployment shows `failed`, check the actual service status:**
If `runtime_instances.status` is `"running"` and/or the health endpoint returns 200, **the bot IS running** despite the "failed" deployment status. Tell the user it's live and skip to Step 8.
469
565
470
-
**If deployment fails**, fetch the last logs:
566
+
**If the service is genuinely not running**, fetch the deployment logs:
- **Health check timeout:** The `/health` endpoint didn't respond intime. Check that `locus_runner.py` is starting the health server before the bot.
576
+
-**Health check timeout during startup:** The bot's initial credential registration and USDC approval can take time. The health endpoint starts immediately but ECS may declare the task unhealthy before the bot stabilizes. This is usually recoverable — the container keeps running.
481
577
-**Dependency install failed:** Missing packages in `pyproject.toml`.
482
578
-**Dockerfile error:** Check the build logs for syntax issues.
483
579
484
580
Help the user fix the issue and redeploy with another `git push locus main`.
485
581
486
-
**IMPORTANT:** After deployment reaches `healthy`, the public URL may return 503 for up to 60 seconds while service discovery registers the container. This is normal. Tell the user to wait before testing the URL.
582
+
**IMPORTANT:** After deployment reaches `healthy` (or the service shows as running), the public URL may return 503 for up to 60 seconds while service discovery registers the container. This is normal. Tell the user to wait before testing the URL.
487
583
488
584
---
489
585
@@ -543,22 +639,19 @@ Track your bot's performance on the leaderboard:
543
639
544
640
If the user wants to redeploy after making changes to their bot:
0 commit comments