Update notes.md with the v0.5.1 Linux portability baseline (commits7a7b249,1033072): WSL-native validation passed, install.sh works, ctask doctor recognizes the Linux statusline helper, the cross-built Linux binary is statically linked, and WorkspacePath was removed from new task.yaml metadata. Add load-bearing notes for the new invariants (CGO_ENABLED=0, install script does not modify shell config) and a "Next: v0.5.2" pointer. Also check in v0.5.2-spec.md so the workspace-retrieval round has the same on-disk durability as the prior specs.
17 KiB
ctask v0.5.2 Spec — Workspace Retrieval and Cross-Workspace Context
Theme
v0.1 = create and resume workspaces v0.2 = understand and continue workspaces later v0.3 = personalize workspaces and support longer-lived project work v0.4 = protect workspaces from concurrent session conflicts v0.5 = separate workspace management from project code v0.5.1 = ctask runs correctly on Linux (WSL and Docker) v0.5.2 = workspaces are discoverable, retrievable, and inspectable across sessions
Problem
Four usability gaps discovered through real usage:
-
Archived workspaces are a dead end.
ctask archivesets metadata and hides the workspace from default listing, but there is noctask restoreto bring it back. Users who archive prematurely must recreate the workspace and manually copy notes.md. -
Archived workspaces are invisible to direct lookup.
ctask info <workspace>does not find archived workspaces unless the user passes-a. Archived workspaces are still workspaces — users expect to look them up by name. -
No cross-workspace context access. When an AI agent works in one workspace, it has no way to read the notes or location of another workspace. Prior work is invisible unless the user manually copies content. ctask should expose workspace context through CLI commands that agents can call.
-
No shell autocompletion. Workspace names can be long and detailed. Users must type them in full or rely on shell history. Since ctask knows what workspaces exist and uses Cobra, autocompletion should be available.
Design Principles
Two rules govern this spec:
Listing is filtered. Direct lookup is comprehensive. ctask list shows active workspaces by default to keep output clean. Commands that accept a workspace name — info, notes, path, restore — search active and archived workspaces because the user asked for a specific workspace by name.
ctask exposes workspace context through CLI commands. Agents consume it themselves. ctask does not inject context into agent sessions, manage agent memory, or maintain a central knowledge base. It provides commands that print useful text to stdout. Agents (Claude Code or otherwise) can call these commands and read the output. This keeps ctask agent-agnostic and in its lane as a workspace manager.
Scope
ctask restore <workspace>— un-archive a workspacectask notes <workspace>— print another workspace's notes.mdctask path <workspace>— print the absolute path of a workspace- Archived-inclusive direct lookup for
info(and other direct-lookup commands) ctask list --names— machine-readable workspace enumerationctask completion <shell>— shell autocompletion- Updated CLAUDE.md seed text for cross-workspace awareness
Workspace Lookup Policy
The resolver (resolveOne → ResolveQuery) already supports an includeArchived boolean. This spec standardizes how each command sets it.
Active-only lookup
These commands operate on active workspaces. Looking up an archived workspace would be an error.
ctask resume <workspace> active only (archived → error with restore hint)
ctask archive <workspace> active only
Archived-inclusive lookup
These commands read or inspect workspaces. The user asked for a specific workspace by name — don't pretend it doesn't exist because it's archived.
ctask info <workspace> active + archived
ctask notes <workspace> active + archived
ctask path <workspace> active + archived
ctask restore <workspace> active + archived (then require status == archived)
Active-only by default, with --all opt-in
These commands are destructive or start sessions. Defaulting to active-only is safer; --all allows explicit archived access.
ctask delete <workspace> active only by default; archived allowed with --all/-a
ctask open <workspace> active only by default; archived allowed with --all/-a
Implementation
For commands currently hardcoding includeArchived=false (archive at cmd/archive.go:29, resume at cmd/resume.go:50): no change needed, these are correct.
For info (cmd/info.go:23): remove the --all/-a flag and always resolve with includeArchived=true. The flag is not needed — info is a read-only lookup and should always find the workspace the user asked for.
For delete and open: keep their existing --all/-a flags with current defaults (active-only). No change needed.
Resume behavior for archived workspaces
When a user runs ctask resume <archived-workspace>, the command should fail with a helpful message:
[ctask] error: workspace "promptvolley-v2" is archived
To restore it:
ctask restore promptvolley-v2
This keeps archive and restore as intentional lifecycle actions, not something that happens silently through resume.
Implementation note: resume currently resolves with includeArchived=false, so it won't find archived workspaces at all — it just reports "not found." To provide the restore hint, change resume to resolve with includeArchived=true, then check the result's status. If the workspace is active, proceed normally. If archived, print the hint and exit. This way the user gets a specific, actionable message instead of a generic "not found" error.
1. ctask restore <workspace>
Behavior
ctask restore promptvolley-v2
Resolves the workspace using archived-inclusive lookup, then:
- Verify the workspace status is
archived. If it's already active, print an error:workspace "promptvolley-v2" is already active - Check for an active session lease (mirror the guard in
ctask archive). If a lease is held, refuse with an appropriate message - Set
status: activein task.yaml. Write the value explicitly — do not omit the field or set it to empty string, even if older code treats empty status as active - Clear
archived_at(set to zero value / omit from YAML) - Update
updated_atto current time - Write task.yaml
- Print confirmation:
[ctask] restored: projects/2026-04-24_promptvolley-v2
[ctask] status: active
Rules
- Restore is metadata-only. No directory moves, no file changes beyond task.yaml
- Restoring does not start a session. The user runs
ctask resumeafterward if they want to work in it - If a workspace with the same slug exists in active status (edge case: user archived one, created a new one with the same name), the resolver will find both. The resolver's existing ambiguity handling applies — it should report the conflict and ask the user to use the full name
What restore does NOT do
- Does not launch an agent
- Does not regenerate CLAUDE.md or any seed files
- Does not modify notes.md, context/, or any workspace content
- Does not create a session log entry (no session is started)
2. ctask notes <workspace>
Behavior
ctask notes promptvolley-v2
Resolves the workspace using archived-inclusive lookup, then prints the contents of notes.md to stdout.
# Equivalent to:
cat "$(ctask path promptvolley-v2)/notes.md"
Rules
- Output is the raw contents of notes.md, no framing or decoration. This makes it directly consumable by agents reading stdout
- If notes.md does not exist in the workspace, print a clear message to stderr and exit with a non-zero code:
[ctask] no notes.md found in workspace "promptvolley-v2" - If the workspace is not found, the resolver's existing error handling applies
- Works on both active and archived workspaces
Why stdout matters
The primary consumer of this command is an AI coding agent running ctask notes <workspace> via shell. The agent reads stdout to get context from prior work. Keeping the output clean (no banners, no status lines) means the agent gets exactly the document content with no parsing needed. Informational messages go to stderr.
3. ctask path <workspace>
Behavior
ctask path promptvolley-v2
Resolves the workspace using archived-inclusive lookup, then prints the absolute filesystem path to stdout.
C:\Users\Warren\ai-workspaces\projects\2026-04-24_promptvolley-v2
or on Linux:
/home/warren/ai-workspaces/projects/2026-04-24_promptvolley-v2
Rules
- Output is a single line: the absolute, OS-native filesystem path. No trailing newline decoration, no framing
- The path uses native separators (backslashes on Windows, forward slashes on Linux). This is the real filesystem path, not a display identifier
- Works on both active and archived workspaces
- This is
QueryResult.Path— already available from the resolver, no new logic needed
Use case
An agent that needs to inspect files in another workspace can run ctask path <workspace> and then read files at that location. Combined with ctask notes, this gives agents full read access to prior workspace context through standard shell commands.
4. ctask info — Archived-Inclusive by Default
Current behavior
ctask info <workspace> requires --all or -a to find archived workspaces. Without the flag, an archived workspace is reported as not found.
New behavior
ctask info <workspace> finds the workspace whether it is active or archived. If the workspace is archived, the info output should include the status clearly:
Task: promptvolley-v2
Title: promptvolley-v2
Category: projects
Status: archived
...
Archived: 2026-05-01 14:30:00
Implementation
Change cmd/info.go so that the resolver call uses includeArchived=true unconditionally. Remove the --all/-a flag from info — it is no longer needed since info always searches comprehensively.
Why this is correct
The user typed a specific workspace name. They know it exists. Telling them "not found" because it happens to be archived is unhelpful and forces them to guess at the flag. The principle: listing is filtered, direct lookup is comprehensive.
5. ctask list --names
Behavior
ctask list --names
Outputs one workspace directory basename per line, no headers, no table formatting:
2026-04-24_promptvolley-v2
2026-04-22_litlink-v2
2026-05-07_linux-test
ctask list --names --all
Includes archived workspaces in the output.
Rules
- One directory basename per line (e.g.,
2026-04-24_promptvolley-v2, not the bare slugpromptvolley-v2). Basenames are unambiguous — bare slugs can collide across categories or dates - What
list --namesoutputs, other commands accept as input. The resolver already accepts exact directory basenames - Respects existing filters:
--all,--archived,--projects, or whatever category/status filterslistcurrently supports - No additional decoration: no dates, no status, no categories. This is for machine consumption
- If no workspaces match, output nothing (empty stdout, zero exit code)
Why this exists
Shell completion scripts and external tooling need a stable, parseable enumeration of workspace names. While Cobra's ValidArgsFunction can enumerate internally, list --names serves agents, shell scripts, and any future integration that needs to discover workspaces without importing ctask's Go code.
6. ctask completion <shell>
Behavior
ctask completion powershell
ctask completion bash
ctask completion zsh
ctask completion fish
Outputs the completion script for the specified shell. The user sources it in their shell profile.
Implementation
Cobra provides built-in completion generation. The implementation is:
- Enable Cobra's completion command (or add a thin wrapper if customization is needed)
- Add
ValidArgsFunctionhooks to every command that accepts a workspace name argument
ValidArgsFunction hooks
Each command gets a completion function that enumerates workspace candidates appropriate to that command's lookup policy:
resume: active workspaces only
archive: active workspaces only
restore: archived workspaces only
info: active + archived
notes: active + archived
path: active + archived
delete: active workspaces only (flag-aware completion for --all can come later)
open: active workspaces only (flag-aware completion for --all can come later)
The completion function calls the workspace listing logic internally (no shell-out to ctask list). A shared helper should enumerate slugs with a configurable status filter to avoid duplicating logic across commands.
PowerShell completion
PowerShell is the primary shell on Windows. The user adds the output of ctask completion powershell to their $PROFILE. Tab-cycling through candidates works natively with PowerShell's completion system.
Bash/Zsh completion
For WSL and Linux environments. The user sources the script in .bashrc or .zshrc. This also benefits the workflow where the developer SSHs into a container and uses ctask there.
Rules
- Completion scripts are generated, not maintained by hand. Cobra handles the shell-specific syntax
- The
completioncommand itself does not require workspace resolution — it is a utility command - Fish completion is included for free via Cobra. No extra work, but no need to test extensively unless a real user needs it
7. CLAUDE.md Seed Text Update
Current state
ctask seeds a CLAUDE.md into each workspace with workspace management instructions. This text does not mention cross-workspace context access.
Addition
Add the following section to the built-in CLAUDE.md template used during workspace creation:
## Cross-Workspace Context
Related work may exist in other ctask workspaces. For project continuation,
migration, debugging, or building on prior work, inspect related workspaces
before making changes.
Available commands:
ctask list --all discover all workspaces (including archived)
ctask info <workspace> view metadata and status of any workspace
ctask notes <workspace> read another workspace's notes.md
ctask path <workspace> get the filesystem path to inspect files directly
Treat other workspaces as read-only unless the user explicitly asks you to
modify them.
Rules
- This text is added to the seed template, not retroactively injected into existing workspaces
- Users who have customized their seed directory will not see this text unless they add it themselves. This is expected — seeds are user-controlled
- The text is concise. CLAUDE.md is loaded into the agent's context window at session start; long instructions waste context budget
- The text is agent-agnostic. It references CLI commands, not Claude-specific features. If AGENTS.md is in use (v0.6), this section belongs there instead, with the CLAUDE.md shim pointing to it
Backward Compatibility
- Existing workspaces are unaffected. No metadata changes, no layout changes
ctask infobecomes more permissive (finds archived workspaces), which is strictly a UX improvement — no existing workflow breaksctask listdefault behavior is unchanged (active only).--namesis additive- Existing CLAUDE.md files in workspaces are not modified. The new seed text only applies to newly created workspaces
Non-Goals for v0.5.2
ctask find <query>— full-text search across workspaces. Defer until list + notes proves insufficient- Claude-specific slash commands or skills files. Defer until the manual workflow proves itself
list --json— defer unless a real consumer needs structured output.--namescovers the completion and scripting use case- Fuzzy or partial-match workspace resolution. The current resolver accepts exact slug, exact basename, and case-insensitive substring. That's sufficient
- Modifying other workspaces via ctask commands. Cross-workspace access is read-only by design
Build Order
- Settle the lookup policy: update
infoto useincludeArchived=trueby default. Verify no tests assume the old default - Implement
ctask restorewith archived-inclusive lookup and active-lease guard - Implement
ctask noteswith archived-inclusive lookup and clean stdout output - Implement
ctask pathwith archived-inclusive lookup - Update
ctask resumeto print a helpful restore hint when targeting an archived workspace - Add
ctask list --nameswith filter support - Add
ctask completioncommand andValidArgsFunctionhooks for all workspace-accepting commands - Update CLAUDE.md seed template with cross-workspace context section
- Tests:
- restore: archived workspace restored to active with explicit
status: active, already-active workspace refused, lease guard respected, metadata updated correctly - notes: prints notes.md content, handles missing notes.md, works on archived workspace
- path: prints absolute path, correct separators per OS, works on archived workspace
- info: finds archived workspace without
-aflag, flag removed - resume: archived workspace refused with restore hint (not generic "not found")
- list --names: outputs directory basenames one per line, respects --all filter, empty output on no matches, no slug collisions
- completion: generates valid shell scripts (smoke test — no need to test shell integration)
- restore: archived workspace restored to active with explicit
- Full test suite pass on both Windows and Linux