Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 4 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -190,7 +190,6 @@ That's it. One line. The `dir` field says where specs live (defaults to `specs/`
| Skill | What it does |
|-------|-------------|
| [migrate-to-openspec](skills/migrate-to-openspec/SKILL.md) | One-time migration from a legacy `.specs` project to OpenSpec — preserves Given/When/Then fidelity, archives originals at `.workflow/legacy-specs/` |
| [close-spec-drift](skills/close-spec-drift/SKILL.md) | When an OpenSpec base spec is correct but code or peripheral spec text drifted from it — surfaces full extent of drift, scaffolds a thin change folder (no deltas), hands off to /execute-plan |
| [spec-writer](skills/spec-writer/SKILL.md) | Thin orchestrator around `openspec instructions <artifact>` — returns enriched proposal/design/tasks/specs templates with project context |
| [spec-recommender](skills/spec-recommender/SKILL.md) | Detect code without spec coverage, infer intent, recommend OpenSpec capabilities + requirements |
| [spec-audit](skills/spec-audit/SKILL.md) | Audit OpenSpec coverage — inventory capabilities, map to code, dispatch agents to find behavioral gaps |
Expand Down Expand Up @@ -261,7 +260,6 @@ These skills describe how agents should think and work. They're loaded by refere
| [agent-driven-development](skills/agent-driven-development/SKILL.md) | Use when executing implementation plans with independent tasks -- worktree isolation, TDD discipline, two-stage review |
| [test-driven-development](skills/test-driven-development/SKILL.md) | Use when implementing any feature or bugfix, before writing implementation code |
| [verification-before-completion](skills/verification-before-completion/SKILL.md) | Use when about to claim work is complete, before committing or creating PRs -- evidence before assertions always |
| [tp](skills/tp/SKILL.md) | CLI for checkbox flips and one-line status annotations in markdown task lists (`tasks.md`, test plans) -- much cheaper than Read+Edit per tick. Ships source + prebuilt macOS arm64 binary at [bin/tp/](bin/tp/) |

### Git & PR

Expand All @@ -285,7 +283,6 @@ These skills describe how agents should think and work. They're loaded by refere
| [skill-audit](skills/skill-audit/SKILL.md) | Use after collecting usage data for a few weeks to identify dead weight -- recommends which skills to keep, prune, or consolidate |
| [promote](skills/promote/SKILL.md) | Use when checking which project skills should be available globally |
| [disk-cleanup](skills/disk-cleanup/SKILL.md) | Use when the user asks about disk space or storage -- scans for large consumers, never deletes without approval |
| [logo](skills/logo/SKILL.md) | Use when the user wants to create or generate a logo -- produces 6 SVG alternatives with a side-by-side comparison page |
| [mcp-prune](skills/mcp-prune/SKILL.md) | Use when starting work in a project with many global MCP servers that waste context tokens |
| [upload-notion-image](skills/upload-notion-image/SKILL.md) | Use when embedding images in Notion pages -- uploads natively via the Notion API file upload flow |
| [set-topic](skills/set-topic/SKILL.md) | Set the session topic displayed in the [status line](bin/statusline.sh) |
Expand All @@ -294,6 +291,10 @@ These skills describe how agents should think and work. They're loaded by refere
| [steal](skills/steal/SKILL.md) | Use when the user wants to find reusable skills, patterns, or techniques from other repos -- scans tracked GitHub repos or evaluates new ones |
| [list-skills](skills/list-skills/SKILL.md) | Use when you need a reminder of your toolkit -- quick reference of all available skills |
| [migrate-to-openspec](skills/migrate-to-openspec/SKILL.md) | Convert a legacy `.specs` project to OpenSpec layout with verifiable fidelity -- one-time per project |
| [eli5](skills/eli5/SKILL.md) | Restate the prior response in plain language and orient the user around the decision they need to make |
| [doitright](skills/doitright/SKILL.md) | Pick the long-term-correct option from a multi-option recommendation -- "go with the proper fix unless there's a real downside beyond effort" |
| [trust-action](skills/trust-action/SKILL.md) | Eliminate a specific permission prompt by adding a targeted allowlist rule -- paste a permission prompt, choose global or project scope |
| [trust-skills](skills/trust-skills/SKILL.md) | Bulk-trust all skills in the current project's `.claude/skills/` directory to stop per-skill permission prompts |

