Skip to content

feat(lab-mode): per-repo config toggle — harness.config.json labMode replaces the host-wide flag file - #435

Merged
dancinlife merged 1 commit into
mainfrom
feat/lab-mode-per-repo
Jul 26, 2026
Merged

dancinlife merged 1 commit into
mainfrom
feat/lab-mode-per-repo

Conversation

@dancinlife

Copy link
Copy Markdown
Contributor

Move the lab-mode on/off switch from an ambient host flag file to a per-repo
config key. New labMode: {enabled, target} in lib/config.ts (default
{enabled:false, target:"full"}) — UNSET = OFF, so a repo that never opts in
pays zero per-turn inject.

  • resolution: the repo's harness.config.json, and nothing else. The host scope
    (~/.sidecar/lab-mode) is retired — one ambient file turning EVERY unrelated
    repo's turns into delegation directives is exactly what this removes. One repo
    can no longer enable another; --global/--host is refused.
  • pre-config flag files (.harness/lab-mode · fable-mode · host twins) are never
    consulted: status reports them as IGNORED, on/off clear them (repo ones
    deleted, host ones renamed *.retired so the user's own file is kept).
  • on/off write-back preserves sibling keys (lockdown-add precedent), writes via
    tmp+rename, and REFUSES to overwrite a malformed config (no settings loss).
    off keeps the target so a later bare on can restore it.
  • this repo commits labMode {enabled:true, target:"full"} so its current
    behavior carries over with no gap; every other repo opts in on its own.

Hook wiring (hooks.json · setup.ts · pi/sidecar.ts) and the directive text are
unchanged — both agent surfaces keep calling sidecar lab-mode inject, and the
inject budget is untouched.

Design delegated to lab full (fable + sol) and reconciled: {enabled,target}
schema from sol (matches memGuard/annotationGuard; off keeps target) over
fable's single-string; no init.ts scaffolding per fable (other toggles omit
defaults too); host flag renamed rather than deleted per sol. Both models
recommended honoring legacy repo flags for one release — dropped on the user's
rule that an unset key is false, full stop.

…replaces the host-wide flag file

Move the lab-mode on/off switch from an ambient host flag file to a per-repo
config key. New `labMode: {enabled, target}` in lib/config.ts (default
{enabled:false, target:"full"}) — UNSET = OFF, so a repo that never opts in
pays zero per-turn inject.

- resolution: the repo's harness.config.json, and nothing else. The host scope
  (~/.sidecar/lab-mode) is retired — one ambient file turning EVERY unrelated
  repo's turns into delegation directives is exactly what this removes. One repo
  can no longer enable another; --global/--host is refused.
- pre-config flag files (.harness/lab-mode · fable-mode · host twins) are never
  consulted: `status` reports them as IGNORED, `on`/`off` clear them (repo ones
  deleted, host ones renamed *.retired so the user's own file is kept).
- on/off write-back preserves sibling keys (lockdown-add precedent), writes via
  tmp+rename, and REFUSES to overwrite a malformed config (no settings loss).
  `off` keeps the target so a later bare `on` can restore it.
- this repo commits labMode {enabled:true, target:"full"} so its current
  behavior carries over with no gap; every other repo opts in on its own.

Hook wiring (hooks.json · setup.ts · pi/sidecar.ts) and the directive text are
unchanged — both agent surfaces keep calling `sidecar lab-mode inject`, and the
inject budget is untouched.

Design delegated to lab full (fable + sol) and reconciled: {enabled,target}
schema from sol (matches memGuard/annotationGuard; off keeps target) over
fable's single-string; no init.ts scaffolding per fable (other toggles omit
defaults too); host flag renamed rather than deleted per sol. Both models
recommended honoring legacy repo flags for one release — dropped on the user's
rule that an unset key is false, full stop.
@dancinlife
dancinlife merged commit a7cd039 into main Jul 26, 2026
@dancinlife
dancinlife deleted the feat/lab-mode-per-repo branch July 26, 2026 05:39
dancinlife added a commit that referenced this pull request Jul 26, 2026
…l|full (no {enabled,target} pair) (#436)

Collapse the config key to a single value: the backend name IS the on-switch, so
`{enabled:false, target:"sol"}`-style zombie states become unrepresentable. This
carries the old flag-file property ("one value per scope, contradiction
impossible") into the config, and reads the same as the CLI verb you type.

- lib/config.ts: labMode: "off" | "fable" | "sol" | "full", DEFAULTS "off".
- unset stays OFF, and now anything UNRECOGNIZED is OFF too — a typo ("fabel")
  can neither silently enable nor pass as a deliberate off; `status` prints
  `← unrecognized, treated as OFF` so the mistake is visible.
- write-back simplifies to raw.labMode = <string> (sibling keys preserved,
  tmp+rename, malformed config still refused).
- `off` no longer remembers the last target — inherent to one value, and bare
  `on` = full is unchanged, so there is no practical regression.

No compat branch for the object form shipped in #435: it existed only in this
repo's own config, normalized to "full" in this same commit.

Hook wiring and the directive text are untouched; inject budget unchanged.

Co-authored-by: dancinlife <mk55911@proton.me>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant