c6a3ed8c97c073fd1dcf1df8309040af57bedb54
The YAML `watches:` seed was the last piece of forge state the config file carried. Everything else about watches already lived in the extension: the table (SQLite, runtime-managed), the HTTP routes (`GET/POST/DELETE /v1/watches`), the chat tools, the poller that reads the table fresh every pass. A static seed list on top meant two homes for one fact — and the seed's own semantics (import-once, ignored once the table has rows) had to be explained to every reader. Now the config carries none of it: - `ClawConfig.watches` is gone, with the `Watch` seed type and the boot-time validation loop that guarded it. A config still carrying `watches:` is refused at parse time — `deny_unknown_fields` turns the retirement into a loud migration, not a silent no-op. - `Watch` moved to `watch_store` (re-exported from the crate root), where the row's vocabulary belongs; `validate_watch` keeps guarding the one door every writer shares — the routes and the tools both call it, so the moved validation tests test it there. - `seed_from_config` and the daemon's seeding are gone; the operator seeds once over HTTP or `watches add`, and the table stays true. The one guarantee the seed carried that nothing else did — boot refuses a tokenless watch — goes with it, deliberately: a tokenless watch now fails at its first poll, loudly, like any other watch the agent adds at runtime. Boot-time certainty was paying for config state the daemon no longer owns.
Languages
Rust
74.9%
Kotlin
13.8%
Vue
7.1%
TypeScript
3%
Dockerfile
0.5%
Other
0.6%