Graduate a Labs feature
Graduation removes a feature's Labs switch and makes it a normal feature. Two separate decisions, made by the owner before any code:
- Leave Labs: the feature gets a permanent home (its own settings or plugin page) and loses Labs wording.
- Default: on by default, or still off by default.
They are independent. #197029 first tried both, then shipped only the first: Advisor left Labs but stayed off. Ask which one is wanted; do not assume "graduate" means "on by default".
Precedents: Swarm on by default (#136514), Tool Search on by default (#154068), native plugin UI on without a Labs opt-in (de50262a1f96), Labs features moved into Settings (#145460), Advisor out of Labs and still off (#197029).
Before the PR
- Measure cost or risk on the real route if the feature costs money or tokens, or changes behavior for users who never opted in. Today's numbers from mocks or unit tests are not proof. #197074 merged a cache-cost claim from a mock that live providers disproved, and was reverted in #197175. Use the live measurement the feature's own PRs already established, and put the numbers in the PR body.
- Settle known defects first. Advisor's graduation waited for its fork cache fixes (#197203, #197223, #197224, #197226) because default-on would have charged every user the uncached cost.
- Find the enable path that remains. After the Labs row goes, users must still be able to turn the feature on from the UI. A bundled plugin uses Settings → Plugins → → Enable; a core feature needs its settings page. Add a switch only if none exists.
The change
- Default. Change it only if the owner chose on by default: a bundled plugin's
enabledByDefaultinopenclaw.plugin.json, or the core config default. An existing explicitfalse(or the feature's opt-out value) must keep working, and an existingtruemust stay on. Never add a migration that rewrites saved config to change someone's choice. - Labs. Remove the entry from
ui/src/pages/labs/labs-registry.tsand everything only it used:labs-page.tsxrows or slots,labs-feature-state.tsentries, strings and tests. - Docs. Move the feature's section out of
docs/concepts/experimental-features.mdinto its own reference page. Leave a one-paragraph note there with the old anchor, saying it graduated, its default, and where to turn it on. Update the "Labs includes ..." list and the "Currently documented flags" table. - Wording. Remove "Experimental" and "OpenClaw Labs" from the manifest description, package description, README, plugin summary, and any user- or model-facing text such as prompt prefixes.
- Generated files. Regenerate, never hand-merge:
pnpm config:docs:gen,pnpm plugins:inventory:gen. Control UI locale artifacts (*.meta.json,*.tm.jsonl,catalog-fallbacks.json) stay out of the PR perui/AGENTS.md; the locale refresh workflow updates them.pnpm ui:i18n:verifymust pass. - Upgrade proof. Only for a default change: prove across a real upgrade that no saved entry gets the new default, an explicit off stays off, and an explicit on stays on. A default that stays the same needs no upgrade case; #197029 dropped the one it had built for default-on.
Proof in the PR
- Control UI screenshots, inspected for private data before upload: Labs before and after, and the enable path working on a real Gateway. Attach them with
gh pr comment <n> --attach '<file>#<alt text>'. - The enable path tested end to end: the switch saves the expected config and takes effect without a restart.
- The feature's tests and the Labs page tests pass; the test-lines ratchet does not grow.
- Docs claims match code. ClawSweeper caught Advisor's "at most one review per
everyMinutes", which was false witheveryToolCallson.
After merge
The new location only appears in builds that include the merge. Tell users the exact path, and that older builds still show the Labs switch.