## What
Wave 2 of the AgentOps 3.0 honest-docs sweep (post-#518 audit, bead
ag-qbw). Makes the `docs/` prose match the shipped code: the daemon,
scheduler, factory, and all hooks were **DELETED** (not deprecated).
AgentOps is the in-session loop + context compiler; out-of-session
orchestration is delegated to a substrate (Gas City reference City /
Olympus). Mirrors the already-correct `docs/3.0.md`.
This makes `docs/3.0.md:150` ("the standalone
daemon/scheduler/overnight-runner surfaces are gone from ... live doc
prose") true for the enumerated wave-2 surfaces.
## Deleted (whole docs about deleted commands)
- `docs/scheduling.md` — entire `ao schedule` + `ao daemon` guide
-
`docs/contracts/{agentopsd-control-plane,agentopsd-schedule,routing-policy}.md`
- `docs/contracts/jobspec-openapi-v0.yaml`
- `docs/templates/dark-factory-schedule.yaml.example`
- `docs/design/olympus-v4-specs/*.md` — v4-port reference for the dead
Olympus → agentopsd extraction
## Reframed (prose → in-session + Gas City)
- Daemon/schedule/overnight: `agentops-3-youtube-starter-series.md`,
`agentops-3-pmf-evidence-loop.md`, `wiki-for-agents.md`,
`activation-profiles.md` (+ `profiles/README.md` profile rename),
`CI-CD.md` (overnight lane)
- Hooks → hookless + CI-as-authoritative-gate (hooks removed #511):
`knowledge-flywheel.md`, `troubleshooting.md`, `reference.md`,
`CI-CD.md`, `release-e2e-checklist.md`, `seed-definition.md`
## Catalog + cross-link cleanup (no broken links)
- `documentation-index.md` — removed deleted-doc rows + the v4 section
- `contracts/index.md` — removed deleted-contract cards
- `rfcs/0002-jobspec-openapi-v0.md` marked superseded; `SCHEMAS.md`,
`templates/README.md` cross-links fixed
## Created
- `docs/MIGRATION-3.0.md` (from the approved draft) + catalog row +
mkdocs nav entry
## Gates (green for this PR's surfaces)
- Link check: **2723 links, 0 broken**
- Contracts structural floor: **PASS (45 contracts)**
- Contract compatibility (orphans): **PASS**
- markdownlint (all changed/new files): **clean**
- `heal.sh --strict`: **All clean**
- mkdocs-strict: my new doc + nav entry build cleanly. The strict build
is **red on main for pre-existing reasons outside this scope** —
`docs/_hooks/gen_cli_reference.py` FATALs on missing `cli/docs/HOOKS.md`
(hooks removed #511, generator not updated; release-mechanics domain)
and `docs/3.0.md:172` links `../PRODUCT.md`/`../GOALS.md` (root files
outside the docs tree). Both confirmed present on `origin/main`; filed
for wave 3.
## Scope notes
- Did **not** touch `CHANGELOG.md`, `cli/`, or version files (parallel
worker owns release mechanics).
- The audit grep still matches ~40 more out-of-scope `docs/` files
(contracts/*, code-map, comparisons, narrative pages, runbooks). Filed
as **wave 3 (ag-p7j)**.
Closes-scenario: ag-qbw#doc-sweep-2
Bounded-context: BC1-Corpus
Evidence: docs/3.0.md
7.0 KiB
RFC 0002: JobSpec OpenAPI v0
Status: superseded (the daemon was deleted in AgentOps 3.0 — see ADR-0009)
Date: 2026-04-30
Companion spec: docs/contracts/jobspec-openapi-v0.yaml (removed with the daemon)
Superseded. This RFC proposed a conformance contract for the standalone
agentopsddaemon. The daemon, its job queue, and this companion spec were deleted in the 3.0 in-session-only rearchitecture. AgentOps runs the loop in session; out-of-session orchestration is delegated to a substrate (Gas City is the reference). Kept as a historical decision record only.
Decision Ask
Publish JobSpec OpenAPI v0 as the first daemon conformance contract for
AgentOps runtimes. The v0 contract describes current agentopsd behavior only:
durable job submission, cancellation, queue state, ledger replay, projection
readiness, and the OpenClaw consumer surface.
This RFC does not ask to refactor agentopsd, add placement, or introduce new
job types. It asks whether the current behavior is stable enough to name,
document, test, and publish.
Context
The strategic direction is now:
The 12-factor doctrine is the product.
agentops is the implementation.
agentopsd is plumbing.
Be the conformance program.
That only works if the public contract names actual behavior. The daemon has a small useful kernel today:
- loopback-local HTTP routes
- local-token-protected mutations
- append-only daemon ledger under
.agents/daemon/ledger.jsonl - durable-first mutation acknowledgement
- idempotent recovery by
job_idoridempotency_key - queue leasing with claim tokens, lease epochs, heartbeats, retry waiting, and terminal completion, failure, or cancellation
- read models rebuilt from ledger replay
- OpenClaw projection resources and allowlisted safe triggers
The OpenAPI document turns that kernel into a portable conformance target. Any runtime can implement the same contract without adopting AgentOps internals.
Current Behavior Captured
Source of truth:
cli/internal/daemon/server.gofor HTTP routes and response structscli/internal/daemon/jobs.gofor queue mutation and replay behaviorcli/internal/daemon/types.gofor job, status, event, and failure enumscli/internal/daemon/projections.gofor projection names and read modelscli/internal/openclaw/api.goandcli/internal/openclaw/types.gofor the OpenClaw consumer surface
Versioned daemon routes:
| Route | Method | Purpose |
|---|---|---|
/v1/health |
GET | process health |
/v1/ready |
GET | ledger replay and projection readiness |
/v1/status |
GET | queue snapshot and projections |
/v1/events |
GET | replayed ledger events |
/v1/jobs |
POST | submit a durable daemon job |
/v1/jobs/cancel |
POST | cancel a non-terminal daemon job |
The current router also exposes unversioned aliases for the same daemon routes.
OpenClaw consumer routes:
| Route | Method | Purpose |
|---|---|---|
/openclaw/v1/health |
GET | consumer projection health |
/openclaw/v1/snapshot/latest |
GET | aggregate consumer snapshot |
/openclaw/v1/runs |
GET | run resources |
/openclaw/v1/jobs |
GET | job resources |
/openclaw/v1/wiki |
GET | wiki resources |
/openclaw/v1/triggers/jobs |
POST | allowlisted job trigger |
Non-Goals
JobSpec v0 intentionally excludes:
placement.affinity- node scheduling
- provider capability negotiation
- new worker kinds
- retry policy configuration beyond the current fixed queue options
- distributed lease coordination beyond the current ledger-derived queue
- public browser-safe mutation semantics
Those may belong in later RFCs. They do not belong in a current-behavior v0.
Contract Shape
The public submission envelope is the current SubmitJobRequest:
{
"request_id": "req_20260430_000001",
"job_id": "job_rpi_000001",
"job_type": "rpi.run",
"idempotency_key": "rpi:demo:cycle-1",
"payload": {
"goal": "Draft current-behavior JobSpec v0"
}
}
The accepted response names the durable ids, the queue status, and projection acknowledgement state:
{
"accepted": true,
"request_id": "req_20260430_000001",
"job_id": "job_rpi_000001",
"status": "queued",
"last_event_id": "evt_job.accepted_job_rpi_000001_000001",
"projection_status": "current",
"projection_lag": {
"last_event_id": "evt_job.accepted_job_rpi_000001_000001",
"event_count": 1,
"corrupt_record_count": 0,
"degraded": false
},
"idempotency_key": "rpi:demo:cycle-1"
}
The queue state machine is intentionally conservative:
queued -> running -> completed
queued -> running -> failed
queued -> running -> retry_waiting -> running
queued -> cancelled
running -> cancelled
Terminal statuses are completed, failed, and cancelled. A terminal ledger
event wins over any projection or lease state.
Conformance Profile
An implementation conforms to JobSpec v0 when it can pass these observable checks:
GET /v1/healthreturnsstatus=ok,daemon=agentopsd, and a timestamp.GET /v1/readyreports replay status, projection status, projection lag, and degraded reasons without mutating quarantine state.POST /v1/jobsrequires local mutation authorization and appends a durable accepted event before returning202.- Retrying a submit with the same
job_idoridempotency_keyreturns the existing job instead of appending a duplicate accepted event. GET /v1/statusexposes queue jobs rebuilt from the ledger.- Running jobs carry a claim token, lease epoch, lease expiry, and attempt count.
- Expired leases become claimable again as
retry_waitinguntil retry exhaustion. POST /v1/jobs/cancelappends a cancellation for non-terminal jobs and returns analready_terminal_*outcome for terminal jobs.GET /v1/eventsreturns replayed ledger events and last event id.- OpenClaw read routes report resources from the same daemon projections as
/v1/status. /openclaw/v1/triggers/jobsrefuses non-allowlisted job types.
The next tactical step is to turn this list into golden compatibility tests for
/jobs, /status, ledger replay, and queue transitions.
Open Questions
- Should invalid
job_typeon/v1/jobsbecome a400in v1, or should v0 preserve the current generic error behavior until a compatibility window is announced? - Should unversioned route aliases be part of conformance, or documented as compatibility conveniences outside the required profile?
- Should
placement.affinitybe a JobSpec v0 extension field underpayload.placement, or wait for JobSpec v1 after the mt-olympus shim soaks? - Should OpenClaw stay inside the JobSpec v0 document, or split into a separate consumer API conformance profile?
Recommendation
Publish the OpenAPI as a draft RFC now. Treat it as a compatibility target, not as a promise that the daemon API is finished. The value is category ownership: the schema makes the doctrine executable while preserving the council's scope discipline.