Add the v0.5.2 round summary (commits a5e508b..3b6be0d +5910100): restore/notes/path commands, direct-lookup archived-inclusive policy, resume archived hint, list --names, shell completion, cross-workspace context seed section. Windows + WSL validation passed; Linux binary statically linked. Add load-bearing v0.5.2 invariants to the "don't unlearn" section (archived-inclusive lookup policy, list --names emits basenames not slugs, completion calls ListWorkspaces directly, etc.). Replace the "Next: v0.5.2" pointer with a "Next: v0.6 (planning)" stub covering config/agent profile work, resume-error polish, and flag-aware completion for open/delete --all. Drop v0.5.2-spec.md from the untracked-files list (committed ina5e508b).
28 KiB
ctask — Session Handoff Notes
Last touched: 2026-05-07 (after v0.5.2 ship). Pause before starting v0.6.
Where we are
v0.5.1 is shipped on main and installed locally. v0.5 added nested project structure (project subdir scaffolding, launch_dir-driven cd into the subdir, default discovery including $CTASK_ROOT/projects/). v0.5.1 is a tiny follow-up that fixes a UTC-date confusion surfaced during v0.5 smoke testing.
- Version string:
v0.5.1(seecmd/root.go) - Branch:
main - Remote: none (local-only, intentional — see
CLAUDE.md) - Tests: all pass across 7 packages (
go test ./... -count=1) go vet ./...clean,go build ./...clean- Installed at
%LOCALAPPDATA%\ctask\bin\ctask.exeviajust install— reflects both v0.5 and v0.5.1 ctask doctornow reports 5 pass/fail checks + 2 seed-directory checks + 1CTASK_PROJECT_ROOTcheck (all three-state)
What v0.4 delivered (still true, unchanged)
Workspace concurrency protection — session lease with heartbeat (Layer 1), metadata write lock (Layer 2), stale-workspace detection (Layer 3), session handoff summary (Layer 4). --force flag on resume/last/open. WriteMetaLocked, LaunchOpts.Force, Preflight. All unchanged in v0.5.
What v0.4.1 delivered (still true, unchanged)
Correctness and polish: config.SearchRoots() multi-root discovery; two-depth scanWorkspaces (flat + category, first-match-wins); nested-git documentation; doctor seed-dir three-state checks; archive active-session warning with non-TTY refuse; provisional-cleanup exit-code gate. Still load-bearing — see "From v0.4.1" section below.
What v0.5 delivered
Theme: separate workspace management from project code. --project now scaffolds a project subdirectory and session commands cd into it. Twelve commits on main (175fbb0..8130a68).
launch_dirfield inTaskMeta(175fbb0)- New
LaunchDir stringwithyaml:"launch_dir,omitempty"— empty for tasks and pre-v0.5 projects, defaults to the project slug for new projects. - Omitempty keeps on-disk task.yaml clean for backward compatibility.
- New
workspace.ResolveLaunchhelper (dcb1610)- Converts a relative
launch_dirinto an absolute child-cwd with three outcomes:- Valid dir → return absolute path, no warning, no error.
- Missing path (
os.IsNotExist) or path-is-a-file → return(wsDir, warning, nil)so the caller warns and falls back. - Absolute path,
..-escape, or any non-IsNotExiststat error (permission, ENOTDIR, invalid name) → return("", "", error)— caller must surface.
- This asymmetry is deliberate — masking a permission error as a warning fallback would silently strip launch-dir semantics.
- Converts a relative
- Project subdirectory scaffolding (
7cfafdc)ctask new --projectcreates an empty subdir named after the final suffixed slug (sodup-2collisions produce matchingdup-2/subdir).- ctask does not seed anything inside the subdir — the user places their own CLAUDE.md, source code, project configuration.
- Task workspaces are completely unchanged — no subdir, no
launch_dir.
CTASK_LAUNCH_DIRenv var (509a6d6)- Added as a 7th arg to
config.EnvVars. All three cmd callers (new,resume,open) passws.Meta.LaunchDir.
- Added as a 7th arg to
- Session launch routed through
LaunchDir(103f2cd)LaunchOpts.LaunchDiradded.session.RuncallsResolveLaunchbefore banner/exec, prints any warning to stderr, aborts on security error, and passes the absolute path toshell.ExecAgent/shell.ExecShellas the child's working directory.- Banner gains a
[ctask] project dir: <name>/line whenlaunch_diris set. - Lease, manifest, heartbeat, and summary scope stays the workspace root — only the child's cwd changes.
ctask infoshows launch fields (cdff7f3)- For workspaces with
launch_dirset, info printsLaunch dir:,Launch path:, andDir exists: yes|no(via directos.Stat, not viaResolveLaunch— info is a display command, not a launch command).
- For workspaces with
SearchRootsdefault fallback (47430a1)- When
CTASK_PROJECT_ROOTis unset,SearchRoots()now appends$CTASK_ROOT/projects/so default-location projects are findable from any shell (resolves the v0.4.1 env-var scoping footgun from the previous follow-up list). - Dedupe in
scanAllRootsprevents duplicate results when the same workspace is reachable via both the depth-2 scan underCTASK_ROOTand the explicit$CTASK_ROOT/projects/search root.
- When
- Doctor
CTASK_PROJECT_ROOTcheck (70bd167)- Three-state, matching the
checkSeedDirpattern:[INFO]when unset (points at$CTASK_ROOT/projects/),[INFO]with user-scope advisory when set+exists,[FAIL]when set but missing. Only FAIL increments the failure counter. - Wording is advisory ("recommended: set at user scope…"), not prescriptive.
- Three-state, matching the
- Project CLAUDE.md template rewrite (
cdf1c55)- Adds a "Workspace Structure" section explicitly describing the root-vs-subdir split.
- Keeps the "Git" section from v0.4.1, now with an explicit mention that the project subdir is tracked by the root repo.
- Status line helpers show effective launch path (
0976dce)- Both
.shand.ps1buildDISPLAY_PATH = $CTASK_WORKSPACE + (CTASK_LAUNCH_DIR if set). WhenCTASK_LAUNCH_DIR != CTASK_TASK, the tag becomes|project:<launch_dir>(user-overridden launch directory).
- Both
- Docs updated (
82c9445)docs/commands.md: workspace-layout diagram,launch_dirsemantics (default, override, fallback vs error),CTASK_LAUNCH_DIRenv var, doctor example with new INFO line, Query Resolution default-discovery paragraph.
- Version bump
0.4.1→0.5.0(8130a68).
What v0.5.1 delivered
Two rounds shipped under the v0.5.1 tag: wall-clock date for user-facing surfaces (a162aec, a11d48b) and Linux portability baseline (7a7b249, 1033072).
Round 1 — date fix (a162aec, a11d48b)
- Bug: workspace directory names used UTC date, so at 20:22 EDT on April 22 a new workspace was named
2026-04-23_foo. Confusing in file explorer,ctask list, andctask info. - Fix:
internal/workspace/create.gonow usestime.Now()(local) for the directory-prefix date and theYYYYMMDD-HHMMSSID.cmd/info.goformatsCreated/Updated/Archivedwith.Local(). - Stored timestamps still UTC.
task.yamlCreatedAt/UpdatedAt/ArchivedAt, session logs, lease, manifest, and summary all continue to store UTC. Only user-facing surfaces (directory prefix + info display) switched. - Regression guards:
TestCreateDirectoryPrefixUsesLocalDateandTestInfoFormatsTimestampsInLocalZoneenforce both invariants.
Round 2 — Linux portability baseline (7a7b249, 1033072)
- Build targets (
justfile):build-linux,build-windows,build-alloutput todist/. Both cross-targets forceCGO_ENABLED=0so the artifact is pure-Go statically linked regardless of build host (a native Linux build otherwise defaults toCGO_ENABLED=1and links against host glibc). - POSIX install scripts (
scripts/install.sh,scripts/uninstall.sh): mirror the.ps1UX. Default install dir~/.local/bin, optional override arg, PATH check warns with the right shell snippet (zsh / bash / fallback) — the script does NOT modify shell config. Statusline helperctask-statusline.shships alongside the binary; the.ps1helper is intentionally not installed on Linux. Workspace data is preserved on uninstall. .gitignorenow coversctask,ctask-*,dist/(in addition to*.exe).WorkspacePathremoved fromTaskMeta. The audit (audit-report.md) confirmed the field was write-only with no production readers — it persisted an absolute Windows path intotask.yamlthat would have been misleading on cross-OS shares. Existingtask.yamlfiles withworkspace_pathcontinue to load (Go's YAML unmarshal silently ignores unknown fields).TestMetaTypeMissingDefaultsToTaskkeeps the legacy YAML literal in its fixture as a backward-compat regression guard.- Validation: Windows
go test ./...green across all 7 packages; cross-compile produces ELF x86-64. WSL-native validation passed:go test ./... -count=1green;just build-linuxproduces astatically linkedELF (lddreportsnot a dynamic executable);./scripts/install.shinstalls to~/.local/bin/ctaskand registers the statusline helper;ctask doctorrecognizes the Linux statusline helper.
What v0.5.2 delivered
Theme: workspace retrieval and cross-workspace context. Five feature commits (a5e508b..3b6be0d) plus a version bump (5910100).
-
Three new direct-lookup commands (
176e788):ctask restore <ws>— un-archive (metadata-only flip; mirrors archive's lease guard; refuses already-active workspaces)ctask notes <ws>— streamnotes.mdto stdout raw, no framing;[ctask]-prefixed stderr on missing file (SilenceErrors: trueso the spec format is the only diagnostic shown)ctask path <ws>— print absolute filesystem path on one line, OS-native separators
-
Direct-lookup commands are archived-inclusive by default (
b923ae8). The--all/-aflag was dropped frominfoentirely; theStatus:line in info output surfaces archived state.deleteandopenkeep their--allflags (they are potentially destructive).resumeandarchiveresolve archived-inclusive then filter, so they can give actionable error messages. -
ctask resume <archived-ws>prints a restore hint (b923ae8):[ctask] error: workspace "X" is archived To restore it: ctask restore XGenuine not-found and ambiguity behavior preserved.
-
ctask list --names(56d2e07) — machine-readable enumeration. One workspace directory basename per line, no header. Empty stdout on no match (no "No workspaces found." placeholder). Honors all existing list filters. Spec invariantTestListNamesCandidatesResolveUniquelyenforces that every emitted line resolves to exactly one workspace. -
Shell completion via Cobra (
176e788,b923ae8).ctask completion {bash,zsh,fish,powershell}works through Cobra's auto-injected subcommand.ValidArgsFunctionhooks per spec policy:resume,archive→ active onlyrestore→ archived onlyinfo,notes,path→ bothdelete,open→ active only (flag-aware completion deferred)
Candidates are workspace directory basenames (unique under the resolver's exact-match step), not bare slugs (which can collide across categories or dates).
-
Cross-workspace context section in seed CLAUDE.md (
3b6be0d). Both task and project templates teach agents to inspect related workspaces withlist --all/info/notes/pathbefore starting work, and to treat other workspaces as read-only. Applies to newly-created workspaces only — no retroactive overwrite of existing CLAUDE.md files. -
Version bump to
0.5.2(5910100).
Validation:
- Windows:
go test ./... -count=1green across all 7 packages;go vetclean;go buildclean. End-to-end smoke against the binary covered the full archive ↔ restore cycle plus completion-script generation. - WSL/Linux: refreshed validation copy; reinstalled via
install.sh; full smoke checklist passed (16 behaviors across new + active + archived + restore + completion). Cross-built Linux binary is statically linked (filereportsstatically linked;lddreportsnot a dynamic executable).
Known limitation (v0.5.2)
ctask resume <archived-ws>printsError: workspace archivedbelow the actionable hint. Cosmetic only — the user-visible hint is shown first and is correct. Suppressing the trailing line would requireSilenceErrors: trueonresume, which would also swallow unrelated session-launch errors. Acceptable trade; revisit only if the redundancy actively confuses users.
Next: v0.6 (planning)
Not yet specced. Likely scope:
- Config / agent profile work. The long-flagged direction towards
~/.config/ctask/configuration; may supersede the env-var resolution dance forCTASK_ROOT/CTASK_PROJECT_ROOT/CTASK_SEED_DIR/CTASK_AGENT. - Optional polish for resume error output. Silence the trailing Cobra "Error: workspace archived" line — likely via per-error-path
SilenceErrorsor a sentinel-error wrapper. - Flag-aware completion for
open/delete --all. Cobra supportsRegisterFlagCompletionFuncper flag; would let completion offer archived candidates only when--allis passed.
Post-v0.4 bugfixes (still live, carried forward)
Provisional-workspace cleanup (2026-04-22, commits 02dcdcc, ba8b3a1)
Covered in v0.4.1 notes. The exit-code gate (childExitCode != 0 && startManifest != nil && emptyDiff && NewlyCreated) is unchanged in v0.5.
Tree state at pause
mainclean with respect to v0.4, v0.4.1, v0.5, v0.5.1.- Installed
ctask.exeis v0.5.1 — no reinstall needed unless source changes. - Untracked files (do NOT touch without asking):
.claude/settings.local.json(modified — Claude Code local settings)bugfix-provisional-workspace.md(spec for the 2026-04-22 initial provisional fix; may be deleted or archived)docs/superpowers/plans/2026-04-06-install-workflow.md(install-workflow plan from an earlier session)docs/superpowers/plans/2026-04-21-v0.4-implementation.md(v0.4 plan — executed)docs/superpowers/plans/2026-04-22-v0.4.1-patch.md(v0.4.1 plan — executed)docs/superpowers/plans/2026-04-22-v0.5-implementation.md(v0.5 plan — executed)v0.4-spec.md,v0.4.1-patch-spec.md,v0.5-spec.md(specs the implementations followed)
How to resume
cd C:\Users\Warren\claude_tasks\ctask
just test # go test ./... -count=1
just build # or: go build -o ctask.exe .
just install # only reinstall if source changed
Quick sanity checks that v0.5.1 is live:
ctask --version # expect: ctask v0.5.1
ctask doctor # expect: 5 pass/fail + 2 seed-dir INFO + 1 CTASK_PROJECT_ROOT INFO
# Local-time directory prefix (v0.5.1):
ctask new --project "tz-check" --no-launch
# Expected output: [ctask] created projects/YYYY-MM-DD_tz-check — YYYY-MM-DD matches
# the user's local wall-clock date, not UTC.
ctask info tz-check # Created/Updated in local zone
ctask delete --force tz-check
# Project subdir + banner (v0.5):
ctask new --project "smoke" --no-launch
# A subdir named smoke/ exists inside the workspace.
ctask resume smoke # banner shows "[ctask] project dir: smoke/" and Claude
# launches with cwd inside smoke/. /exit to leave.
ctask delete --force smoke
# Default discovery (v0.5):
# Projects created without $CTASK_PROJECT_ROOT should now be findable from any shell.
ctask list --projects
Load-bearing design points (don't forget)
From v0.4 (unchanged)
- Coexisting-session limitation: "Continue anyway?" or
--force→ second session runs without its own lease. Documented indocs/commands.md. Don't redesign without a real user complaint. end_manifestin the summary is ctask-internal (not in spec example JSON) and powers Layer-3 stale-workspace diff. Removing it breaks Layer 3.- Write-lock skip classification (best-effort vs important-but-non-fatal): unchanged.
cmd/delete.gotwo-check invariant: unchanged.CTASK_WORKSPACEmatch → refuse;.ctask/manifest-start.jsonexists → refuse. Both before any mutation.session.Run()lifecycle ininternal/session/run.go:PreflightFull(Layers 3 + 1)- Write lock → write lease (unless coexisting)
- Write lock → capture + write start manifest
- Print launch-context banner (Layer 4)
- Start heartbeat (only if we own the lease)
- v0.5:
workspace.ResolveLaunch(opts.WsDir, opts.LaunchDir)— print warning or abort on security error - Banner lines (including
project dir:when LaunchDir set) + exec child with cwd = resolved launch path - Stop heartbeat
handleProvisional(gated onNewlyCreated && childExitCode != 0 && emptyDiff) — if it removes the workspace, skip finalize entirelyfinalize: single write-lock acquire → append log + write summary + remove lease (if owned) + remove manifest-start
newis intentionally not given--force. Brand-new workspaces have nothing for Layer 1/3 to warn about.internal/lockfileis a neutral package — no other ctask imports.
From v0.4.1 (unchanged, still load-bearing)
config.SearchRoots()is the canonical way to enumerate workspace roots. Always includes CTASK_ROOT. In v0.5 the semantics of the second entry expanded — see "From v0.5" below.QueryResult.Rootis how callers render relative paths and computeCTASK_ROOTenv var. Populated byscanAllRoots.scanWorkspacesis a two-depth scan, first-match-wins. Depth-1 (flat) check wins if present; never descends into a detected workspace.- Archive's non-TTY stdin refuses. Fresh lease + non-TTY = exit non-zero without mutating. Don't regress to "silent proceed".
- Doctor seed-dir checks are three-state. Only "configured but missing" counts as a failure.
- Provisional-cleanup exit-code gate.
childExitCode == 0means preserve. Don't special-case specific codes.
From v0.5 (new — don't unlearn)
launch_diris stored as workspace-relative intask.yaml, empty for tasks and pre-v0.5 projects. Never store absolute paths. Never interpretlaunch_diroutsideworkspace.ResolveLaunch.workspace.ResolveLaunchhas three outcomes: valid, soft fallback (with warning), security/permission error. Soft fallback is(wsDir, warning, nil)— caller warns and keeps launching. Error is("", "", err)— caller must abort. The asymmetry betweenos.IsNotExist(fallback) and other stat errors (propagate) is intentional; masking a permission error as a warning would silently strip launch-dir semantics.- Project subdir name = final suffixed slug.
dup-2collision means subdir isdup-2/, notdup/. TheactualSlugvariable inworkspace.Createis the single source of truth. - Subdir is created after seeds, empty, never seeded. Layer 1 (built-in defaults), Layer 2 (general seed), Layer 3 (project seed) all target the workspace root. The
if opts.IsProject { os.MkdirAll(projDir, 0755) }block runs AFTER seed overlays and BEFOREtask.yamlis written. - Session scope is workspace-wide even when launched in the subdir. Lease, manifest capture, write lock, summary, stale-workspace diff all operate on
opts.WsDir(the workspace root), not on the resolved launch path. Only the child process's cwd changes. CTASK_LAUNCH_DIRis always exported (empty string for tasks). Status line helpers and any future child-side integration can check-n "$CTASK_LAUNCH_DIR"safely.SearchRoots()now appends$CTASK_ROOT/projects/by default whenCTASK_PROJECT_ROOTis unset. This is redundant with the v0.4.1 two-depth scan under$CTASK_ROOTbut explicit per spec. Dedupe inscanAllRoots(searchRootKey— cleaned + lower-cased on Windows) prevents double-counting. Don't remove the default fallback without also reverting the spec-driven expectation that default projects are findable from any shell.- Doctor check for
CTASK_PROJECT_ROOTis advisory, not prescriptive. "Recommended: set at user scope so all terminals can discover these workspaces." Don't harden into a FAIL when the variable is set but the path exists.
From v0.5.1 (new — don't unlearn)
- Workspace directory prefix uses LOCAL time.
time.Now()inworkspace.Createfeeds theYYYY-MM-DDdate and theYYYYMMDD-HHMMSSID. Don't switch back to.UTC()for these. TheTestCreateDirectoryPrefixUsesLocalDateregression test enforces this. ctask infodisplays timestamps in local zone via.Local().Format(...). Stored timestamps intask.yamlare still UTC (meta.CreatedAt = nowLocal.UTC().Truncate(time.Second)) — only the display converts.- Stored timestamps everywhere else remain UTC. Session logs, lease
StartedAt/LastHeartbeatAt, manifest capture times, summary timestamps are all unambiguous UTC. Don't "localize" those — they're machine-readable. - Cross-builds force
CGO_ENABLED=0.just build-linuxandjust build-windowsset this explicitly so the artifact is pure-Go static. Don't drop the flag — a native Linux build defaults to cgo and produces a glibc-linked binary that won't run in Alpine / distroless / scratch containers. WorkspacePathis gone fromTaskMeta. Don't add it back. If a persistent workspace identifier is ever needed, add a properly relative-to-rootworkspace_id(forward-slash normalized). Oldtask.yamlfiles withworkspace_pathparse silently — the field is ignored on read.- POSIX install script does not modify shell config. It warns the user about PATH but never edits
~/.bashrc/~/.zshrc. Don't change this without an explicit user request.
From v0.5.2 (new — don't unlearn)
infono longer has--all/-a. Direct lookup is archived-inclusive by default. Don't add the flag back. TheStatus:line in info output makes archived state obvious.TestInfoFindsArchivedWorkspaceWithoutFlagenforces this.resume/archiveresolve archived-inclusive then filter. Don't switch back toincludeArchived=falseat the resolver layer. The two-step pattern (resolve broadly, reject explicitly) is what letsresumegive the actionable restore hint instead of a generic "not found".- Direct-lookup commands (
info,notes,path,restore) useincludeArchived=true. Active-only commands (resume,archive) reject archived after resolve. Potentially-destructive commands (delete,open) keep their explicit--allopt-in. Don't drift back to a uniform default — the policy is intentional. Seev0.5.2-spec.md"Workspace Lookup Policy". list --namesemits directory basenames, not bare slugs. Bare slugs can collide (e.g.,promptvolleyarchived in v1, active in v2). Basenames are unique under the resolver's exact-match step.TestListNamesCandidatesResolveUniquelyenforces the invariant.ValidArgsFunctionhooks callworkspace.ListWorkspacesdirectly. No subprocess shell-out toctask list --names. Don't add one — direct calls are faster and don't depend on PATH state.- Cobra adds the
completionsubcommand lazily on firstExecute(). A test that callsrootCmd.Find("completion")before anyExecute()returns "unknown command". For unit tests, prefer therootCmd.GenXxxCompletion(...)generators directly. For end-to-end, oneSetArgs(...)+Execute()per test — running multipleExecute()calls in succession with different shell args has state issues. notesusesSilenceErrors: trueso the[ctask] no notes.md found in workspace "X"stderr line is the only diagnostic the user/agent sees. Don't setSilenceErrors: falseand add a[ctask]prefix to the returned error message — Cobra would then print both, doubling the message.
Open follow-ups (NOT in v0.4/v0.4.1/v0.5, deferred)
Potentially worth doing
- Pre-v0.5 project workspaces have no
launch_dir. They launch from the workspace root, not from any project subdir. No migration path today. Acceptable — users can manually add alaunch_dirto theirtask.yamlif they want the new behavior. Revisit only if someone complains. - Drop unused
slug/category/workspacePathparameters fromseed.ClaudeMD(v0.3 follow-up, still open). - Status-line: color the
|project/|project:<dir>marker if Claude Code'sstatusLineever supports ANSI.
Concurrency-related (from v0.4)
- Coexisting-session detection (more than one live lease per workspace).
- Cross-machine PID liveness check.
--forcesymmetry on other commands — no use case yet.- A
ctask sessionssubcommand to inspect lease/summary.
Repo hygiene
- Several untracked working docs (
v0.4-spec.md,v0.4.1-patch-spec.md,v0.5-spec.md,bugfix-provisional-workspace.md, the plan files) could be committed alongsidev0.2-spec.md/v0.3-spec.mdfor durability. Currently session-local. .claude/settings.local.jsonhas uncommitted changes of unknown scope. Leave alone unless asked.
Resolved (don't re-add to this list)
CTASK_PROJECT_ROOT env-var scoping UX footgun→ resolved in v0.5 via the default$CTASK_ROOT/projects/fallback inSearchRoots().UTC date in directory names / info display→ resolved in v0.5.1.
Files to read first when resuming
For the v0.5 surface:
v0.5-spec.md— the spec v0.5 followeddocs/superpowers/plans/2026-04-22-v0.5-implementation.md— the executed plan (includes scanner-safety regression tests, dedupe tests, amendment history)internal/workspace/launchdir.go—ResolveLaunchwith the three-outcome contractinternal/workspace/create.go— subdir scaffold + local-time date +launch_dirdefaultinternal/session/run.go—LaunchOpts.LaunchDir,ResolveLaunchcall site, banner extensioncmd/info.go— local-time display + launch fieldscmd/doctor.go—checkProjectRoothelperscripts/ctask-statusline.{sh,ps1}— effective-path display logicinternal/seed/templates.go—ClaudeMDProjectwith Workspace Structure section
For the v0.4.1 surface (still load-bearing):
internal/config/config.go—SearchRoots(),samePath,searchRootKeydedup; default$CTASK_ROOT/projects/fallbackinternal/workspace/query.go— two-depthscanWorkspaces,scanAllRoots,QueryResult.Rootcmd/archive.go— active-session check + non-TTY refusal +isStdinTerminal
For the v0.4 surface:
internal/session/run_preflight.go— Layer 3 + Layer 1 preflightinternal/session/lease.go— Lease + freshness + cleanupinternal/session/summary.go— SessionSummary + launch-context bannerinternal/lockfile/writelock.go— write-lock primitiveinternal/session/run_provisional.go—handleProvisionalwithchildExitCodegatedocs/commands.md— user-facing surface
Don't re-do
- Do not invent remote install /
go installcommands (perCLAUDE.md, this project is local-only) - Do not touch
cmd/delete.go's two-check protection - Do not weaken the v0.3
.gitignoreseed-wins rule - Do not redesign the lease model around multiple concurrent leases without a real user-reported problem
- Do not re-run the v0.4 smoke tests in a fresh session unless source has changed
- Do not expand the provisional-cleanup gate beyond "strictly empty manifest diff AND non-zero child exit". No size thresholds, no heuristics, no exit-code-specific mappings.
- Do not extend provisional cleanup to
resume/open/last.NewlyCreatedis set only bycmd/new.go. - Do not drop
QueryResult.Rootor collapseSearchRoots()back to a single string. - Do not change archive's non-TTY behavior back to "proceed silently".
- Do not add a workspace registry file. The default
$CTASK_ROOT/projects/fallback solved the discovery footgun. - v0.5: Do not change
launch_dirstorage to absolute paths. Workspace-relative is load-bearing. - v0.5: Do not mask non-
os.IsNotExiststat errors inResolveLaunchas warning fallbacks. The asymmetry between soft-fallback (missing / not-a-dir) and hard-error (permission / ENOTDIR / invalid name) is deliberate. - v0.5: Do not seed anything inside the project subdirectory. Seeds target the workspace root only.
- v0.5: Do not let the session launch change scope (lease, manifest, summary, write-lock) away from the workspace root. Only the child's cwd is the launch dir.
- v0.5: Do not remove the default
$CTASK_ROOT/projects/fallback inSearchRoots()— it resolves the v0.4.1 env-var scoping footgun. - v0.5.1: Do not switch the directory prefix / ID back to UTC. The
TestCreateDirectoryPrefixUsesLocalDatetest enforces local time. - v0.5.1: Do not remove
.Local()from thectask infoCreated/Updated/Archived formatting.TestInfoFormatsTimestampsInLocalZoneenforces local display. - v0.5.1: Do not change stored timestamps (task.yaml, session logs, lease, manifest, summary) to local time. UTC storage is deliberate — only display converts.