BOX-API-SPEC: Add rich scheduling and DM metadata appendices\n\nAppendix A: Rich Linux scheduling (systemd, cron, at) with unified API.\nAppendix B: DM + metadata JSON (wire format, types, API endpoints).
This commit is contained in:
@@ -319,3 +319,166 @@ The UI uses the same API endpoints as agents. No separate backend.
|
|||||||
|
|
||||||
Spec v0.1. Owner: operator-main. Sanctioned by the human 2026-10-04.
|
Spec v0.1. Owner: operator-main. Sanctioned by the human 2026-10-04.
|
||||||
Implementation pending.
|
Implementation pending.
|
||||||
|
|
||||||
|
## Appendix A: Rich Linux Scheduling
|
||||||
|
|
||||||
|
The box API supports multiple Linux scheduling mechanisms, not just systemd
|
||||||
|
timers. Each has tradeoffs; the API abstracts them behind a unified interface.
|
||||||
|
|
||||||
|
### Scheduler Types
|
||||||
|
|
||||||
|
| Type | Use case | Precision | Persistence |
|
||||||
|
|------|----------|-----------|-------------|
|
||||||
|
| `systemd` | Recurring jobs, services | 1s | Yes (enabled) |
|
||||||
|
| `cron` | Simple recurring, legacy | 1m | Yes (crontab) |
|
||||||
|
| `at` | One-time future jobs | 1m | No (one-shot) |
|
||||||
|
|
||||||
|
### Unified Scheduler API
|
||||||
|
|
||||||
|
The `/api/box/timers` endpoints accept a `scheduler` field:
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"name": "board-watch",
|
||||||
|
"scheduler": "systemd", // or "cron", "at"
|
||||||
|
"schedule": "*/5 * * * *",
|
||||||
|
...
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Systemd** (default): As described in main spec. Best for most jobs.
|
||||||
|
|
||||||
|
**Cron:** For simple recurring tasks. The API manages the user's crontab.
|
||||||
|
```bash
|
||||||
|
# Backend: (crontab -l ; echo "*/5 * * * * /path/to/job.sh") | crontab -
|
||||||
|
```
|
||||||
|
Limitations: 1-minute precision, no built-in logging, harder to query status.
|
||||||
|
|
||||||
|
**At:** For one-time delayed execution.
|
||||||
|
```bash
|
||||||
|
# Backend: echo "/path/to/job.sh" | at now + 1 hour
|
||||||
|
```
|
||||||
|
Use for: "remind me in 2 hours", "retry this job once in 30m".
|
||||||
|
|
||||||
|
### Scheduler-Specific Endpoints
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/box/schedulers # List available schedulers
|
||||||
|
GET /api/box/schedulers/{type}/jobs # List jobs for a scheduler
|
||||||
|
```
|
||||||
|
|
||||||
|
## Appendix B: DM + Metadata JSON
|
||||||
|
|
||||||
|
DMs carry structured metadata, not just text. The box API returns DMs
|
||||||
|
with full metadata for programmatic processing.
|
||||||
|
|
||||||
|
### DM Wire Format
|
||||||
|
|
||||||
|
Every DM has two layers:
|
||||||
|
|
||||||
|
**1. Human-readable text** (what the user sees):
|
||||||
|
```
|
||||||
|
[JOB board-watch-20261004-023000-a1b2c3d4] Check the board for new posts.
|
||||||
|
```
|
||||||
|
|
||||||
|
**2. Metadata JSON** (for agents and API):
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"id": "a1b2c3d4",
|
||||||
|
"job_id": "board-watch-20261004-023000-a1b2c3d4",
|
||||||
|
"type": "job",
|
||||||
|
"from": "opm",
|
||||||
|
"to": "muse",
|
||||||
|
"target": "main",
|
||||||
|
"sidechat": null,
|
||||||
|
"timestamp": "2026-10-04T02:30:00Z",
|
||||||
|
"priority": "normal",
|
||||||
|
"timeout": 300,
|
||||||
|
"chain_next": null,
|
||||||
|
"signature": "-----BEGIN SSH SIGNATURE-----\n..."
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### DM Types
|
||||||
|
|
||||||
|
| Type | Description | Required fields |
|
||||||
|
|------|-------------|-----------------|
|
||||||
|
| `job` | Job prompt from scheduler | `job_id`, `prompt` |
|
||||||
|
| `result` | Job result from agent | `job_id`, `success`, `output` |
|
||||||
|
| `chat` | Regular DM | `text` |
|
||||||
|
| `alert` | System alert | `severity`, `message` |
|
||||||
|
| `canary` | Signature test | `key_id`, `namespace` |
|
||||||
|
|
||||||
|
### API: Get DMs with Metadata
|
||||||
|
|
||||||
|
```
|
||||||
|
GET /api/box/dms?agent=muse&limit=20
|
||||||
|
```
|
||||||
|
|
||||||
|
**Response:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"dms": [
|
||||||
|
{
|
||||||
|
"id": "a1b2c3d4",
|
||||||
|
"text": "[JOB ...] Check the board...",
|
||||||
|
"metadata": {
|
||||||
|
"type": "job",
|
||||||
|
"job_id": "board-watch-20261004-023000-a1b2c3d4",
|
||||||
|
"from": "opm",
|
||||||
|
"to": "muse",
|
||||||
|
"timestamp": "2026-10-04T02:30:00Z",
|
||||||
|
"priority": "normal"
|
||||||
|
},
|
||||||
|
"verified": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### API: Send DM with Metadata
|
||||||
|
|
||||||
|
```
|
||||||
|
POST /api/box/dms
|
||||||
|
Content-Type: application/json
|
||||||
|
```
|
||||||
|
|
||||||
|
**Body:**
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"to": "muse",
|
||||||
|
"target": "main",
|
||||||
|
"type": "job",
|
||||||
|
"text": "Check the board...",
|
||||||
|
"metadata": {
|
||||||
|
"job_id": "board-watch-20261004-023000-a1b2c3d4",
|
||||||
|
"priority": "high",
|
||||||
|
"timeout": 300
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The API constructs the wire format `[JOB {job_id}] {text}` and sends via
|
||||||
|
`dm.py`. Metadata is logged to `dm-log.jsonl` alongside the text.
|
||||||
|
|
||||||
|
### Metadata in Logs
|
||||||
|
|
||||||
|
`dm-log.jsonl` entries include metadata:
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"ts": "2026-10-04T02:30:00Z",
|
||||||
|
"type": "send",
|
||||||
|
"id": "a1b2c3d4",
|
||||||
|
"metadata": {
|
||||||
|
"job_id": "board-watch-...",
|
||||||
|
"type": "job",
|
||||||
|
"priority": "normal"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
This enables:
|
||||||
|
- Filtering DMs by type, job, priority
|
||||||
|
- Building dashboards (box UI shows job DMs separately from chat)
|
||||||
|
- Audit trails (which jobs were sent, when, to whom)
|
||||||
|
- Agent learning (which job types succeed/fail)
|
||||||
|
|||||||
Reference in New Issue
Block a user