# Shell Linting Implementation Plan

> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.

**Goal:** Add one repository-wide shell lint target and reuse it locally and in CI.

**Architecture:** Keep the lint rule simple: discover repository-owned executable shell files, run `shellcheck` against each one, and fail fast with the file name that triggered the error. Makefile stays the single local entry point, and GitHub Actions calls the same target so local and remote behavior stay aligned.

**Tech Stack:** Bash, Makefile, `shellcheck`, GitHub Actions.

---

### Task 1: Add the local shell lint target

**Files:**
- Modify: `Makefile`

- [ ] **Step 1: Add a `lint-shell` target and expose it in `help`**

```make
.PHONY: help check check-bootstrap check-fish check-deps-script check-deps-manifest test-install docker-check docker-deps-check docker-deps-update-lock deps-list deps-check deps-plan deps-update-lock doctor deps install bootstrap lint-shell

help:
	@echo "  lint-shell    Run shellcheck across repository-owned shell scripts"
```

- [ ] **Step 2: Implement shell file discovery and shellcheck execution**

```make
lint-shell:
	@set -euo pipefail; \
	if ! command -v shellcheck >/dev/null 2>&1; then \
		echo "error: shellcheck is required for lint-shell" >&2; \
		exit 1; \
	fi; \
	files="$$(find . \
		-path './.git' -prune -o \
		-path './__pycache__' -prune -o \
		-type f -perm -111 \
		\( -name bootstrap -o -path './scripts/*' \) \
		-print | sort)"; \
	if [ -z "$$files" ]; then \
		exit 0; \
	fi; \
	for file in $$files; do \
		shellcheck "$$file"; \
	done
```

- [ ] **Step 3: Keep the target narrow and deterministic**

The target should lint only repository-owned executable shell files. It should not try to lint generated files, `__pycache__`, `.git`, or non-shell files such as `scripts/update-lock.py`.

### Task 2: Wire shell linting into CI

**Files:**
- Modify: `.github/workflows/ci.yml`

- [ ] **Step 1: Add a dedicated shell lint job on Ubuntu**

```yaml
  lint-shell:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout
        uses: actions/checkout@v4

      - name: Install shellcheck
        run: sudo apt-get update && sudo apt-get install -y shellcheck

      - name: Run shell lint
        run: make lint-shell
```

- [ ] **Step 2: Keep the existing jobs unchanged**

The existing `check` matrix and `docker-smoke` job should stay as they are so shell linting is an additive CI check, not a replacement for the current validation coverage.

### Task 3: Update the roadmap to reflect v0.6 progress

**Files:**
- Modify: `docs/roadmap.md`

- [ ] **Step 1: Mark shell linting as part of v0.6**

Add `make lint-shell` and the GitHub Actions shell lint job under v0.6 `Done`.

- [ ] **Step 2: Keep the remaining v0.6 items visible**

Leave `shfmt` as the remaining CI-related work if it is not already covered by the new workflow.

### Task 4: Verify the new lint target and workflow syntax

**Files:**
- None

- [ ] **Step 1: Run the local validation targets**

```bash
make check
python3 -m unittest discover -s tests -p 'test_*.py'
```

- [ ] **Step 2: Run the new shell lint target**

```bash
make lint-shell
```

- [ ] **Step 3: Validate the workflow file syntax**

```bash
ruby -e "require 'yaml'; YAML.load_file('.github/workflows/ci.yml'); puts 'workflow ok'"
```