---

Expand Down
4 changes: 3 additions & 1 deletion claude-rules/compile.sh
Original file line number Diff line number Diff line change
Expand Up @@ -94,13 +94,15 @@ save_checksums() {

resolve_variables() {
local file="$1"
local project_dir
local project_dir personal_dir
project_dir="$(dirname "$RULES_DIR")"
personal_dir="$(dirname "$project_dir")"

# Built-in variables (name=value, one per line)
local builtins
builtins="CLAUDE_RULES_DIR=$RULES_DIR
PROJECT_DIR=$project_dir
PERSONAL_DIR=$personal_dir
GLOBAL_TARGET=$GLOBAL_TARGET"

# Collect all variables: builtins first, then custom from variables.env
Expand Down
106 changes: 106 additions & 0 deletions claude-rules/lib/parse-frontmatter.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#!/usr/bin/env bash
# parse-frontmatter.sh <file> <key>
#
# Extract a single YAML key's value from a markdown file's frontmatter.
# Frontmatter must be the very first block delimited by --- / --- lines.
#
# Supported value shapes:
# scalar: key: value
# inline list: key: [a, b, c]
#
# Block-list (- item lines) is NOT supported.
# Prints each list element (or the scalar) on its own line to stdout.
# Prints nothing if key is absent, no frontmatter, or file not found.
# Always exits 0.

set -euo pipefail

FILE="${1:-}"
KEY="${2:-}"

if [ -z "$FILE" ] || [ -z "$KEY" ]; then
exit 0
fi

if [ ! -f "$FILE" ]; then
exit 0
fi

# Read the frontmatter block: must start at line 1 with ---
# and end at the next --- line. If no closing --- found, treat as no frontmatter.

in_frontmatter=0
found_open=0
value=""

while IFS= read -r line; do
if [ $found_open -eq 0 ]; then
# First line must be exactly ---
if [ "$line" = "---" ]; then
found_open=1
in_frontmatter=1
continue
else
# Not a frontmatter file
break
fi
fi

# Inside frontmatter — look for closing ---
if [ "$line" = "---" ]; then
in_frontmatter=0
break
fi

# Try to match key: ...
# Strip leading whitespace for the comparison
trimmed="${line#"${line%%[![:space:]]*}"}"
key_prefix="${KEY}: "
if [[ "$trimmed" == "${KEY}: "* ]] || [[ "$trimmed" == "${KEY}:"* ]]; then
# Extract value after the colon
raw_value="${trimmed#*: }"
# Handle case where there's no space after colon
if [[ "$trimmed" == "${KEY}:" ]]; then
raw_value=""
fi
value="$raw_value"
fi
done < "$FILE"

# If we never found an opening ---, nothing to output
if [ $found_open -eq 0 ]; then
exit 0
fi

# If key wasn't found, nothing to output
if [ -z "$value" ]; then
exit 0
fi

# Parse value: inline list or scalar
trimmed_value="${value#"${value%%[![:space:]]*}"}"
trimmed_value="${trimmed_value%"${trimmed_value##*[![:space:]]}"}"

if [[ "$trimmed_value" == "["* ]]; then
# Inline list: [a, b, c]
# Strip brackets
inner="${trimmed_value#[}"
inner="${inner%]}"
# Split by comma, trim whitespace from each element
IFS=',' read -ra items <<< "$inner"
for item in "${items[@]}"; do
# Trim whitespace
trimmed_item="${item#"${item%%[![:space:]]*}"}"
trimmed_item="${trimmed_item%"${trimmed_item##*[![:space:]]}"}"
if [ -n "$trimmed_item" ]; then
echo "$trimmed_item"
fi
done
else
# Scalar
if [ -n "$trimmed_value" ]; then
echo "$trimmed_value"
fi
fi

exit 0
26 changes: 26 additions & 0 deletions claude-rules/scope-presets.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
{
"$schema": "scope-presets",
"presets": {
"full": {
"description": "Everything not matched by the source's hardcoded exclude list. Aaron's default for his own dev loop.",
"skills": "*",
"snippets": "*",
"excludeSkills": ["airon-*", "thanx-*", "baker_st-*", "frontend-design", "playground", "plannotator-*", "anutron-install", "anutron-uninstall"]
},
"spec-discipline": {
"description": "Spec-first + TDD + quality gates. Recommended for contributor-facing repos.",
"skillTags": ["spec", "quality"],
"snippetTags": ["spec", "quality", "formatting"],
"snippetAudience": ["shared"]
},
"dev-tools": {
"extends": "spec-discipline",
"description": "spec-discipline + parallel workflow + PR shipping.",
"skillTags": ["spec", "quality", "workflow", "pr"]
},
"custom": {
"description": "Read includeSkills/excludeSkills/includeSnippets/excludeSnippets from .anutron-install.config.json in the target repo.",
"from": "manifest"
}
}
}
25 changes: 15 additions & 10 deletions claude-rules/snippets/global/005-claudemd-management.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,18 @@
---
tags: [personal]
audience: [aaron]
---
## CLAUDE.md Management

Both `~/.claude/CLAUDE.md` (global) and `{{PROJECT_DIR}}/CLAUDE.md` (project) are **compiled from snippets** — never edit the CLAUDE.md files directly.
Both `~/.claude/CLAUDE.md` (global) and the project CLAUDE.md are **compiled from snippets** — never edit the CLAUDE.md files directly.

**Source of truth:** `{{CLAUDE_RULES_DIR}}/snippets/`
**Source of truth:** the `snippets/` directory in `claude-rules/`
- `snippets/global/*.md` → compiled into `~/.claude/CLAUDE.md`
- `snippets/project/*.md` → compiled into `{{PROJECT_DIR}}/CLAUDE.md`
- `snippets/project/*.md` → compiled into the project's CLAUDE.md

**Workflow:**
1. Edit or create a snippet in the appropriate `snippets/{global,project}/` directory
2. Run `{{CLAUDE_RULES_DIR}}/compile.sh` to regenerate the dist files
2. Run `compile.sh` (in `claude-rules/`) to regenerate the dist files
3. The CLAUDE.md files are symlinks to the compiled output — changes appear immediately

**Commands:**
Expand All @@ -21,13 +25,14 @@ Both `~/.claude/CLAUDE.md` (global) and `{{PROJECT_DIR}}/CLAUDE.md` (project) ar
**Naming convention:** Snippets are numbered for ordering (e.g., `010-plan-formatting.md`, `040-tech-stack.md`). Use gaps to allow inserting new snippets without renumbering.

**Template Variables:**
Snippets can use `{{VARIABLE}}` placeholders that compile.sh resolves during compilation.
Snippets can use `{{VAR}}`-style placeholders (double curly braces around an uppercase name) that compile.sh resolves during compilation.

Built-in variables:
- `{{CLAUDE_RULES_DIR}}` — absolute path to the claude-rules directory
- `{{PROJECT_DIR}}` — absolute path to the project root (parent of claude-rules/)
- `{{GLOBAL_TARGET}}` — `~/.claude/CLAUDE.md`
Built-in variables — refer to these names when writing placeholders in snippets:
- `CLAUDE_RULES_DIR` — absolute path to the claude-rules directory
- `PROJECT_DIR` — absolute path to the project root (parent of claude-rules/)
- `PERSONAL_DIR` — absolute path to the personal-projects root (parent of PROJECT_DIR)
- `GLOBAL_TARGET` — absolute path to `~/.claude/CLAUDE.md`

Custom variables: define in `{{CLAUDE_RULES_DIR}}/variables.env`, one per line (`KEY=value`). Values can reference other variables.
Custom variables: define in `variables.env` (next to `compile.sh`), one per line (`KEY=value`). Values can reference other variables using the same placeholder syntax.

When editing or creating snippets, **always use template variables for paths** — never hardcode absolute paths. This keeps snippets portable and publishable.
4 changes: 4 additions & 0 deletions claude-rules/snippets/global/010-plan-formatting.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
tags: [formatting]
audience: [shared]
---
## Markdown Formatting Requirements

All markdown you produce — plans, reports, codebase gap summaries, agent outputs, specs, any structured text — MUST use proper markdown to ensure correct rendering in Plannotator.
Expand Down
4 changes: 4 additions & 0 deletions claude-rules/snippets/global/015-writing-style.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
tags: [formatting]
audience: [shared]
---
## Writing style

- **Titles:** Always sentence case (capitalize first word only). Never Title Case or ALL CAPS.
Expand Down
17 changes: 17 additions & 0 deletions claude-rules/snippets/global/020-interaction-prefs.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,22 @@
---
tags: [formatting]
audience: [shared]
---
## Interaction Preferences

### Asking for a decision

When you need the user's input to choose between approaches, frame it in terms of outcomes — not implementation details. Structure every decision request like this:

- **The decision** — one sentence naming the choice, framed as a question. Lead with the observable outcome ("the UI freezes briefly during X"), not the mechanism ("functionA() calls sleep()").
- **Your options** — a bullet list, one short plain-language sentence each.
- **Tradeoffs** — the main upside and downside for each option, in plain terms.
- **My recommendation** — pick one, state it directly, give the one-line reason. No hedging.

This applies anywhere a decision needs the user — after `/ralph-review`, `/review`, `/debug`, mid-implementation forks, plan reviews, anywhere. If the prior context was deeply technical, translate before asking. Strip jargon, acronyms, and code references unless the decision is literally about syntax.

The user can still type `/eli5` to retroactively re-explain a prior response — that's a separate user-invoked path.

### Question-by-Question Approach

When you have multiple questions, ask them **one at a time** with progress indicators:
Expand Down
35 changes: 0 additions & 35 deletions claude-rules/snippets/global/022-user-facing-framing.md

This file was deleted.

4 changes: 4 additions & 0 deletions claude-rules/snippets/global/040-plan-execution-handoff.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
tags: [spec]
audience: [shared]
---
## Plan execution handoff

After a plan is approved via `ExitPlanMode`, always:
Expand Down
6 changes: 5 additions & 1 deletion claude-rules/snippets/global/040-tech-stack.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
---
tags: [personal]
audience: [aaron]
---
## Tech Stack Spectrum

New applications follow the **stack spectrum** defined in `{{PROJECT_DIR}}/docs/stack-spectrum.md`. Four web tiers plus a CLI track — pick the lightest that fits:
Expand All @@ -7,7 +11,7 @@ New applications follow the **stack spectrum** defined in `{{PROJECT_DIR}}/docs/
| **Lightweight** | No database, simple web UI | HTML + CSS + JS (no build step) |
| **Personal** | Local app with DB and real UI | Next.js + Prisma + MySQL + shadcn/ui |
| **Distributed** | Local app, shared/hosted data | Personal tier + Supabase (Postgres) |
| **Deployable** | Production app for other users | Rails + Next.js monorepo (see `docs/thanx-dev-system.md`) |
| **Deployable** | Production app for other users | Rails + Next.js monorepo |
| **CLI** | Terminal-first tool | Go + Cobra (+ Bubbletea for TUI) |

### Quick decision guide
Expand Down
Loading