# 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: 1. Linux build targets and binary artifacts 2. POSIX install and uninstall scripts 3. Remove dead `WorkspacePath` metadata 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-linux` produces a single `ctask` binary for linux/amd64 - `build-all` produces both Windows and Linux binaries with distinguishable names - No cgo. Pure Go build. If any dependency introduces cgo, set `CGO_ENABLED=0` explicitly - 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/bin` exists; create it if not - Copy the binary and set executable permission - Install `scripts/ctask-statusline.sh` to the same location as the binary (so `ctask doctor` can find it). Mark it executable. Do not install the PowerShell statusline helper on Linux - Check whether `~/.local/bin` is 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.sh` helper from the same directory - Do not remove `CTASK_ROOT` or 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 `COPY` or `RUN curl` in 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 `WorkspacePath` from the `TaskMeta` struct in `internal/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_path` should 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_id` with 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_path` in 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_ROOT` resolves 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 doctor` reports 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_path` continue 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 1. Add Linux build targets to justfile (with `dist/` output) and update .gitignore 2. Add `scripts/install.sh` and `scripts/uninstall.sh` (including statusline helper install) 3. Remove `WorkspacePath` from `TaskMeta`, `create.go`, and test fixtures 4. Run test suite on Windows (confirm nothing broke) 5. Cross-compile Linux binary 6. Run test suite on Linux/WSL 7. Install via `install.sh` on Linux/WSL, verify `ctask doctor` passes (including statusline helper check) 8. Execute smoke test checklist on Linux/WSL