docs: replace localhost with FLEET_API_URL, add persistence and heartbeat guidance

- Replace all localhost:9090 with FLEET_API_URL:PORT placeholder
- Add Step 0: persist Fleet API URL to agent memory
- Clarify heartbeat must be periodic loop (60s interval)
- Add execution mode self-selection decision flow
- Add persisting configuration section (URL, agent_id, token)
This commit is contained in:
Zer4tul 2026-05-12 18:34:23 +08:00
parent 01f5fac718
commit 1f351a1734
3 changed files with 213 additions and 48 deletions

View file

@ -14,18 +14,27 @@ description: |
# Agent Fleet Integration Skill
`FLEET_API_URL:PORT` means the address of your Agent Fleet Orchestrator (for example, `100.102.101.43:9090`). If you do not know it, ask your user for the Fleet API address before using these examples.
## Quick Start (http_pull mode)
**Step 0.** Get the Fleet API URL from your user and **save it to your persistent memory**:
- Ask: "What is the Agent Fleet Orchestrator URL?"
- Example answer: `http://100.102.101.43:9090`
- **IMPORTANT**: Write this URL to your persistent storage (memory file, config, etc.) so you remember it across sessions. If you lose this URL, you cannot reconnect to the fleet.
**Step 1.** Register your agent:
```bash
curl -X POST http://localhost:9090/api/v1/agents/register \
curl -X POST http://FLEET_API_URL:PORT/api/v1/agents/register \
-H 'Content-Type: application/json' \
-d '{"agent_id":"my-agent","agent_type":"openclaw","hostname":"myhost","capabilities":["code:rust"],"max_concurrency":2}'
```
After registration, save your `agent_id` and `registry_token` to persistent memory too, then start a heartbeat loop immediately. The heartbeat must run for the entire lifetime of the agent.
**Step 2.** Pull and execute a task:
```bash
curl -X POST http://localhost:9090/api/v1/tasks/dequeue \
curl -X POST http://FLEET_API_URL:PORT/api/v1/tasks/dequeue \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \
-d '{"agent_id":"my-agent","capabilities":["code:rust"]}'
@ -33,7 +42,7 @@ curl -X POST http://localhost:9090/api/v1/tasks/dequeue \
**Step 3.** Submit your result:
```bash
curl -X POST http://localhost:9090/api/v1/tasks/<task_id>/complete \
curl -X POST http://FLEET_API_URL:PORT/api/v1/tasks/<task_id>/complete \
-H 'Content-Type: application/json' \
-d '{"task_id":"<task_id>","agent_id":"my-agent","status":"completed","duration_seconds":60,"summary":"done","artifacts":[],"error":null}'
```
@ -42,30 +51,82 @@ curl -X POST http://localhost:9090/api/v1/tasks/<task_id>/complete \
## Choosing Your Execution Mode
| If you... | Use this mode |
|-----------|---------------|
| Have a CLI binary installed on a configured host | `ssh_cli` — Orchestrator calls you |
| Have your own scheduler or run outside configured hosts | `http_pull` — You call the API |
Ask your user: **"What is the address of the Agent Fleet Orchestrator?"**
If you do not know the address, ask your user.
Then determine your mode:
1. If you have a CLI binary **and** the Fleet orchestrator can SSH into your machine:
→ Use `ssh_cli` (Orchestrator calls you via SSH)
2. If the Fleet orchestrator cannot reach your machine via SSH (for example, you are behind NAT, a firewall, or on a different network):
→ Use `http_pull` (you call the Fleet API)
3. If you have your own scheduler or task loop (for example, OpenClaw or Hermes Agent):
→ Use `http_pull` (you control when to pull tasks)
4. If unsure, try this test:
- Ask your user: **"Can the Fleet orchestrator SSH into this machine?"**
- If yes → `ssh_cli`
- If no → `http_pull`
Common scenarios:
- Codex / Claude Code / OpenCode on a server → `ssh_cli` (Fleet SSHs in and runs your CLI)
- OpenClaw / Hermes Agent / any bot framework → `http_pull` (you pull tasks via HTTP API)
- Agent on a laptop behind NAT → `http_pull` (Fleet cannot reach you)
- `ssh_cli` agents do **not** need to call any API. The Orchestrator handles everything via SSH or local subprocess.
- `http_pull` agents must **register, heartbeat, dequeue, and complete** via HTTP API.
---
### Self-Determination Decision Flow
As an agent, you can self-determine your mode by answering these questions:
```
1. Do I have a CLI binary that can execute tasks non-interactively?
└─ NO → Use http_pull
└─ YES → Continue
2. Can the Fleet orchestrator SSH into my machine?
└─ NO → Use http_pull
└─ YES → Continue
3. Do I have my own scheduler, worker loop, or bot runtime?
└─ YES → Use http_pull (you prefer to control your own task flow)
└─ NO → Continue
4. Do I want the Orchestrator to initiate execution remotely?
└─ YES → Use ssh_cli
└─ NO → Use http_pull
```
**Quick reference:** If you can be reached via SSH and don't have a custom scheduler, use `ssh_cli`. Otherwise, use `http_pull`.
---
## Instructions
### http_pull Agent Lifecycle
```
Register → Heartbeat (loop) → Dequeue → Execute → Complete/Deregister
Register → Save credentials to memory → Start heartbeat loop (every 60s, runs forever)
→ Dequeue (poll when idle) → Execute → Complete → Dequeue again
→ On shutdown: Deregister
```
1. **Register** once at startup via `POST /api/v1/agents/register`.
2. **Heartbeat** periodically (every 60s recommended) via `POST /api/v1/agents/heartbeat`. Without heartbeats, you will be marked offline and your tasks requeued.
3. **Dequeue** when ready for work via `POST /api/v1/tasks/dequeue`. Returns a Task or 204 No Content.
4. **Update status** to `running` via `POST /api/v1/tasks/{task_id}/status`.
5. **Complete** the task via `POST /api/v1/tasks/{task_id}/complete` with a Receipt.
6. **Deregister** when shutting down via `POST /api/v1/agents/deregister`.
2. **Save credentials to memory** immediately after registration: persist `FLEET_API_URL`, your `agent_id`, and your `registry_token` in long-term memory or a config file.
3. **Start a periodic heartbeat loop** via `POST /api/v1/agents/heartbeat`.
- Default interval: every 60 seconds
- Maximum allowed gap: `heartbeat_interval_secs × heartbeat_timeout_threshold` (default: 180 seconds)
- If you exceed that gap, you will be marked offline and your tasks will be requeued
- This must run for the entire lifetime of the agent, not just once
4. **Dequeue** when ready for work via `POST /api/v1/tasks/dequeue`. Returns a Task or 204 No Content.
5. **Update status** to `running` via `POST /api/v1/tasks/{task_id}/status`.
6. **Complete** the task via `POST /api/v1/tasks/{task_id}/complete` with a Receipt.
7. **Deregister** when shutting down via `POST /api/v1/agents/deregister`.
### ssh_cli Agent Notes
@ -81,7 +142,7 @@ No API interaction required. Ensure:
### Register
```bash
curl -X POST http://localhost:9090/api/v1/agents/register \
curl -X POST http://FLEET_API_URL:PORT/api/v1/agents/register \
-H 'Content-Type: application/json' \
-d '{
"agent_id": "worker-03",
@ -96,7 +157,9 @@ curl -X POST http://localhost:9090/api/v1/agents/register \
### Heartbeat
```bash
curl -X POST http://localhost:9090/api/v1/agents/heartbeat \
# Heartbeat must be sent periodically. Example using a shell loop:
# while true; do curl -X POST http://FLEET_API_URL:PORT/api/v1/agents/heartbeat -H 'Content-Type: application/json' -d '{"agent_id": "worker-03"}'; sleep 60; done
curl -X POST http://FLEET_API_URL:PORT/api/v1/agents/heartbeat \
-H 'Content-Type: application/json' \
-d '{"agent_id": "worker-03"}'
```
@ -104,13 +167,13 @@ curl -X POST http://localhost:9090/api/v1/agents/heartbeat \
### List Available Tasks
```bash
curl 'http://localhost:9090/api/v1/tasks?status=created'
curl 'http://FLEET_API_URL:PORT/api/v1/tasks?status=created'
```
### Dequeue
```bash
curl -X POST http://localhost:9090/api/v1/tasks/dequeue \
curl -X POST http://FLEET_API_URL:PORT/api/v1/tasks/dequeue \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer my-token' \
-d '{"agent_id": "worker-03", "capabilities": ["code:rust"]}'
@ -121,13 +184,13 @@ Returns 200 with Task JSON, or 204 if no matching task.
### Get Task Detail
```bash
curl 'http://localhost:9090/api/v1/tasks/org%2Frepo%2342'
curl 'http://FLEET_API_URL:PORT/api/v1/tasks/org%2Frepo%2342'
```
### Update Task Status
```bash
curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/status \
curl -X POST http://FLEET_API_URL:PORT/api/v1/tasks/org%2Frepo%2342/status \
-H 'Content-Type: application/json' \
-H 'Authorization: Bearer my-token' \
-d '{"status": "running"}'
@ -136,7 +199,7 @@ curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/status \
### Complete Task with Receipt
```bash
curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/complete \
curl -X POST http://FLEET_API_URL:PORT/api/v1/tasks/org%2Frepo%2342/complete \
-H 'Content-Type: application/json' \
-d '{
"task_id": "org/repo#42",
@ -154,7 +217,7 @@ curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/complete \
### Submit Receipt
```bash
curl -X POST http://localhost:9090/api/v1/receipts \
curl -X POST http://FLEET_API_URL:PORT/api/v1/receipts \
-H 'Content-Type: application/json' \
-d '{
"task_id": "org/repo#42",
@ -170,7 +233,7 @@ curl -X POST http://localhost:9090/api/v1/receipts \
### Retry a Failed Task
```bash
curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/retry
curl -X POST http://FLEET_API_URL:PORT/api/v1/tasks/org%2Frepo%2342/retry
```
Only works for tasks in `failed` or `agent_lost` status.
@ -178,13 +241,13 @@ Only works for tasks in `failed` or `agent_lost` status.
### List Agents
```bash
curl 'http://localhost:9090/api/v1/agents?status=online&capability=code:rust'
curl 'http://FLEET_API_URL:PORT/api/v1/agents?status=online&capability=code:rust'
```
### Deregister
```bash
curl -X POST http://localhost:9090/api/v1/agents/deregister \
curl -X POST http://FLEET_API_URL:PORT/api/v1/agents/deregister \
-H 'Content-Type: application/json' \
-d '{"agent_id": "worker-03"}'
```
@ -192,7 +255,7 @@ curl -X POST http://localhost:9090/api/v1/agents/deregister \
### Health Check
```bash
curl http://localhost:9090/healthz
curl http://FLEET_API_URL:PORT/healthz
```
---
@ -237,10 +300,20 @@ created → assigned → running → review_pending → completed
### Heartbeat Requirements
- Send heartbeats at least every `heartbeat_interval_secs` (default: 60s).
- Send heartbeats in a background loop at least every `heartbeat_interval_secs` (default: 60s).
- A one-time heartbeat is not enough; the loop must run for the full lifetime of the agent.
- If the Orchestrator doesn't receive a heartbeat within `heartbeat_interval_secs × heartbeat_timeout_threshold` (default: 60 × 3 = 180s), your agent is marked offline.
- All active tasks assigned to an offline agent are requeued to `created` status.
### Persisting Configuration
After registration, you MUST persist these values to your long-term memory or config file:
1. **FLEET_API_URL** — the orchestrator address
2. **Your agent_id** — your registered agent ID
3. **Your registry_token** — the token returned by registration (needed for http_pull auth)
Without these, you cannot reconnect after a session restart.
---
## Forgejo Workflow