From 6c4c3e8df2d76302d8c024148185d43f118bc22f Mon Sep 17 00:00:00 2001 From: typebasedio Date: Thu, 14 May 2026 22:20:10 -0400 Subject: [PATCH] docs(v0.6): Phase 1 closeout in notes.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Records: - Branch feat/v0.6-multi-agent-config is the active surface for v0.6; Phase 1 (5 commits) is implemented, tested, and reviewed but the branch is NOT merged into main. Phase 2 and Phase 3 will continue on the same branch per the v0.6 spec's "one branch, three sequential milestones" policy. The eventual merge happens at the end of Phase 3 alongside the version bump. - The five Phase 1 commits with one-line summaries each: 6f80c8b config file parser + resolver + source attribution 0b21b8d schema_version and workspace.mode in task.yaml c918e5c doctor Settings section with source attribution 937a1c8 info source attribution on Agent and Launch session mode 6182d89 platform-override stderr warning on launch paths - Per-commit detail: what each commit landed, where the load-bearing code lives, and what the test coverage is. - Verification gate (all clean on tip 6182d89): go test ./... -count=1, go vet ./..., go build, just build-linux (statically linked ELF). Version stays v0.5.4 — bump is deferred to the end-of-Phase-3 commit. - Phase 1 constraints held: no config auto-creation, no opportunistic schema writes, env vars remain overrides, task.yaml remains workspace state, no Phase 2 or Phase 3 work started. - Native-Windows platform-override behavior across the three surfaces: * doctor + info — show source attribution * launch paths (new/resume/last/open) — emit one stderr warning per invocation and downgrade to direct * attach — does NOT downgrade; continues to refuse via preflightPersistentEntry because it has no direct-mode equivalent - Architecture notes worth preserving for future Phase work: "one resolver per command", exported test seams, validation in ReadMeta rather than callers, omitempty as the load-bearing primitive for no-opportunistic-writes. - Files-committed list and "How to resume" section both updated to point at Phase 2 as the next horizon and to enumerate the resume sanity checks against the unmerged branch. --- notes.md | 128 ++++++++++++++++++++++++++++++++++++++++++++++--------- 1 file changed, 109 insertions(+), 19 deletions(-) diff --git a/notes.md b/notes.md index b262cf9..96ded97 100644 --- a/notes.md +++ b/notes.md @@ -1,14 +1,14 @@ # ctask — Session Handoff Notes -Last touched: 2026-05-14. **v0.5.4 is shipped on `main` and installed locally as `v0.5.4`. Branch `feat/v0.5.4-session-visibility-polish` merged via `--no-ff` (merge commit `10b7d5a`) and deleted. No tag pushed (no remote). Theme: surface workspace session state in everyday commands + finish the v0.5.3 invocation-name work + bring `docs/commands.md` current — pure polish, no new subsystems.** +Last touched: 2026-05-14. **v0.6 Phase 1 is implemented and verified on branch `feat/v0.6-multi-agent-config` (5 commits, NOT yet merged into `main`). v0.5.4 remains the shipped tip on `main` and the installed binary is still `v0.5.4` — no version bump in Phase 1 (per spec, the bump lands at the end of Phase 3). Phase 2 is the next horizon and is explicitly NOT started.** ## Where we are -- **`main`:** v0.5.4 (session-visibility polish). Tip at merge commit `10b7d5a`; version-bump commit `7704cd9`. Installed binary at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is `v0.5.4`. v0.5.3 still load-bearing underneath — none of its surfaces changed. -- **Active branches:** none. v0.5.4 feature branch was deleted post-merge. -- **Pending action:** none. v0.6 Phase 1 is the next horizon (config file + schema_version + workspace.mode + source attribution in doctor/info). See "Next" section below. +- **`main`:** v0.5.4 (session-visibility polish). Tip at merge commit `10b7d5a`; version-bump commit `7704cd9`. Installed binary at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is `v0.5.4`. Not refreshed during Phase 1 — the branch builds locally but has not been installed. +- **Active branches:** `feat/v0.6-multi-agent-config` — 5 commits ahead of `main`, all under the v0.6 theme. Not yet merged. Phase 2 + Phase 3 work will continue on this branch. +- **Pending action:** Phase 2 planning (multi-agent layer: agent profile system in task.yaml, `--agent` flag on `ctask new`, AGENTS.md + CLAUDE.md shim generation, `ctask agents check`). Phase 2 must NOT start until Phase 1 has been reviewed. - Remote: none (local-only, intentional — see `CLAUDE.md`). -- `ctask doctor` reports 5 pass/fail + 2 seed-directory + 1 `CTASK_PROJECT_ROOT` check + 1 `Session mode` INFO line + 1 tmux INFO/FAIL line (when persistent mode is configured). Unchanged in v0.5.4. +- `ctask doctor` reports 5 pass/fail + 2 seed-directory + 1 `CTASK_PROJECT_ROOT` check + 1 `Session mode` INFO line + 1 tmux INFO/FAIL line (when persistent mode is configured) + the new v0.6 `── Settings ──` block with per-key source attribution. ### What v0.4 delivered (still true, unchanged) @@ -184,9 +184,76 @@ Spec deviations (intentional, not bugs): - **The v0.5.4 spec referred to `.ctask/lease.json` and a `session_mode` field; the actual existing implementation uses `.ctask/session.json` and `mode`.** The implementation correctly followed the existing metadata names per the spec's "no new metadata fields, no behavioral changes" constraint — renaming would have been a v0.5.3 schema change masquerading as polish. Future specs touching this surface should use `.ctask/session.json` and `mode` unless intentionally renaming the metadata. - **The invocation-name audit found no production hardcoded command-form hints to change.** v0.5.3's `c204d87` had already done the work. v0.5.4 added two regression tests (`TestInvocationNameInActiveSessionPrompt`, `TestInvocationNameInRestoreHintNonCanonical`) that pin a non-canonical invocation name to prevent future drift. The split between command-form (uses `invocationName()`) and product-identity (literal `"ctask"`) is the codified rule per spec §2. -### Next: v0.6 Phase 1 +### What v0.6 Phase 1 delivered (branch `feat/v0.6-multi-agent-config`, NOT merged) -v0.6 is the **last specced direction** but the spec splits into two phases. **Only Phase 1 is in scope for the next branch.** Phase 2 (agent profiles, AGENTS.md / context-file templates, PID liveness, lazy-cleanup adoption changes) is explicitly out of scope until Phase 1 is implemented, tested, and reviewed. +Theme: **infrastructure foundation for v0.6** — global config file, schema versioning in task.yaml, and source attribution in doctor/info. Five commits on the feature branch; no version bump (lands at end of Phase 3). All Phase 1 spec items (`v0.6-spec.md` sections 1–4) covered, plus a follow-up commit added on reviewer request for the native-Windows session_mode launch-time warning. + +#### Commit list (oldest → newest) + +- `6f80c8b` `feat(v0.6): config file parser + resolver + source attribution` + - `internal/config/configfile.go` — strict-key YAML parser; unknown top-level keys invalidate the whole file with the offending key named; future schema versions rejected with an upgrade message. Platform-appropriate path (`$XDG_CONFIG_HOME/ctask/config.yaml` → `~/.config/...` fallback on Unix; `%APPDATA%\ctask\config.yaml` on native Windows). + - `internal/config/resolver.go` — `Resolver` / `ResolvedSetting` / `SettingSource` with five values (`Builtin`, `ConfigFileSrc`, `EnvVar`, `CLIFlag` reserved for v0.6 Phase 2, `PlatformOverride`). Each setting carries an `Override` chain so doctor can render `env var (overrides config file: X)`. Per-setting methods: `CtaskRoot`, `ProjectRoot`, `SeedDir`, `DefaultAgent`, `DefaultCategory`, `Editor`, `SessionMode`. `SessionMode` applies the native-Windows platform override at the resolver layer with the configured value chained as `Override`. Exports `SetConfigPathForTest` and `SetIsNativeWindowsForTest` so cross-package tests can isolate. + - `internal/config/config.go` — legacy `ResolveRoot` / `ResolveAgent` / `ResolveSeedDir` / `ResolveProjectRoot` / `ResolveSessionMode` wrappers migrated to `LoadResolver()` so config-file values take effect for entry commands. `ResolveProjectRoot` preserves the `""` sentinel for `Builtin` source so `SearchRoots` and doctor's `checkProjectRoot` keep their v0.5 fallback semantics. `ResolveSessionMode` keeps the unknown-value stderr warning, distinguishing env-var vs config-file sources in the message. + - Tests: 6 LoadConfigFile + 3 ConfigFilePath + 11 resolver cases including layering, override chains, path expansion, platform override, and `SettingSource.String()` rendering. +- `0b21b8d` `feat(v0.6): schema_version and workspace.mode in task.yaml` + - `CurrentMetaSchemaVersion = 1` constant + `WorkspaceSection struct{ Mode string }` nested block. + - `TaskMeta` gains `SchemaVersion int` and `Workspace WorkspaceSection` fields at the top of the struct. Both `omitempty` — this is what enforces the no-opportunistic-writes invariant: legacy task.yaml files (no `schema_version`, no `workspace:`) round-trip through `WriteMeta` / `WriteMetaLocked` without acquiring those keys. + - `EffectiveSchemaVersion(meta)` returns 1 for stored-value-0 legacy workspaces; non-zero stored values pass through verbatim. + - `ValidateSchemaVersion(slug, meta)` rejects values above `CurrentMetaSchemaVersion` with the spec-mandated upgrade message; `ValidateWorkspaceMode(slug, meta)` rejects values other than `""` and `"native"` (so a Phase 1 binary refuses an "adopted" mode set by hand or by a future v0.7). + - `ReadMeta` now runs both validators after YAML unmarshal. The error includes the workspace slug (derived from the file's `slug:` field or the directory basename when the file itself is corrupt). + - `workspace.Create` stamps every new meta with `SchemaVersion: 1` and `Workspace.Mode: "native"`. This is the ONLY write site for these fields in v0.6. + - Tests: 10 cases including the dedicated `TestLegacyTaskYamlNotBackfilledByWrite` and `TestLegacyTaskYamlNotBackfilledByLockedWrite` regressions that pin the no-opportunistic-writes invariant. +- `c918e5c` `feat(v0.6): doctor Settings section with source attribution` + - New `── Settings ──` block appended between the existing `checkTmux` line and the `N checks passed, M failed` summary. Loaded via `config.LoadResolver()` exactly once per `runDoctor` invocation and reused across every settings line (per user correction: "load the resolver once and reuse it"). + - First emits the config-file lifecycle line: `not found` (INFO), `` (valid, INFO), or `` + `[FAIL] unknown key: "..."` + advisory (invalid, increments `failed`). + - Then iterates `r.CtaskRoot() / ProjectRoot() / SeedDir() / DefaultAgent() / DefaultCategory() / SessionMode() / Editor()` and renders each via `printSettingLine` (key/value/source trio + chained-override info). `PlatformOverride` adds a `configured: ` row so doctor surfaces both the effective and the user-asked-for value. + - Helper `formatSettingSource` centralises the `EnvVar → CTASK_X env var` / `PlatformOverride → ... (persistent mode requires tmux; not available on native Windows)` / override-chain wording. + - Tests: 6 cases including the platform-override `configured: persistent` rendering. +- `937a1c8` `feat(v0.6): info source attribution on Agent and Launch session mode` + - `cmd/info.go::runInfo` calls `config.LoadResolver()` once and reuses it. + - `Agent:` line gains `(workspace)` when `m.Agent` is non-empty (the common case), or `(default)` / `(default — )` when the legacy field is empty and the value falls through to the resolver. + - New `Launch session mode:` row inserted directly between `Agent:` and `Created:`, **outside** the v0.5.4 Session block (per user decision: the Session block represents the current lease's recorded mode; the new line represents the configured launch default — two different things). + - Helper `infoSourceLabel` is the info-side counterpart to `formatSettingSource`. No override-chain suffix in info (single-row layout has no room for the extra parenthetical). + - Tests: 5 cases including a placement check that asserts `Agent < Launch session mode < Created` in the rendered output. +- `6182d89` `feat(v0.6): platform-override stderr warning on launch paths` + - Reviewer follow-up: the v0.6 spec section 1.8 also calls for a stderr warning at launch time when persistent mode is downgraded; commits 1–4 covered the doctor/info display path but the launch paths were still downgrading silently. This commit fixes that. + - New helper `cmd/persistent.go::emitPlatformOverrideWarningIfNeeded(alwaysPersistent bool)` — loads the resolver, emits the warning on stderr when `SessionMode()` reports `PlatformOverride` source AND the caller is not `AlwaysPersistent`. + - Single call site at the top of `cmd/entry.go::defaultRunWorkspaceEntry`, before any launch work. That function is the funnel for `new`, `resume`, `last`, `open` (which can downgrade) AND `attach` (which can't). attach sets `AlwaysPersistent: true`, so the helper short-circuits. + - Warning text (exact): `[ctask] warning: persistent session mode is not supported on native Windows; using direct mode. Use WSL for persistent sessions.` + - "Once per invocation" is provided implicitly by the call site running at most once per ctask command — no warn-once subsystem. + - Tests: 5 cases including the AlwaysPersistent skip gate. attach's actual native-Windows refusal contract (via `preflightPersistentEntry`) continues to be enforced by the pre-existing `TestPreflightRefusesNativeWindows`. + +#### Verification (run on `feat/v0.6-multi-agent-config` tip `6182d89`) + +- `go test ./... -count=1` — all 7 packages `ok`, 0 failures. +- `go vet ./...` — exit 0. +- `go build -o ctask.exe .` — exit 0. +- `just build-linux` — produces `dist/ctask-linux-amd64`, statically linked ELF (`file` reports `statically linked`). +- Version remains `v0.5.4`; bump deferred to the end-of-Phase-3 commit per `v0.6-spec.md` "Commit ordering". + +#### Phase 1 constraints held + +- **No config auto-creation.** `LoadConfigFile` returns `(nil, nil)` on `IsNotExist`; nothing in the codebase writes a config file. Missing file renders as INFO in doctor, never FAIL. +- **No opportunistic schema writes.** The two new task.yaml fields use YAML `omitempty`; legacy files round-trip through `WriteMetaLocked` (the path used by `resume` / `archive` / `restore`) without acquiring `schema_version` or `workspace:`. Pinned by `TestLegacyTaskYamlNotBackfilledByWrite` + `TestLegacyTaskYamlNotBackfilledByLockedWrite`. +- **Env vars preserved as overrides.** The resolver layers them above config; no deprecation. Override chain captured in `ResolvedSetting.Override` so doctor renders `CTASK_X env var (overrides config file: Y)`. +- **task.yaml remains workspace state.** Phase 1 does NOT introduce per-workspace fields like `agent.type` or fold task.yaml into the resolver chain. The Agent and Launch session mode lines in info correctly distinguish `(workspace)` from user-level-default sources. +- **No Phase 2 work started.** Verified by diff: no agent-profile fields in `TaskMeta`, no `--agent` flag on `ctask new`, no AGENTS.md / CLAUDE.md shim generation, no `ctask agents check`, no `context/notes-archive/` scaffolding. `internal/seed/templates.go` unchanged. +- **No Phase 3 work started.** Verified by diff: no PID-liveness logic, no changes to `internal/session/lease.go` or `internal/session/adopt.go`, no change to the 60s `StaleLeaseAfter` threshold or its callers. + +#### Native-Windows platform-override behavior (codified in Phase 1) + +- **Doctor + info show source attribution.** Doctor's Settings block renders `session_mode: direct` + `source: platform override (...)` + `configured: persistent` when config says persistent on native Windows. Info's `Launch session mode:` line surfaces the same effective value with its source label. +- **Launch paths warn once per invocation and downgrade to direct.** `new`, `resume`, `last`, `open` all funnel through `defaultRunWorkspaceEntry`, which calls `emitPlatformOverrideWarningIfNeeded(false)` at the top. Exactly one stderr line per process invocation. No warn-once subsystem — the call site frequency is what enforces "once". +- **`ctask attach` does NOT downgrade.** attach sets `AlwaysPersistent: true`, which (a) bypasses the warning helper and (b) routes through `preflightPersistentEntry` which refuses on native Windows with the v0.5.3 "ctask persistent mode requires tmux ... Recommended: Run ctask from WSL" message. attach has no direct-mode equivalent — refusal is the right contract. + +#### Architecture notes (worth preserving) + +- **One resolver per command.** `config.LoadResolver()` is cheap (one config file read + env snapshot) but doctor/info call it exactly once per invocation and reuse the result across many `Resolver.X()` accessors. Legacy `Resolve*` wrappers (`ResolveRoot` etc.) each construct a fresh resolver — acceptable for entry commands that call them once or twice; new code in `cmd/` should follow the doctor/info pattern. +- **Test seams are exported.** `config.SetConfigPathForTest(t, path)` and `config.SetIsNativeWindowsForTest(t, f)` are exported helpers so `cmd/`-package tests can isolate from developer-host config files and simulate platform-override scenarios without `runtime.GOOS` skips. +- **Validation lives in `ReadMeta`, not in callers.** The schema-version and workspace-mode checks happen at read time — so any path that gets a `*TaskMeta` has already passed validation. Callers do not need to re-check. +- **`omitempty` is the load-bearing primitive for "no opportunistic writes."** If a future change needs to track another optional field, follow the same pattern: zero value must round-trip without serialization, and only `workspace.Create` (or an explicit migration) writes a non-zero value. + +### Historical: original Phase 1 plan (now shipped — kept for traceability) **Phase 1 scope (only thing to start next):** @@ -215,10 +282,10 @@ Covered in v0.4.1 notes. The exit-code gate (`childExitCode != 0 && startManifes ## Tree state at pause -- `main` clean with respect to v0.4, v0.4.1, v0.5, v0.5.1, v0.5.2, v0.5.3, v0.5.4. Latest tip is the merge commit `10b7d5a Merge branch 'feat/v0.5.4-session-visibility-polish' into main`; the v0.5.4 version-bump commit `7704cd9` sits on the merged-in branch tip. -- No tag pushed for v0.5.4 (no remote — the project is intentionally local-only per `CLAUDE.md`). v0.5.3 had `git tag v0.5.3` locally; v0.5.4 has none. Add later if a publication path opens up. -- No active branches. `feat/v0.5.4-session-visibility-polish` was deleted post-merge. -- Installed `ctask.exe` at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is **v0.5.4** (refreshed via `just install` after merge). `dist/ctask-linux-amd64` is the v0.5.4 Linux cross-build (statically linked ELF, 7.5 MiB). +- `main` tip is unchanged: `10b7d5a Merge branch 'feat/v0.5.4-session-visibility-polish' into main` (v0.5.4 shipped). +- `feat/v0.6-multi-agent-config` is the active branch, 5 commits ahead of `main`. Tip `6182d89`. NOT merged — Phase 2 and Phase 3 will continue on this same branch per spec. +- No tag pushed for v0.5.4 (no remote — the project is intentionally local-only per `CLAUDE.md`). v0.5.3 had `git tag v0.5.3` locally; v0.5.4 has none. No v0.6 tag yet — that's a post-Phase-3 task. +- Installed `ctask.exe` at `%LOCALAPPDATA%\ctask\bin\ctask.exe` is still **v0.5.4** — Phase 1 did NOT refresh the installed binary. Local `ctask.exe` in the repo root is a `6182d89` build. `dist/ctask-linux-amd64` is the Phase-1 Linux cross-build (statically linked ELF). - Memory follow-ups (still live from v0.5.3, both relevant to v0.6 Phase 2 — see `memory/MEMORY.md`): - `feedback_design_for_lazy_cleanup` — drives v0.6 Phase 2 work on the 60s freshness wait + PID liveness. - `feedback_invocation_name_in_hints` — partially closed by the v0.5.4 audit (split between command-form and product-identity is now codified). Memory entry retained for the descriptive-prose question, which Phase 2 may revisit. @@ -237,10 +304,29 @@ Covered in v0.4.1 notes. The exit-code gate (`childExitCode != 0 && startManifes - `cmd/invocation_audit_test.go` (regression tests pinning a non-canonical invocation name) - `cmd/resume_archived_polish_test.go` (Cobra-end-to-end test that the duplicate `Error:` line is suppressed) - `docs/commands.md` (rewrite — see commit `4fd0bef`) +- Files committed on `feat/v0.6-multi-agent-config` (NOT yet merged): + - `internal/config/configfile.go` + `configfile_test.go` (strict-key YAML parser + ConfigFilePath) + - `internal/config/resolver.go` + `resolver_test.go` (Resolver + ResolvedSetting + SettingSource + 2 exported test seams) + - `internal/config/config.go` modified (5 legacy wrappers migrated to LoadResolver) + - `internal/config/config_test.go` + `config_roots_test.go` modified (config-path isolation in tests that assert Builtin defaults) + - `internal/workspace/metadata.go` modified (CurrentMetaSchemaVersion, WorkspaceSection, SchemaVersion + Workspace fields on TaskMeta, EffectiveSchemaVersion + ValidateSchemaVersion + ValidateWorkspaceMode helpers, ReadMeta validation) + - `internal/workspace/create.go` modified (writes schema_version: 1 + workspace.mode: native) + - `internal/workspace/schema_test.go` (10 tests including the two no-opportunistic-writes regressions) + - `cmd/doctor.go` modified (── Settings ── block + checkSettings + printSettingLine + formatSettingSource) + - `cmd/doctor_test.go` modified (config import + 2 tests gated by SetIsNativeWindowsForTest) + - `cmd/doctor_settings_test.go` (6 tests covering the new Settings block) + - `cmd/info.go` modified (Agent source label + new Launch session mode line + agentLineWithSource + infoSourceLabel) + - `cmd/info_attribution_test.go` (5 tests including placement assertion) + - `cmd/new_persistent_test.go` modified (config import + 1 test gated by SetIsNativeWindowsForTest) + - `cmd/entry.go` modified (emitPlatformOverrideWarningIfNeeded call at top of defaultRunWorkspaceEntry) + - `cmd/persistent.go` modified (config import + platformOverrideWarning const + emitPlatformOverrideWarningIfNeeded helper) + - `cmd/platform_warning_test.go` (5 tests covering the warning + AlwaysPersistent skip) ## How to resume -v0.5.4 is shipped; no pending follow-through. Next horizon is v0.6 Phase 1 only — see "Next: v0.6 Phase 1" above. **Do not begin Phase 2 work** (agent profiles, AGENTS.md, PID liveness, lazy-cleanup adoption) until Phase 1 is implemented, tested, and reviewed. +v0.6 Phase 1 is shipped on `feat/v0.6-multi-agent-config` and reviewed. **The branch is NOT merged into `main` yet** — Phase 2 (and Phase 3) will continue on the same branch per the v0.6 spec's "one branch, three sequential milestones" policy. The eventual merge happens at the end of Phase 3 alongside the version bump. + +**Do not begin Phase 2 work** (agent profiles, `--agent` flag, AGENTS.md + CLAUDE.md shim, `ctask agents check`) until the Phase 2 plan is written and reviewed. Phase 3 (PID liveness, lazy-cleanup adoption, context-file scaffolding) does not start until Phase 2 is implemented, tested, and reviewed. ### General resume (on `main` after a ship) @@ -278,19 +364,23 @@ ctask doctor 2>&1 | grep -E "Session mode|tmux" unset CTASK_SESSION_MODE ``` -### Starting v0.6 Phase 1 +### Starting v0.6 Phase 2 -Suggested opening session prompt (paste into a fresh ctask agent session on `main`): +Branch is already `feat/v0.6-multi-agent-config`; check it out and continue. **Read the Phase 1 ship report above first** — Phase 2 builds on the resolver and the task.yaml schema fields it landed. -> Implement v0.6 Phase 1 only, per the scope listed in `notes.md` ("Next: v0.6 Phase 1"): config file parser + resolver, `schema_version` and `workspace.mode` fields in `task.yaml`, source attribution in `ctask doctor` and `ctask info`. Start with the brainstorming skill to lock the config file format (XDG path, key names, layering rules). Do not start Phase 2 work (agent profiles, AGENTS.md, PID liveness, lazy-cleanup adoption) — those are explicitly deferred. +Suggested opening session prompt (paste into a fresh ctask agent session): -Branch creation (when ready to start coding): +> Begin v0.6 Phase 2 implementation planning only. Phase 1 is complete on `feat/v0.6-multi-agent-config` (see `notes.md`). Phase 2 scope per `v0.6-spec.md` sections 5–7: agent profile system in task.yaml (`agent.type` / `agent.command` / `agent.args` / `agent.env`; built-in types `claude` and `opencode`, escape hatch `custom`), `--agent` flag on `ctask new` with the deferred `TestCLIFlagOverridesEnvVar`, AGENTS.md canonical file + CLAUDE.md shim (claude type only — opencode shim deferred until conventions are verified), and `ctask agents check` validation command. Per spec implementation notes, the AGENTS.md template + `handoff.md` + `context/notes-archive/` scaffold land together in one seed-template change (commit 7 in the spec's ordering) — Phase 3's context-file scaffolding rides along with Phase 2's seed work to avoid rewriting templates twice. Stop after Phase 2 planning; do not start Phase 3 (PID liveness). + +Resume sanity checks: ```powershell cd C:\Users\Warren\claude_tasks\ctask -git checkout main -git pull # no-op (no remote), but cheap habit -git checkout -b feat/v0.6-phase1-config-and-schema +git checkout feat/v0.6-multi-agent-config +git log --oneline main..HEAD # expect 5 commits, tip 6182d89 +just test # all 7 packages green +just build # ctask.exe builds locally +just build-linux # dist/ctask-linux-amd64 statically linked ``` ## Load-bearing design points (don't forget)