- Transform tufte-press from reference guide to conversation-aware generator - Add JSON generation from conversation context following strict schema - Create build automation scripts with Nix environment handling - Integrate CUPS printing with duplex support - Add comprehensive workflow documentation Scripts added: - skills/tufte-press/scripts/generate-and-build.sh (242 lines) - skills/tufte-press/scripts/build-card.sh (23 lines) Documentation: - Updated SKILL.md with complete workflow instructions (370 lines) - Updated README.md with usage examples (340 lines) - Created SKILL-DEVELOPMENT-STRATEGY-tufte-press.md (450 lines) - Added worklog: 2025-11-10-tufte-press-skill-evolution.org Features: - Agent generates valid JSON from conversation - Schema validation before build (catches errors early) - Automatic Nix shell entry for dependencies - PDF build via tufte-press toolchain - Optional print with duplex support - Self-contained margin notes enforced - Complete end-to-end testing Workflow: Conversation → JSON → Validate → Build → Print Related: niri-window-capture, screenshot-latest, worklog skills
9.8 KiB
Script Interface Contract: Screenshot Analysis Skill
Feature: 001-screenshot-analysis
Date: 2025-11-08
Type: Bash Script CLI Interface
Overview
This document defines the interface contract for bash helper scripts used by the screenshot analysis skill. These scripts are invoked by the SKILL.md instructions and must adhere to the following specifications.
Script 1: find-latest-screenshot.sh
Purpose: Locate the most recent screenshot file in a directory
Location: skills/screenshot-analysis/scripts/find-latest-screenshot.sh
Interface:
find-latest-screenshot.sh [DIRECTORY]
Arguments:
DIRECTORY(optional): Path to screenshot directory- Default: Value from config or
~/Pictures/Screenshots - Type: String (absolute or tilde-expanded path)
- Default: Value from config or
Output (stdout):
- Success with file found: Absolute path to most recent screenshot file
- Example:
/home/user/Pictures/Screenshots/screenshot-2025-11-08.png
- Example:
- Success with no files: Empty string (or optional message)
- Example: (empty) or
No screenshots found in /home/user/Pictures/Screenshots
- Example: (empty) or
Errors (stderr):
- Directory not found:
Error: Directory not found: {path} - Permission denied:
Error: Directory not readable (permission denied): {path} - Invalid argument:
Error: Invalid directory path: {path}
Exit Codes:
0: Success (file found or directory empty)1: Error (directory not found, permission denied, invalid argument)
Behavior:
- Scans for files matching extensions:
.png,.jpg,.jpeg(case-insensitive) - Excludes symlinks (only regular files via
find -type f) - Sorts by modification time (newest first)
- Applies lexicographic tiebreaker for identical timestamps
- Returns first result after sorting
Example Usage:
# Use default directory
$ ./find-latest-screenshot.sh
/home/user/Pictures/Screenshots/screenshot-2025-11-08-143022.png
# Use custom directory
$ ./find-latest-screenshot.sh ~/Documents/Screenshots
/home/user/Documents/Screenshots/image-20251108.png
# Empty directory
$ ./find-latest-screenshot.sh /tmp/empty
# Directory doesn't exist
$ ./find-latest-screenshot.sh /nonexistent
Error: Directory not found: /nonexistent
Script 2: find-nth-screenshot.sh
Purpose: Locate the Nth most recent screenshot file
Location: skills/screenshot-analysis/scripts/find-nth-screenshot.sh
Interface:
find-nth-screenshot.sh N [DIRECTORY]
Arguments:
N(required): Screenshot index (1-based, 1 = most recent)- Type: Positive integer
- Example:
2for "previous screenshot",3for "third-most-recent"
DIRECTORY(optional): Path to screenshot directory- Default: Value from config or
~/Pictures/Screenshots
- Default: Value from config or
Output (stdout):
- Success with file found: Absolute path to Nth most recent screenshot
- Success but N exceeds count: Empty string
Errors (stderr):
- Invalid N:
Error: N must be a positive integer, got: {N} - N exceeds available files:
Error: Only {count} screenshot(s) available, cannot retrieve #{N} - Directory errors: Same as find-latest-screenshot.sh
Exit Codes:
0: Success (file found)1: Error (invalid N, directory error, N exceeds count)
Behavior:
- Same filtering/sorting logic as find-latest-screenshot.sh
- Selects Nth result from sorted list
Example Usage:
# Get previous screenshot (2nd most recent)
$ ./find-nth-screenshot.sh 2
/home/user/Pictures/Screenshots/screenshot-2025-11-08-120000.png
# Only 1 screenshot available
$ ./find-nth-screenshot.sh 2
Error: Only 1 screenshot(s) available, cannot retrieve #2
# Invalid N
$ ./find-nth-screenshot.sh 0
Error: N must be a positive integer, got: 0
Script 3: filter-by-time.sh
Purpose: Find screenshots within a time range
Location: skills/screenshot-analysis/scripts/filter-by-time.sh
Interface:
filter-by-time.sh TIME_SPEC [DIRECTORY]
Arguments:
TIME_SPEC(required): Time filter specificationtoday: Screenshots from today (00:00:00 to now){N}m: Last N minutes (e.g.,5mfor last 5 minutes){N}h: Last N hours (e.g.,2hfor last 2 hours){N}d: Last N days (e.g.,7dfor last week)
DIRECTORY(optional): Path to screenshot directory
Output (stdout):
- Success: Newline-separated list of matching screenshot paths (sorted newest first)
- No matches: Empty string
Errors (stderr):
- Invalid time spec:
Error: Invalid time specification: {TIME_SPEC} - Directory errors: Same as find-latest-screenshot.sh
Exit Codes:
0: Success (files found or no matches)1: Error (invalid time spec, directory error)
Example Usage:
# Screenshots from today
$ ./filter-by-time.sh today
/home/user/Pictures/Screenshots/screenshot-2025-11-08-143022.png
/home/user/Pictures/Screenshots/screenshot-2025-11-08-120000.png
# Last 5 minutes
$ ./filter-by-time.sh 5m
/home/user/Pictures/Screenshots/screenshot-2025-11-08-143022.png
# Last 2 hours (none found)
$ ./filter-by-time.sh 2h
Script 4: load-config.sh
Purpose: Load configuration and return screenshot directory path
Location: skills/screenshot-analysis/scripts/load-config.sh
Interface:
load-config.sh
Arguments: None
Output (stdout):
- Absolute path to screenshot directory (default or from config)
Errors (stderr):
- Malformed config JSON:
Warning: Failed to parse config.json, using default directory - Missing jq:
Warning: jq not found, using default directory - Invalid screenshot_dir:
Error: Configured screenshot_dir is not a valid directory: {path}
Exit Codes:
0: Success (config loaded or default used)1: Error (configured directory invalid)
Behavior:
- Checks for config file in order:
~/.config/opencode/skills/screenshot-analysis/config.json~/.claude/skills/screenshot-analysis/config.json
- Parses JSON using
jq -r '.screenshot_dir // empty' - Expands tilde in paths
- Falls back to
~/Pictures/Screenshotsif config missing/malformed - Validates returned directory exists and is readable
Example Usage:
# No config file (use default)
$ ./load-config.sh
/home/user/Pictures/Screenshots
# Valid config with custom directory
$ ./load-config.sh
/home/user/Documents/Screenshots
# Malformed config JSON
$ ./load-config.sh
Warning: Failed to parse config.json, using default directory
/home/user/Pictures/Screenshots
Common Contract Elements
All Scripts Must:
-
Set strict error handling:
set -euo pipefail -
Provide help flag:
if [[ "${1:-}" == "-h" ]] || [[ "${1:-}" == "--help" ]]; then show_help exit 0 fi -
Use absolute paths in output (no relative paths)
-
Handle missing dependencies gracefully:
- Check for required commands (
jq,find,stat) - Provide actionable error messages
- Check for required commands (
-
Be executable:
chmod +x scripts/*.sh -
Include shebang:
#!/usr/bin/env bash -
Support testing with fixtures:
- Accept directory argument for test isolation
- Don't hard-code paths
Integration Contract
SKILL.md → Scripts
How SKILL.md invokes scripts:
1. Run helper script to load config:
```bash
SCREENSHOT_DIR=$(~/.claude/skills/screenshot-analysis/scripts/load-config.sh)
-
Find latest screenshot:
SCREENSHOT_PATH=$(~/.claude/skills/screenshot-analysis/scripts/find-latest-screenshot.sh "$SCREENSHOT_DIR") -
Pass path to agent's image analysis capability
**Contract Requirements**:
- Scripts output ONLY the requested data to stdout (no logging/diagnostics)
- Errors/warnings go to stderr
- Exit codes indicate success/failure clearly
- Scripts are idempotent (multiple calls produce same result)
---
## Version Compatibility
**Bash Version**: 4.0+ required for:
- `[[ ]]` conditional expressions
- `$(...)` command substitution
- Arrays and associative arrays (future use)
**GNU Coreutils**: Standard versions (no special features)
- `find`: POSIX-compliant options
- `stat`: GNU stat format strings (`-c`)
- `sort`: Numeric sorting (`-rn`)
**External Dependencies**:
- `jq` 1.5+ (JSON parsing)
- All dependencies checked at runtime with fallback behavior
---
## Testing Contract
Each script must have corresponding bats tests:
**Required Test Coverage**:
1. Happy path (valid input, expected output)
2. Empty directory (no screenshots)
3. Invalid directory (not found, permission denied)
4. Symlink filtering (symlinks present, excluded correctly)
5. Timestamp tiebreaker (multiple files, same mtime)
6. Edge case: Very large directory (performance test)
**Test Location**: `tests/skills/screenshot-analysis/unit/test-{script-name}.bats`
**Example Test Structure**:
```bash
#!/usr/bin/env bats
setup() {
TEST_DIR="$(mktemp -d)"
export TEST_DIR
}
teardown() {
rm -rf "$TEST_DIR"
}
@test "script-name: happy path" {
# ... test code
}
Error Message Standards
Format: {Level}: {Description}: {Context}
Examples:
Error: Directory not found: /home/user/nonexistentWarning: jq not found, using default directoryError: Only 5 screenshot(s) available, cannot retrieve #10
Guidelines:
- Be specific (include paths, values)
- Be actionable (user knows how to fix)
- Use consistent terminology (directory, screenshot, file)
- No technical jargon (avoid "errno", "ENOENT")
Performance Contracts
| Script | Max Execution Time | Conditions |
|---|---|---|
| find-latest-screenshot.sh | <1s | Up to 1000 files |
| find-nth-screenshot.sh | <1s | Up to 1000 files |
| filter-by-time.sh | <1s | Up to 1000 files |
| load-config.sh | <10ms | Config file <1KB |
Measurement: Time from script invocation to stdout output complete
Degradation: Graceful performance degradation up to 10,000 files (<5s acceptable)