- justfile: add build-linux, build-windows, build-all (output to dist/) - .gitignore: cover ctask, ctask-*, dist/ - scripts/install.sh + scripts/uninstall.sh: POSIX equivalents of .ps1 - remove WorkspacePath metadata field (no production readers; legacy task.yaml files continue to parse silently) Linux smoke-test on WSL/container pending. See audit-report.md and v0.5.1-spec.md.
8.1 KiB
ctask v0.5.1 Spec — Linux Portability Baseline
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)
Problem
ctask was developed on Windows and has only been built and tested there. The developer now works across Windows, WSL, and Docker containers, and needs ctask available in all three environments. A portability audit (see audit-report.md) confirmed that the Go code is already portable — path handling uses filepath.* consistently, config defaults are OS-aware, and shell launching branches by runtime.GOOS. There are no blocking issues.
What's missing is the distribution surface: build targets, install scripts, and binary artifact coverage. There is also one piece of dead metadata (WorkspacePath) that persists absolute Windows paths into task.yaml, creating misleading data that would confuse cross-OS workspace inspection.
This spec covers the minimal work to produce a working, installable Linux binary and clean up the one metadata issue before the next feature round builds on top of it.
Scope
Three deliverables:
- Linux build targets and binary artifacts
- POSIX install and uninstall scripts
- Remove dead
WorkspacePathmetadata
Plus a manual validation step: smoke test on WSL or a Linux container.
1. Linux Build Targets
Current state
justfile has Windows-only build targets. .gitignore covers ctask.exe but not the extension-less Linux binary.
Reference: audit-report.md Section 8 — justfile lines 11, 18, 23; .gitignore lines 1–2.
Changes
Add build targets to justfile, outputting to a dist/ directory to keep the project root clean:
build-linux:
mkdir -p dist
GOOS=linux GOARCH=amd64 go build -o dist/ctask-linux-amd64 ./
build-windows:
mkdir -p dist
GOOS=windows GOARCH=amd64 go build -o dist/ctask-windows-amd64.exe ./
build-all: build-windows build-linux
Update .gitignore:
ctask
ctask.exe
ctask-*
dist/
Rules
build-linuxproduces a singlectaskbinary for linux/amd64build-allproduces both Windows and Linux binaries with distinguishable names- No cgo. Pure Go build. If any dependency introduces cgo, set
CGO_ENABLED=0explicitly - No ARM64 Linux target yet. Add when a real need exists (e.g., ARM-based containers or CI runners)
- No macOS target. Deferred per roadmap (post-v1.0)
- No GitHub Actions release pipeline yet. That belongs in a later round when ctask is ready for distribution beyond personal use
2. Install and Uninstall Scripts
Current state
scripts/install.ps1 and scripts/uninstall.ps1 exist for Windows. No equivalent for Linux.
New files
scripts/install.sh
Behavior:
- Default install location:
~/.local/bin/ctask - Check that
~/.local/binexists; create it if not - Copy the binary and set executable permission
- Install
scripts/ctask-statusline.shto the same location as the binary (soctask doctorcan find it). Mark it executable. Do not install the PowerShell statusline helper on Linux - Check whether
~/.local/binis in$PATH; if not, print a warning with the appropriate shell config line to add (detect bash vs zsh by checking$SHELL) - Accept an optional argument to override install location:
./install.sh /usr/local/bin - If a ctask binary already exists at the target, overwrite it (upgrade path)
scripts/uninstall.sh
Behavior:
- Default location:
~/.local/bin/ctask - Accept optional argument to override
- Remove the binary and the
ctask-statusline.shhelper from the same directory - Do not remove
CTASK_ROOTor any workspace data — print a note that workspaces are preserved
Rules
- Scripts should be POSIX sh, not bash-specific, for maximum container compatibility
- Scripts mirror the install/uninstall pattern of the existing PowerShell scripts — keep the UX parallel
- No package manager integration (apt, brew, etc.). Not in scope
- For Docker containers, the expected install pattern is a
COPYorRUN curlin the Dockerfile, not running install.sh. The script is primarily for WSL and interactive Linux environments
3. Remove WorkspacePath Metadata
Current state
internal/workspace/create.go:138 sets meta.WorkspacePath = wsDir, persisting the absolute filesystem path (e.g., C:\Users\Warren\ai-workspaces\general\2026-04-24_foo) into task.yaml as workspace_path.
The audit confirmed this field is never read by production code. It appears only in test struct initializers. The runtime workspace path is always derived fresh from the filesystem walk via QueryResult.Path.
Reference: audit-report.md Section 1 — internal/workspace/create.go:138, internal/workspace/metadata.go:29.
Changes
- Remove
WorkspacePathfrom theTaskMetastruct ininternal/workspace/metadata.go - Remove the assignment in
internal/workspace/create.go:138 - Update all test fixtures and struct initializers that reference the field
- Existing task.yaml files that contain
workspace_pathshould be left alone — Go's YAML unmarshaling will silently ignore unknown fields. No migration needed - Do not add a replacement field. If a persistent workspace identifier is needed later, add a proper
workspace_idwith correct semantics (relative path, forward-slash normalized) at that time
Rules
- This is a removal, not a replacement. The field is dead code with misleading output
- Newly created workspaces will no longer have
workspace_pathin their task.yaml - Old workspaces with the field continue to work — the field is simply ignored on read
- No schema migration command needed
4. Validation
After implementing the above, perform a manual smoke test on WSL or a Linux container.
Smoke test checklist
Run these commands on Linux and verify correct behavior:
ctask new "linux-test"
ctask list
ctask info linux-test
ctask resume linux-test (agent launch — verify shell and env vars)
ctask archive linux-test
ctask list (should not show archived workspace)
ctask list --all (should show archived workspace, if flag exists)
ctask info linux-test -a (should show archived workspace info)
ctask delete linux-test (clean up)
ctask doctor (verify all checks pass on Linux)
Verify:
- Default
CTASK_ROOTresolves to$HOME/ai-workspaces - Workspace directories are created with correct structure
- task.yaml does not contain
workspace_path - Session logs, notes.md, CLAUDE.md are created with LF line endings
- Agent launch works (or fails gracefully if the agent binary isn't installed in the Linux environment)
ctask doctorreports correct OS, root path, and PATH status
Test suite
Run go test ./... on Linux. The audit states the test suite should pass without modification after the WorkspacePath removal and fixture updates. Confirm this.
Backward Compatibility
- Existing Windows workspaces are unaffected
- Old task.yaml files with
workspace_pathcontinue to load correctly (field ignored) - No changes to any existing command behavior
- No changes to workspace layout, session logging, or agent launching
Non-Goals for v0.5.1
- Shell completion (v0.5.2 or later)
- New commands (restore, notes, path — covered in the next spec)
- GitHub Actions or release automation
- Package manager integration
- macOS or ARM64 targets
- Config file changes (v0.6 scope per roadmap)
Build Order
- Add Linux build targets to justfile (with
dist/output) and update .gitignore - Add
scripts/install.shandscripts/uninstall.sh(including statusline helper install) - Remove
WorkspacePathfromTaskMeta,create.go, and test fixtures - Run test suite on Windows (confirm nothing broke)
- Cross-compile Linux binary
- Run test suite on Linux/WSL
- Install via
install.shon Linux/WSL, verifyctask doctorpasses (including statusline helper check) - Execute smoke test checklist on Linux/WSL