- 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
250 lines
7.5 KiB
Markdown
250 lines
7.5 KiB
Markdown
# Data Model: Screenshot Analysis Skill
|
|
|
|
**Feature**: 001-screenshot-analysis
|
|
**Date**: 2025-11-08
|
|
|
|
## Overview
|
|
|
|
This skill has a minimal data model focused on configuration and file metadata. There are no persistent data structures or databases - all data is ephemeral (file system state) or configuration (JSON file).
|
|
|
|
## Entities
|
|
|
|
### Screenshot File
|
|
|
|
**Description**: A screenshot image file discovered in the configured directory
|
|
|
|
**Attributes**:
|
|
- `path` (string, absolute): Full filesystem path to the screenshot file
|
|
- Example: `/home/user/Pictures/Screenshots/screenshot-2025-11-08-143022.png`
|
|
- Validation: Must be absolute path, must exist, must be readable
|
|
- `modification_time` (timestamp, Unix epoch): File modification time in seconds since epoch
|
|
- Example: `1731078622` (2025-11-08 14:30:22 UTC)
|
|
- Used for: Sorting files by recency
|
|
- Source: `stat -c '%Y'`
|
|
- `format` (enum): Image file format
|
|
- Allowed values: `PNG`, `JPG`, `JPEG`
|
|
- Validation: Case-insensitive match on file extension
|
|
- Used for: Filtering non-screenshot files
|
|
|
|
**Lifecycle**: Ephemeral (discovered on each invocation, not persisted)
|
|
|
|
**Relationships**: None (standalone file, no references)
|
|
|
|
**State Transitions**: N/A (stateless)
|
|
|
|
---
|
|
|
|
### Screenshot Directory
|
|
|
|
**Description**: Location where screenshots are stored
|
|
|
|
**Attributes**:
|
|
- `path` (string, absolute): Full filesystem path to the directory
|
|
- Default: `~/Pictures/Screenshots` (expanded to absolute)
|
|
- Custom: Loaded from config file `screenshot_dir` field
|
|
- Validation: Must be absolute, must exist, must be readable
|
|
- `exists` (boolean, derived): Whether the directory exists
|
|
- Computed: `[[ -d "$path" ]]`
|
|
- `readable` (boolean, derived): Whether the directory is readable
|
|
- Computed: `[[ -r "$path" ]]`
|
|
|
|
**Lifecycle**: Checked on each skill invocation
|
|
|
|
**Relationships**: Contains zero or more Screenshot Files
|
|
|
|
---
|
|
|
|
### Skill Configuration
|
|
|
|
**Description**: Optional user configuration stored in JSON file
|
|
|
|
**Storage Location** (precedence order):
|
|
1. `~/.config/opencode/skills/screenshot-analysis/config.json` (OpenCode)
|
|
2. `~/.claude/skills/screenshot-analysis/config.json` (Claude Code)
|
|
|
|
**Schema**:
|
|
```json
|
|
{
|
|
"$schema": "http://json-schema.org/draft-07/schema#",
|
|
"type": "object",
|
|
"properties": {
|
|
"screenshot_dir": {
|
|
"type": "string",
|
|
"description": "Custom screenshot directory path (absolute or ~-expanded)",
|
|
"examples": [
|
|
"/home/user/Pictures/Screenshots",
|
|
"~/Screenshots",
|
|
"/mnt/storage/screenshots"
|
|
]
|
|
}
|
|
},
|
|
"additionalProperties": false
|
|
}
|
|
```
|
|
|
|
**Attributes**:
|
|
- `screenshot_dir` (string, optional): Custom directory path
|
|
- Default: `~/Pictures/Screenshots` if omitted or file doesn't exist
|
|
- Validation: Must resolve to valid directory path after tilde expansion
|
|
|
|
**Lifecycle**: Loaded once per skill invocation
|
|
|
|
**Validation Rules**:
|
|
- If config file missing → Use default, no error
|
|
- If config file malformed JSON → Log warning, use default
|
|
- If `screenshot_dir` present but invalid path → Error with actionable message
|
|
- If `screenshot_dir` omitted → Use default
|
|
|
|
**Example Valid Configs**:
|
|
```json
|
|
// Minimal (use all defaults)
|
|
{}
|
|
|
|
// Custom directory
|
|
{
|
|
"screenshot_dir": "/home/user/Documents/Screenshots"
|
|
}
|
|
|
|
// Tilde expansion supported
|
|
{
|
|
"screenshot_dir": "~/Pictures/MyScreenshots"
|
|
}
|
|
```
|
|
|
|
**Example Invalid Configs**:
|
|
```json
|
|
// Invalid: not an object
|
|
"~/Pictures"
|
|
|
|
// Invalid: wrong type
|
|
{
|
|
"screenshot_dir": 12345
|
|
}
|
|
|
|
// Invalid: extra fields (allowed but ignored per additionalProperties: false)
|
|
{
|
|
"screenshot_dir": "~/Pictures/Screenshots",
|
|
"unknown_field": "value"
|
|
}
|
|
```
|
|
|
|
---
|
|
|
|
## Data Flow
|
|
|
|
```
|
|
1. Skill Invoked
|
|
↓
|
|
2. Load Configuration
|
|
- Check ~/.config/opencode/skills/screenshot-analysis/config.json
|
|
- Check ~/.claude/skills/screenshot-analysis/config.json
|
|
- Parse JSON (jq)
|
|
- Extract screenshot_dir or use default
|
|
↓
|
|
3. Validate Directory
|
|
- Expand tilde (~) to absolute path
|
|
- Check directory exists ([[ -d ]])
|
|
- Check directory readable ([[ -r ]])
|
|
↓
|
|
4. Discover Screenshot Files
|
|
- Find regular files (exclude symlinks)
|
|
- Filter by extension (.png, .jpg, .jpeg)
|
|
- Get modification times (stat -c '%Y %n')
|
|
↓
|
|
5. Sort by Recency
|
|
- Primary: modification time (newest first)
|
|
- Tiebreaker: lexicographic filename (Z > A)
|
|
↓
|
|
6. Select File(s)
|
|
- Latest: First result (head -1)
|
|
- Nth: Nth result (sed -n "${N}p")
|
|
- Time-filtered: All matching time constraint
|
|
↓
|
|
7. Return File Path(s)
|
|
- Absolute path(s) to agent
|
|
- Agent passes to image analysis
|
|
```
|
|
|
|
---
|
|
|
|
## Validation Rules Summary
|
|
|
|
| Entity | Field | Validation | Error Behavior |
|
|
|--------|-------|------------|----------------|
|
|
| Config File | JSON format | Valid JSON | Warn + use default |
|
|
| Config File | screenshot_dir | Absolute/expandable path | Error if invalid |
|
|
| Screenshot Dir | path | Exists + readable | Error with message |
|
|
| Screenshot File | path | Regular file (not symlink) | Skip (filter) |
|
|
| Screenshot File | format | PNG/JPG/JPEG extension | Skip (filter) |
|
|
| Screenshot File | modification_time | Valid Unix timestamp | Skip (malformed) |
|
|
|
|
---
|
|
|
|
## Edge Cases
|
|
|
|
### Empty Directory
|
|
- **Scenario**: Screenshot directory exists but contains no screenshot files
|
|
- **Behavior**: Return empty result (not an error)
|
|
- **Message**: "No screenshots found in {directory}"
|
|
|
|
### Permission Denied
|
|
- **Scenario**: Screenshot directory exists but is not readable
|
|
- **Behavior**: Error with actionable message
|
|
- **Message**: "Directory not readable (permission denied): {directory}"
|
|
|
|
### Symlinks Present
|
|
- **Scenario**: Directory contains symlinks to screenshot files
|
|
- **Behavior**: Symlinks are filtered out (skip)
|
|
- **Validation**: `find -type f` excludes symlinks automatically
|
|
|
|
### Same Timestamp
|
|
- **Scenario**: Multiple files have identical modification times
|
|
- **Behavior**: Use lexicographic filename ordering as tiebreaker
|
|
- **Example**: Given `a.png` and `z.png` both at timestamp 1731078622, `z.png` is selected (Z > A)
|
|
|
|
### Malformed Config
|
|
- **Scenario**: config.json exists but contains invalid JSON
|
|
- **Behavior**: Log warning, fall back to default directory
|
|
- **Message**: "Warning: Failed to parse config.json, using default directory"
|
|
|
|
### Missing jq
|
|
- **Scenario**: `jq` command not found on system
|
|
- **Behavior**: Log warning, fall back to default directory
|
|
- **Message**: "Warning: jq not found, using default directory"
|
|
|
|
---
|
|
|
|
## Constraints
|
|
|
|
**Performance**:
|
|
- File discovery must complete in <1 second for 1000 files (SC-002)
|
|
- Config loading must be negligible (<10ms)
|
|
|
|
**Storage**:
|
|
- No persistent storage (stateless skill)
|
|
- Config file size limited to 1KB (reasonable for JSON with single path field)
|
|
|
|
**Scalability**:
|
|
- Tested up to 1000 files (requirement)
|
|
- Degrades gracefully beyond 10,000 files (acceptable for screenshot directories)
|
|
|
|
---
|
|
|
|
## Assumptions
|
|
|
|
1. Screenshot files are regular files (not symlinks, special files, or directories)
|
|
2. Modification time accurately reflects screenshot recency (OS maintains mtime correctly)
|
|
3. File extensions (.png, .jpg, .jpeg) reliably indicate image format (case-insensitive)
|
|
4. Config file is user-managed (skill doesn't create or modify it)
|
|
5. Users won't have more than ~10,000 screenshots in a single directory
|
|
|
|
---
|
|
|
|
## Future Enhancements (Out of Scope for v1)
|
|
|
|
- **Screenshot Metadata Database**: Index screenshots for faster queries (>10k files)
|
|
- **Tag/Label Support**: Add metadata field for user-defined tags
|
|
- **Multi-Directory Search**: Support searching multiple directories
|
|
- **Format Conversion**: Support additional formats (WebP, BMP, TIFF)
|
|
- **Content-Based Search**: OCR text extraction, visual similarity
|