docs(v0.6): Phase 1 closeout in notes.md

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.
This commit is contained in:
2026-05-14 22:20:10 -04:00
parent 6182d89135
commit 6c4c3e8df2
+109 -19
View File
@@ -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 14) 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), `<path>` (valid, INFO), or `<path>` + `[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: <value>` 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 — <source>)` 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 14 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 57: 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)