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:
parent
01f5fac718
commit
1f351a1734
3 changed files with 213 additions and 48 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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.
|
||||||
|
|
|
||||||
125
skill/SKILL.md
125
skill/SKILL.md
|
|
@ -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
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue