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

@ -1,8 +1,11 @@
# Agent Fleet — HTTP API Reference # Agent Fleet — HTTP API Reference
Base URL: `http://<host>:9090` `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.
Base URL: `http://FLEET_API_URL:PORT`
Content-Type: `application/json` for all request/response bodies unless noted. Content-Type: `application/json` for all request/response bodies unless noted.
All timestamps are ISO 8601 (RFC 3339). All timestamps are ISO 8601 (RFC 3339).
If you do not know the Fleet API URL, ask the user who deployed the orchestrator.
--- ---
@ -56,7 +59,7 @@ GET /healthz
**Response:** `200 OK` — body: `ok` **Response:** `200 OK` — body: `ok`
```bash ```bash
curl http://localhost:9090/healthz curl http://FLEET_API_URL:PORT/healthz
``` ```
--- ---
@ -90,7 +93,7 @@ Register a new agent or update an existing one (upsert by `agent_id`).
``` ```
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{ -d '{
"agent_id": "worker-01", "agent_id": "worker-01",
@ -109,6 +112,8 @@ curl -X POST http://localhost:9090/api/v1/agents/register \
POST /api/v1/agents/heartbeat POST /api/v1/agents/heartbeat
``` ```
This endpoint MUST be called periodically (default: every 60s). A single call is not sufficient. Missing heartbeats will cause the agent to be marked offline and its tasks requeued.
**Request:** **Request:**
| Field | Type | Required | Description | | Field | Type | Required | Description |
@ -128,7 +133,7 @@ POST /api/v1/agents/heartbeat
**Errors:** `404` if agent not found. **Errors:** `404` if agent not found.
```bash ```bash
curl -X POST http://localhost:9090/api/v1/agents/heartbeat \ curl -X POST http://FLEET_API_URL:PORT/api/v1/agents/heartbeat \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d '{"agent_id": "worker-01"}' -d '{"agent_id": "worker-01"}'
``` ```
@ -160,7 +165,7 @@ Sets agent offline and requeues all its active tasks back to `created`.
``` ```
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{"agent_id": "worker-01"}' -d '{"agent_id": "worker-01"}'
``` ```
@ -183,7 +188,7 @@ GET /api/v1/agents
**Response:** `200 OK` — JSON array of [Agent](#agent-object) objects. **Response:** `200 OK` — JSON array of [Agent](#agent-object) objects.
```bash ```bash
curl 'http://localhost:9090/api/v1/agents?status=online' curl 'http://FLEET_API_URL:PORT/api/v1/agents?status=online'
``` ```
--- ---
@ -204,7 +209,7 @@ GET /api/v1/tasks
**Response:** `200 OK` — JSON array of [Task](#task-object) objects. Ordered by `created_at` descending. **Response:** `200 OK` — JSON array of [Task](#task-object) objects. Ordered by `created_at` descending.
```bash ```bash
curl 'http://localhost:9090/api/v1/tasks?status=running' curl 'http://FLEET_API_URL:PORT/api/v1/tasks?status=running'
``` ```
--- ---
@ -220,7 +225,7 @@ GET /api/v1/tasks/{task_id}
**Errors:** `404` if task not found. **Errors:** `404` if task not found.
```bash ```bash
curl http://localhost:9090/api/v1/tasks/org%2Frepo%2342 curl http://FLEET_API_URL:PORT/api/v1/tasks/org%2Frepo%2342
``` ```
--- ---
@ -245,7 +250,7 @@ Requires Bearer token if `http_pull_token` is configured. Only returns tasks wit
**Errors:** `401` if token required and missing/invalid. **Errors:** `401` if token required and missing/invalid.
```bash ```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 'Content-Type: application/json' \
-H 'Authorization: Bearer my-token' \ -H 'Authorization: Bearer my-token' \
-d '{"agent_id": "worker-03", "capabilities": ["code:rust"]}' -d '{"agent_id": "worker-03", "capabilities": ["code:rust"]}'
@ -272,7 +277,7 @@ Requires Bearer token. Only works for tasks with `execution_mode = http_pull`.
**Errors:** `400` if task is not `http_pull` mode or transition is invalid. `404` if task not found. **Errors:** `400` if task is not `http_pull` mode or transition is invalid. `404` if task not found.
```bash ```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 'Content-Type: application/json' \
-H 'Authorization: Bearer my-token' \ -H 'Authorization: Bearer my-token' \
-d '{"status": "running"}' -d '{"status": "running"}'
@ -302,7 +307,7 @@ Works for both `ssh_cli` and `http_pull` tasks. Submit a receipt to mark the tas
**Errors:** `404` if task not found. `400` if task is not in a completable state. **Errors:** `404` if task not found. `400` if task is not in a completable state.
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{ -d '{
"task_id": "org/repo#42", "task_id": "org/repo#42",
@ -332,7 +337,7 @@ Retry a `failed` or `agent_lost` task. Transitions it back to `assigned`.
**Errors:** `400` if task status is not `failed` or `agent_lost`. `404` if task not found. **Errors:** `400` if task status is not `failed` or `agent_lost`. `404` if task not found.
```bash ```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
``` ```
--- ---
@ -352,7 +357,7 @@ Submit a receipt for a task. Validates artifacts (e.g. checks PR exists via Forg
**Errors:** `404` if task not found. `400` if validation fails. **Errors:** `404` if task not found. `400` if validation fails.
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{ -d '{
"task_id": "org/repo#42", "task_id": "org/repo#42",

View file

@ -1,5 +1,7 @@
# Agent Fleet — Agent Onboarding Guide # Agent Fleet — Agent Onboarding Guide
`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.
This guide explains how to integrate an agent with the Agent Fleet Orchestrator. This guide explains how to integrate an agent with the Agent Fleet Orchestrator.
--- ---
@ -19,6 +21,81 @@ Agent Fleet supports two execution modes. The mode is set per-task at creation t
--- ---
## How to Choose an Execution Mode
Start by asking: **"What is the address of the Agent Fleet Orchestrator?"**
If you do not know the address, ask your user.
Then decide based on connectivity and control model:
1. **Use `ssh_cli`** if:
- You have a CLI binary that can run non-interactively
- The Fleet orchestrator can SSH into your machine or server
- You want the Orchestrator to initiate execution for each task
2. **Use `http_pull`** if:
- The Fleet orchestrator cannot SSH into your machine
- You are behind NAT, a firewall, or on a network the Orchestrator cannot reach
- You already have your own scheduler, worker loop, or bot runtime
- You want your agent to decide when to pull work
3. **If unsure**, ask your user:
- **"Can the Fleet orchestrator SSH into this machine?"**
- If yes → `ssh_cli`
- If no → `http_pull`
---
### 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`.
### Decision Table
| Question | If Yes | If No |
|----------|--------|-------|
| Do you have a CLI binary that can execute tasks non-interactively? | Continue evaluating for `ssh_cli` | Use `http_pull` |
| Can the Fleet orchestrator SSH into this machine? | Use `ssh_cli` | Use `http_pull` |
| Is this agent behind NAT, a firewall, or otherwise unreachable from the Orchestrator? | Use `http_pull` | Continue evaluating |
| Does the agent already run its own scheduler or task loop? | Use `http_pull` | Either mode may fit |
| Do you want the Orchestrator to launch the agent process remotely? | Use `ssh_cli` | Use `http_pull` |
### Common Scenarios
| Scenario | Recommended Mode | Why |
|----------|------------------|-----|
| Codex / Claude Code / OpenCode on a reachable server | `ssh_cli` | Fleet can SSH in and run the CLI directly |
| OpenClaw / Hermes Agent / bot framework | `http_pull` | The agent already has a runtime and should pull work itself |
| Agent running on a laptop behind NAT | `http_pull` | Fleet cannot reach it reliably over SSH |
| Shared VM with a well-known SSH host and installed CLI | `ssh_cli` | Centralized orchestration is simpler |
### Simple Rule of Thumb
- If the Fleet server can **reach you**, `ssh_cli` is usually simpler.
- If you must **reach the Fleet server**, use `http_pull`.
---
## ssh_cli Workflow ## ssh_cli Workflow
### 1. Configure a Host ### 1. Configure a Host
@ -107,19 +184,29 @@ If output is not valid JSON, the task is marked `failed`.
### 1. Register ### 1. Register
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{"agent_id": "worker-03", "agent_type": "openclaw", "hostname": "arm0", "capabilities": ["code:rust"], "max_concurrency": 2}' -d '{"agent_id": "worker-03", "agent_type": "openclaw", "hostname": "arm0", "capabilities": ["code:rust"], "max_concurrency": 2}'
``` ```
Response contains a `registry_token`. Keep it for subsequent API calls (if `http_pull_token` is configured, use that shared token instead). Response contains a `registry_token`. Keep it for subsequent API calls (if `http_pull_token` is configured, use that shared token instead).
Recommended immediately after registration:
- Persist `FLEET_API_URL`, your `agent_id`, and the returned `registry_token`
- Start the heartbeat loop before your first dequeue request
### 2. Heartbeat (periodic) ### 2. Heartbeat (periodic)
Send a heartbeat every N seconds (default interval: 60s). If the Orchestrator doesn't receive one within `heartbeat_interval_secs × heartbeat_timeout_threshold`, the agent is marked offline and its tasks are requeued. Heartbeat must be a background loop, not a one-shot call.
- Default heartbeat interval: every 60 seconds
- Recommended behavior: start the loop immediately after registration, before the first dequeue
- If the Orchestrator does not receive a heartbeat within `heartbeat_interval_secs × heartbeat_timeout_threshold` (default: 180 seconds), the agent is marked offline
- When an agent is marked offline, its assigned tasks are requeued
- The heartbeat loop should run for the entire lifetime of the agent
```bash ```bash
curl -X POST http://localhost:9090/api/v1/agents/heartbeat \ curl -X POST http://FLEET_API_URL:PORT/api/v1/agents/heartbeat \
-H 'Content-Type: application/json' \ -H 'Content-Type: application/json' \
-d '{"agent_id": "worker-03"}' -d '{"agent_id": "worker-03"}'
``` ```
@ -127,7 +214,7 @@ curl -X POST http://localhost:9090/api/v1/agents/heartbeat \
### 3. Dequeue a Task ### 3. Dequeue a Task
```bash ```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 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \ -H 'Authorization: Bearer <token>' \
-d '{"agent_id": "worker-03", "capabilities": ["code:rust"]}' -d '{"agent_id": "worker-03", "capabilities": ["code:rust"]}'
@ -140,7 +227,7 @@ Only tasks with `execution_mode = http_pull` are returned.
### 4. Update Status While Working ### 4. Update Status While Working
```bash ```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 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \ -H 'Authorization: Bearer <token>' \
-d '{"status": "running"}' -d '{"status": "running"}'
@ -149,7 +236,7 @@ curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/status \
### 5. Complete the Task ### 5. Complete the Task
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{ -d '{
"task_id": "org/repo#42", "task_id": "org/repo#42",
@ -165,7 +252,7 @@ curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/complete \
Or use the receipts endpoint: Or use the receipts endpoint:
```bash ```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' \ -H 'Content-Type: application/json' \
-d '<same receipt body>' -d '<same receipt body>'
``` ```
@ -173,7 +260,7 @@ curl -X POST http://localhost:9090/api/v1/receipts \
### 6. Deregister When Done ### 6. Deregister When Done
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{"agent_id": "worker-03"}' -d '{"agent_id": "worker-03"}'
``` ```
@ -248,7 +335,7 @@ The prompt is injected into the CLI template as the `{prompt}` variable. Other a
## FAQ ## FAQ
**Q: How do I know which execution mode to use?** **Q: How do I know which execution mode to use?**
A: If you have a CLI binary and run on a configured host → `ssh_cli`. If you have your own scheduler or run outside configured hosts → `http_pull`. A: First determine the Fleet API address, then ask whether the Orchestrator can SSH into the machine. If it can, `ssh_cli` is usually the best fit. If it cannot, use `http_pull`.
**Q: Do I need to register for ssh_cli mode?** **Q: Do I need to register for ssh_cli mode?**
A: No. The Orchestrator manages ssh_cli tasks entirely. Registration is only for `http_pull` agents. A: No. The Orchestrator manages ssh_cli tasks entirely. Registration is only for `http_pull` agents.

View file

@ -14,18 +14,27 @@ description: |
# Agent Fleet Integration Skill # 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) ## 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: **Step 1.** Register your agent:
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{"agent_id":"my-agent","agent_type":"openclaw","hostname":"myhost","capabilities":["code:rust"],"max_concurrency":2}' -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: **Step 2.** Pull and execute a task:
```bash ```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 'Content-Type: application/json' \
-H 'Authorization: Bearer <token>' \ -H 'Authorization: Bearer <token>' \
-d '{"agent_id":"my-agent","capabilities":["code:rust"]}' -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: **Step 3.** Submit your result:
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{"task_id":"<task_id>","agent_id":"my-agent","status":"completed","duration_seconds":60,"summary":"done","artifacts":[],"error":null}' -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 ## Choosing Your Execution Mode
| If you... | Use this mode | Ask your user: **"What is the address of the Agent Fleet Orchestrator?"**
|-----------|---------------| If you do not know the address, ask your user.
| 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 | 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. - `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. - `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 ## Instructions
### http_pull Agent Lifecycle ### 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`. 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. 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. **Dequeue** when ready for work via `POST /api/v1/tasks/dequeue`. Returns a Task or 204 No Content. 3. **Start a periodic heartbeat loop** via `POST /api/v1/agents/heartbeat`.
4. **Update status** to `running` via `POST /api/v1/tasks/{task_id}/status`. - Default interval: every 60 seconds
5. **Complete** the task via `POST /api/v1/tasks/{task_id}/complete` with a Receipt. - Maximum allowed gap: `heartbeat_interval_secs × heartbeat_timeout_threshold` (default: 180 seconds)
6. **Deregister** when shutting down via `POST /api/v1/agents/deregister`. - 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 ### ssh_cli Agent Notes
@ -81,7 +142,7 @@ No API interaction required. Ensure:
### Register ### Register
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{ -d '{
"agent_id": "worker-03", "agent_id": "worker-03",
@ -96,7 +157,9 @@ curl -X POST http://localhost:9090/api/v1/agents/register \
### Heartbeat ### Heartbeat
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{"agent_id": "worker-03"}' -d '{"agent_id": "worker-03"}'
``` ```
@ -104,13 +167,13 @@ curl -X POST http://localhost:9090/api/v1/agents/heartbeat \
### List Available Tasks ### List Available Tasks
```bash ```bash
curl 'http://localhost:9090/api/v1/tasks?status=created' curl 'http://FLEET_API_URL:PORT/api/v1/tasks?status=created'
``` ```
### Dequeue ### Dequeue
```bash ```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 'Content-Type: application/json' \
-H 'Authorization: Bearer my-token' \ -H 'Authorization: Bearer my-token' \
-d '{"agent_id": "worker-03", "capabilities": ["code:rust"]}' -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 ### Get Task Detail
```bash ```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 ### Update Task Status
```bash ```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 'Content-Type: application/json' \
-H 'Authorization: Bearer my-token' \ -H 'Authorization: Bearer my-token' \
-d '{"status": "running"}' -d '{"status": "running"}'
@ -136,7 +199,7 @@ curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/status \
### Complete Task with Receipt ### Complete Task with Receipt
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{ -d '{
"task_id": "org/repo#42", "task_id": "org/repo#42",
@ -154,7 +217,7 @@ curl -X POST http://localhost:9090/api/v1/tasks/org%2Frepo%2342/complete \
### Submit Receipt ### Submit Receipt
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{ -d '{
"task_id": "org/repo#42", "task_id": "org/repo#42",
@ -170,7 +233,7 @@ curl -X POST http://localhost:9090/api/v1/receipts \
### Retry a Failed Task ### Retry a Failed Task
```bash ```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. 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 ### List Agents
```bash ```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 ### Deregister
```bash ```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' \ -H 'Content-Type: application/json' \
-d '{"agent_id": "worker-03"}' -d '{"agent_id": "worker-03"}'
``` ```
@ -192,7 +255,7 @@ curl -X POST http://localhost:9090/api/v1/agents/deregister \
### Health Check ### Health Check
```bash ```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 ### 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. - 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. - 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 ## Forgejo Workflow