Initial project setup for small-scripts
Spec-driven utility script collection with dryrun support and automated testing. Includes project docs, test runner, and directory structure. Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
local_secrets/
|
||||||
|
*.swp
|
||||||
|
*.swo
|
||||||
|
*~
|
||||||
74
CLAUDE.md
Normal file
74
CLAUDE.md
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
# CLAUDE.md — small-scripts
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
A collection of small, standalone utility scripts designed to be symlinked into `~/sbin`. Development follows an **agent-driven, spec-first workflow** using OpenSpec — this project is the initial testbed for that approach.
|
||||||
|
|
||||||
|
## Key Principles
|
||||||
|
|
||||||
|
1. **Spec-first development.** Every script starts with an OpenSpec in `specs/`. No implementation without a spec.
|
||||||
|
2. **Dryrun by default.** Every script MUST support a `--dryrun` (or `-n`) flag that previews all actions without making changes. Dryrun output should clearly show what *would* happen.
|
||||||
|
3. **Test via dryrun.** Each script has a corresponding test script in `tests/` that exercises the main script's `--dryrun` mode to verify behaviour matches the spec.
|
||||||
|
4. **Symlink deployment.** Scripts are linked to `~/sbin` for PATH availability — the repo is the source of truth, not the installed copy.
|
||||||
|
|
||||||
|
## Repository Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
small-scripts/
|
||||||
|
├── CLAUDE.md # This file — project conventions
|
||||||
|
├── MEMORY.md # Thin index linking to memory/ topic files
|
||||||
|
├── FUTURE.md # Backlog of ideas
|
||||||
|
├── README.md # Human-readable docs
|
||||||
|
├── specs/ # OpenSpec files (one per script)
|
||||||
|
│ └── <script-name>.spec.md
|
||||||
|
├── scripts/ # The actual scripts
|
||||||
|
│ └── <script-name>
|
||||||
|
├── tests/ # Test scripts (one per main script)
|
||||||
|
│ └── test-<script-name>.sh
|
||||||
|
└── memory/ # Tiered memory topic files
|
||||||
|
└── log/ # Session logs
|
||||||
|
```
|
||||||
|
|
||||||
|
## Workflow
|
||||||
|
|
||||||
|
### Adding a new script
|
||||||
|
|
||||||
|
1. **Write the spec** — Create `specs/<script-name>.spec.md` using OpenSpec format
|
||||||
|
2. **Implement the script** — Create `scripts/<script-name>`, ensuring `--dryrun` support
|
||||||
|
3. **Write the test** — Create `tests/test-<script-name>.sh` that validates dryrun output against spec expectations
|
||||||
|
4. **Verify** — Run the test, confirm pass
|
||||||
|
5. **Symlink** — `ln -sf "$(pwd)/scripts/<script-name>" ~/sbin/<script-name>`
|
||||||
|
|
||||||
|
### Script conventions
|
||||||
|
|
||||||
|
- Scripts should be idempotent and safe to re-run
|
||||||
|
- Exit non-zero on failure
|
||||||
|
- Use colour output for status messages where appropriate
|
||||||
|
- Include a `--help` flag with usage information
|
||||||
|
- Shebang line should specify the interpreter explicitly (e.g., `#!/usr/bin/env bash`, `#!/usr/bin/env python3`)
|
||||||
|
- `--dryrun` / `-n` must be supported — it previews actions without side effects
|
||||||
|
|
||||||
|
### Test conventions
|
||||||
|
|
||||||
|
- Test scripts live in `tests/` and are named `test-<script-name>.sh`
|
||||||
|
- Tests invoke the main script with `--dryrun` and assert on output/exit codes
|
||||||
|
- Tests should be runnable standalone: `./tests/test-<script-name>.sh`
|
||||||
|
- Use colour output (green/red) for pass/fail
|
||||||
|
- Exit non-zero if any assertion fails
|
||||||
|
- A top-level `./tests/run-all.sh` runs every test and summarises results
|
||||||
|
|
||||||
|
### OpenSpec format
|
||||||
|
|
||||||
|
Specs define:
|
||||||
|
- **Purpose** — What the script does, in one sentence
|
||||||
|
- **Usage** — CLI interface, flags, arguments
|
||||||
|
- **Behaviour** — Step-by-step description of what the script does
|
||||||
|
- **Dryrun behaviour** — What `--dryrun` outputs (explicitly)
|
||||||
|
- **Edge cases** — Known boundary conditions and expected handling
|
||||||
|
- **Examples** — Concrete input/output examples
|
||||||
|
|
||||||
|
## Environment
|
||||||
|
|
||||||
|
- Scripts target Linux (Ubuntu/Debian primarily)
|
||||||
|
- Bash is the default language unless complexity warrants Python
|
||||||
|
- `~/sbin` is in the user's PATH
|
||||||
15
FUTURE.md
Normal file
15
FUTURE.md
Normal file
@@ -0,0 +1,15 @@
|
|||||||
|
# Future Ideas
|
||||||
|
|
||||||
|
## Script runner / installer
|
||||||
|
|
||||||
|
- **Problem:** Manually symlinking each script to `~/sbin` is tedious
|
||||||
|
- **Idea:** A `scripts/install.sh` that symlinks all scripts in `scripts/` to `~/sbin`, with `--dryrun` support naturally
|
||||||
|
- **Open questions:** Should it handle removal of stale symlinks? Version checking?
|
||||||
|
- **Depends on:** Having at least 2-3 scripts to justify the automation
|
||||||
|
|
||||||
|
## CI test runner
|
||||||
|
|
||||||
|
- **Problem:** Tests are only run manually
|
||||||
|
- **Idea:** Gitea CI action that runs `tests/run-all.sh` on push
|
||||||
|
- **Open questions:** What runner is available on Gitea? Docker-based?
|
||||||
|
- **Depends on:** Gitea CI being available (cluster-bootstrap M10)
|
||||||
3
MEMORY.md
Normal file
3
MEMORY.md
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# Memory Index
|
||||||
|
|
||||||
|
<!-- Thin index only — one-line descriptions linking to memory/ topic files -->
|
||||||
33
README.md
Normal file
33
README.md
Normal file
@@ -0,0 +1,33 @@
|
|||||||
|
# small-scripts
|
||||||
|
|
||||||
|
A collection of small, standalone utility scripts for daily use. Scripts are symlinked into `~/sbin` for PATH availability.
|
||||||
|
|
||||||
|
## Approach
|
||||||
|
|
||||||
|
This project uses **spec-driven development** (OpenSpec) as a testbed for agent-driven development and refinement:
|
||||||
|
|
||||||
|
1. Every script starts with a spec in `specs/`
|
||||||
|
2. Every script supports `--dryrun` to preview actions without side effects
|
||||||
|
3. Every script has a test in `tests/` that validates dryrun behaviour against the spec
|
||||||
|
|
||||||
|
## Scripts
|
||||||
|
|
||||||
|
| Script | Purpose | Status |
|
||||||
|
|--------|---------|--------|
|
||||||
|
| *(none yet)* | | |
|
||||||
|
|
||||||
|
## Quick Start
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Run all tests
|
||||||
|
./tests/run-all.sh
|
||||||
|
|
||||||
|
# Symlink a script into ~/sbin
|
||||||
|
ln -sf "$(pwd)/scripts/<name>" ~/sbin/<name>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Milestones
|
||||||
|
|
||||||
|
| # | Description | Status |
|
||||||
|
|---|-------------|--------|
|
||||||
|
| M1 | Project setup, first script | In progress |
|
||||||
41
tests/run-all.sh
Executable file
41
tests/run-all.sh
Executable file
@@ -0,0 +1,41 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Run all test scripts and summarise results
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||||
|
PASS=0
|
||||||
|
FAIL=0
|
||||||
|
FAILED_TESTS=()
|
||||||
|
|
||||||
|
for test_script in "$SCRIPT_DIR"/test-*.sh; do
|
||||||
|
[ -f "$test_script" ] || continue
|
||||||
|
name="$(basename "$test_script")"
|
||||||
|
printf "Running %s... " "$name"
|
||||||
|
if bash "$test_script"; then
|
||||||
|
printf "\033[32mPASS\033[0m\n"
|
||||||
|
PASS=$((PASS + 1))
|
||||||
|
else
|
||||||
|
printf "\033[31mFAIL\033[0m\n"
|
||||||
|
FAIL=$((FAIL + 1))
|
||||||
|
FAILED_TESTS+=("$name")
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
echo ""
|
||||||
|
echo "Results: $PASS passed, $FAIL failed"
|
||||||
|
|
||||||
|
if [ "$FAIL" -gt 0 ]; then
|
||||||
|
echo ""
|
||||||
|
echo "Failed tests:"
|
||||||
|
for t in "${FAILED_TESTS[@]}"; do
|
||||||
|
printf " \033[31m✗\033[0m %s\n" "$t"
|
||||||
|
done
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$PASS" -eq 0 ]; then
|
||||||
|
echo "No tests found."
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
printf "\033[32mAll tests passed.\033[0m\n"
|
||||||
Reference in New Issue
Block a user