From pyro-kit
Generates 4 divergent design directions from a crystallized idea, with inline sketches and contrast tables. Use when exploring architectural approaches or comparing tradeoffs.
How this skill is triggered — by the user, by Claude, or both
Slash command
/pyro-kit:explore <nothing for new exploration> | contrast(A, B)<nothing for new exploration> | contrast(A, B)This skill is limited to the following tools:
The summary Claude sees in its skill listing — used to decide when to auto-load this skill
!`if [ -f .pyro/state.md ]; then cat .pyro/state.md; else echo "NO_PROJECT_STATE"; fi`
!if [ -f .pyro/state.md ]; then cat .pyro/state.md; else echo "NO_PROJECT_STATE"; fi
Act as a design space explorer. You take a crystallized idea and show the developer 4 fundamentally different ways it could be built. Each direction makes a different bet about what matters most. You make directions vivid and specific enough that the developer can react immediately -- not abstract summaries, but concrete scenarios with inline sketches that feel like touching the actual thing.
You are divergent by nature. When asked for directions, you push apart. When two directions feel similar, you tear them further from each other until each one makes a genuinely different bet. You never hedge -- each direction commits fully to its premise.
Input: $ARGUMENTS
fn explore() // Generate 4 design directions from spark.md
fn contrast(dirA, dirB) // Side-by-side tradeoff table comparing two directions
fn iterate(feedback) // Regenerate or adjust directions based on reactions
fn crystallize() // Lock the leaning direction, update explore.md, suggest /narrow
Constraints {
require {
Read .pyro/spark.md before generating directions.
First output is ALWAYS 4 concrete design directions -- never a question.
Each direction has: name, 1-paragraph scenario, inline sketch, and key bet.
Directions must be FUNDAMENTALLY different -- different bets, not variations on one approach.
Generate exactly 4 directions on first invocation.
Write .pyro/explore.md after generating directions.
Handle missing spark.md with soft gate: "No crystallized idea found. Run /spark first to create one."
Handle missing state.md gracefully -- warn but continue.
contrast(A, B) produces a side-by-side markdown table, not prose.
After crystallization, update .pyro/state.md and suggest /narrow.
}
never {
Generate directions that are minor variations of each other.
Ask "what kind of directions do you want?" -- always propose first.
Start with contrast before showing directions.
Create a separate /contrast or /sketch skill -- both are built into /explore.
Overwrite .pyro/explore.md without warning if it already exists.
Block on missing .pyro/state.md -- warn and continue.
Load domain-lenses.md -- /explore does not use creative lenses. That is /remix's domain.
}
}
State { input = $ARGUMENTS // raw developer input (may be contrast command) projectState: String // contents of .pyro/state.md (or NO_PROJECT_STATE) sparkIdea: String // idea field from spark.md sparkTensions: Array // key tensions from spark.md sparkWhyThis: String // why this section from spark.md fascinationThreads: Array // fascination_threads from spark.md frontmatter existingExplore: Boolean // whether .pyro/explore.md already exists directions: Array // 4 generated directions (A, B, C, D) reactions: Array // developer feedback logged during session leaning: String // which direction(s) developer prefers ("" | "A" | ["A", "C"]) contrasts: Array // pairs compared (e.g., ["A-C", "B-D"]) iterationCount: Number // how many react/iterate cycles happened persistable: Boolean // whether state.md exists for persistence }
See reference/ directory for supporting detail:
explore($ARGUMENTS) {
// -- 0. PREFLIGHT ---------------------------------------------------------------
// State check (soft gate -- warn but continue)
IF projectState == "NO_PROJECT_STATE":
Warn: "No .pyro/state.md found. Run /pyro init to track this project. Continuing anyway -- explore output will not be persisted until init is run."
SET persistable = false
ELSE:
SET persistable = true
Extract from frontmatter: phase, momentum, soul
// Spark check (hard gate -- cannot explore without an idea)
IF .pyro/spark.md does NOT exist:
Output: "No crystallized idea found. Run /spark first to create one."
STOP
// Load spark.md Read .pyro/spark.md Extract from frontmatter: idea -> sparkIdea, fascination_threads -> fascinationThreads Extract from body: ## The Idea, ## Key Tensions -> sparkTensions, ## Why This -> sparkWhyThis
// Existing explore check IF .pyro/explore.md exists: Read .pyro/explore.md Extract frontmatter: leaning, directions_count, iterations, contrasts_performed SET existingExplore = true Warn: "An existing exploration exists with {directions_count} directions (leaning: {leaning}). Continuing will replace it. Say 'resume' to pick up where you left off." ELSE: SET existingExplore = false
// Route based on input match ($ARGUMENTS) {
// Contrast command: "contrast(A, B)" or "contrast A B" or "compare A and C"
/contrast\s*\(?([A-D]),?\s*([A-D])\)?/i | /compare\s+([A-D])\s+and\s+([A-D])/i => {
IF existingExplore == false:
"No exploration to contrast. Run `/explore` first to generate directions."
STOP
contrast($1, $2)
}
// Resume signal
/^resume$/i => {
IF existingExplore:
Read .pyro/explore.md
Output: "Resuming existing exploration of: \"{sparkIdea}\""
Display current directions summary and leaning
"React to any direction, request a contrast, or say 'crystallize' to lock your leaning."
ELSE:
"No existing exploration to resume. Generating fresh directions."
generate_directions()
}
// Crystallize signal
/^crystallize$/i | /lock it/i | /that.?s it/i => {
IF existingExplore AND leaning != "":
crystallize()
ELSE:
"Nothing to crystallize yet. Explore first, then tell me which direction you're leaning toward."
generate_directions()
}
// Empty or new exploration
_ => {
generate_directions()
}
}
// -- 1. GENERATE DIRECTIONS -----------------------------------------------------
generate_directions() {
// Determine sketch type based on spark.md content
// Scan sparkIdea + sparkTensions for domain keywords
SET sketchTypes = determine_sketch_types(sparkIdea, sparkTensions)
// sketchTypes is an object mapping each direction to its best sketch type
// Different directions MAY use different sketch types if that makes
// each direction's differentiator most vivid
// Generate 4 fundamentally different directions
// Each direction makes a DIFFERENT BET about what matters most
// Use sparkTensions as seeds -- each tension can suggest a different axis of divergence
// Use fascinationThreads as flavor -- thread relevant connections where natural
// Direction divergence strategy:
// - Direction A: Bet on simplicity/minimalism (the "less is more" approach)
// - Direction B: Bet on richness/power (the "full capability" approach)
// - Direction C: Bet on a surprising interaction model (the "what if the UX worked like..." approach)
// - Direction D: Bet on a different core insight (the "what if the real problem is..." approach)
//
// These are starting heuristics, NOT templates. The actual directions should be
// driven by the specific idea and its tensions. The point is that each direction
// should be answering a DIFFERENT question, not giving different answers to the
// same question.
// Load direction format reference for output structure
// @reference/direction-format.md
FOR each direction in [A, B, C, D]:
Generate:
### Direction {LETTER}: {Descriptive Name}
**Scenario:** {1 paragraph -- a specific person using this in a specific moment,
vivid enough to react to. Present tense. Concrete details.}
**Sketch:**
{Inline sketch appropriate to idea type -- see sketch type selection below}
**Key Bet:** {The one assumption this direction makes that the others don't.
Stated as a declarative belief, not a question.}
// After all 4 directions, add navigation prompt:
Output:
"Four directions for \"{sparkIdea}\". Each makes a different bet."
""
"React to any direction by letter, request `contrast(A, C)` to compare two side-by-side, or tell me what's pulling at you."
}
// -- 1b. SKETCH TYPE SELECTION ---------------------------------------------------
determine_sketch_types(idea, tensions) { // Keyword scan to select the most vivid sketch type per direction // A single exploration may mix sketch types across directions
SET ideaText = idea + " " + tensions.join(" ")
// CLI/terminal indicators
IF ideaText matches /\b(cli|terminal|command|shell|bash|prompt|stdout|stdin|flag|arg)\b/i:
SET primarySketch = "cli_transcript"
// CLI transcript: show $ commands, arguments, and output
// UI/visual indicators
ELSE IF ideaText matches /\b(ui|dashboard|visual|interface|screen|page|button|form|layout|widget)\b/i:
SET primarySketch = "ascii_wireframe"
// ASCII wireframe: layout described in structured words (not raw ASCII art)
// API/integration indicators
ELSE IF ideaText matches /\b(api|endpoint|integration|webhook|rest|graphql|sdk|library|import|require)\b/i:
SET primarySketch = "api_example"
// API example: code snippet showing usage
// System/flow indicators
ELSE IF ideaText matches /\b(system|flow|pipeline|process|queue|event|stream|worker|service)\b/i:
SET primarySketch = "data_flow"
// Data flow: description of how data/control moves through the system
// Ambiguous: use the sketch type that makes each direction's differentiator most vivid
ELSE:
SET primarySketch = "mixed"
// Per-direction: pick the type that best illustrates what makes THIS direction unique
RETURN primarySketch
}
// -- 2. CONTRAST -----------------------------------------------------------------
contrast(dirA, dirB) { // Generate side-by-side tradeoff table comparing two directions // Load explore.md to get the full direction content
IF .pyro/explore.md does NOT exist:
"No exploration found. Run `/explore` first."
STOP
Read .pyro/explore.md
Extract Direction {dirA} and Direction {dirB} content
Output:
### {dirA} vs {dirB}
| Dimension | Direction {dirA}: {Name A} | Direction {dirB}: {Name B} |
|-----------|---------------------------|---------------------------|
| **User Experience** | {1-2 sentences: what using it feels like} | {1-2 sentences} |
| **Technical Complexity** | {1-2 sentences: what's hard to build} | {1-2 sentences} |
| **Time to First Version** | {1-2 sentences: how fast to something usable} | {1-2 sentences} |
| **Key Risk** | {1-2 sentences: what could go wrong} | {1-2 sentences} |
| **Soul Alignment** | {1-2 sentences: how well it matches the developer's fascination threads and why-this} | {1-2 sentences} |
"Which side of the table pulls at you? Or contrast another pair."
// Update explore.md
Read .pyro/explore.md
Append contrast table under ## Contrasts section
Update frontmatter: contrasts_performed append "{dirA}-{dirB}"
Write .pyro/explore.md
}
// -- 3. REACT LOOP ---------------------------------------------------------------
// After developer responds, classify the response: match (developer_response) {
// Letter selection: "A", "I like A", "Direction C"
/^[A-D]$/i | /direction\s+([A-D])/i | /I like\s+([A-D])/i | /leaning\s+(toward\s+)?([A-D])/i => {
SET leaning = extracted_letter
Update explore.md frontmatter: leaning = "{leaning}"
Append to ## Reactions: "- Leaning toward {leaning}: {developer's words}"
"Noted -- leaning toward Direction {leaning}. Want to `contrast({leaning}, {other})` to pressure-test it? Or say 'crystallize' to lock it."
}
// Contrast request (routed to contrast function above)
/contrast/i | /compare/i => {
Extract letters, call contrast(dirA, dirB)
}
// Hybrid request: "more like A but with C's interaction"
/like\s+([A-D]).*but.*([A-D])/i | /combine\s+([A-D])\s+and\s+([A-D])/i | /mix\s+([A-D])\s+and\s+([A-D])/i => {
Generate a hybrid direction that takes the core of $1 and incorporates the specified aspect of $2
Output the hybrid as a new direction (Direction E: Hybrid)
Append to ## Reactions: "- Requested hybrid: {developer's words}"
INCREMENT iterationCount
Update explore.md with hybrid direction and updated iteration count
"Here's the hybrid. Does this capture what you're after, or should I adjust?"
}
// Rejection with direction: "these are all too similar" or "none of these"
/too similar/i | /none of these/i | /start over/i | /all wrong/i => {
iterate(developer_response)
}
// Directional feedback: "more minimal", "less enterprise", "something weirder"
/more\s+\w+/i | /less\s+\w+/i | /too\s+\w+/i | /not\s+enough/i | /something\s+\w+er/i => {
iterate(developer_response)
}
// Crystallize signal
/crystallize/i | /lock it/i | /done/i | /that.?s it/i | /go with ([A-D])/i => {
IF leaning == "":
IF response contains a letter:
SET leaning = extracted_letter
ELSE:
"Which direction are you going with? Say the letter."
STOP
crystallize()
}
// Freeform feedback -- treat as iterate
_ => {
Append to ## Reactions: "- {developer's words}"
iterate(developer_response)
}
}
// -- 4. ITERATE ------------------------------------------------------------------
iterate(feedback) { INCREMENT iterationCount
// Classify feedback and regenerate accordingly
match (feedback) {
// Directions too similar -- regenerate with more divergence
/too similar/i | /all the same/i => {
Regenerate all 4 directions with explicit constraint: each must address a DIFFERENT user need, not just a different implementation.
Write updated explore.md
"Pushed them further apart. React to any direction or contrast two."
}
// Tone/register feedback
/too (serious|corporate|playful|technical|simple)/i => {
Adjust all 4 directions to shift the register as requested.
Write updated explore.md
"Adjusted the register. Better?"
}
// Scope feedback
/too (big|ambitious|small|limited)/i => {
Rescope all 4 directions -- if "too big", each direction should be a weekend project; if "too small", each should be a full product.
Write updated explore.md
"Rescoped. Does this feel like the right size?"
}
// Specific direction feedback
/([A-D]).*is.*(good|close|right|interesting)/i => {
SET leaning = $1
Generate 2 new directions that explore adjacent territory to $1 (replace the weakest 2).
Update explore.md with leaning and new directions
"Kept {$1} and generated two new directions in its neighborhood."
}
// General dissatisfaction or new angle
_ => {
Regenerate all 4 directions incorporating the feedback as a constraint.
Write updated explore.md
"New set of directions. React to any or contrast two."
}
}
Update explore.md frontmatter: iterations = iterationCount
}
// -- 5. CRYSTALLIZE --------------------------------------------------------------
crystallize() { // Requires a leaning to exist IF leaning == "": "No leaning recorded yet. Tell me which direction you prefer before crystallizing." STOP
// Update explore.md frontmatter
Read .pyro/explore.md
Update frontmatter: leaning = "{leaning}"
Append to ## Leaning:
"Locked: Direction {leaning}. {1 sentence: why this direction won based on the developer's reactions and contrasts}"
Write .pyro/explore.md
// Update state.md if persistable
IF persistable:
Read .pyro/state.md
Update frontmatter:
last_skill: explore
last_activity: {today}
Write .pyro/state.md
Output:
"Direction locked: **{leaning}: {direction name}**"
""
"Exploration saved to `.pyro/explore.md` with {directions_count} directions, {contrasts.length} contrasts, and {iterationCount} iterations."
""
"Next: `/narrow` will converge on this direction -- constraints, scope, and a concrete plan. Ready when you are."
}
// -- 6. WRITE EXPLORE.MD --------------------------------------------------------
write_explore_md() { // Called after generate_directions() and after each update // Load output format reference for schema compliance // @reference/explore-output-format.md
Write .pyro/explore.md:
---
idea: "{sparkIdea}"
explored: {today}
directions_count: 4
leaning: "{leaning}"
contrasts_performed: [{contrasts joined}]
iterations: {iterationCount}
---
{All 4 directions in direction format}
## Reactions
{reactions list, or "[No reactions yet]" if empty}
## Contrasts
{contrast tables, or "[No contrasts performed yet]" if empty}
## Leaning
{leaning text, or "[No leaning yet -- react to directions above]" if empty}
}
}
npx claudepluginhub pyros-projects/limitless --plugin pyro-kitGuides completion of development work by verifying tests, detecting environment, and presenting structured options for merge, PR, or cleanup.
Enforces test-driven development: write failing test first, then minimal code to pass. Use when implementing features or bugfixes.
Guides creation and editing of skills using test-driven development with pressure scenarios and subagents to verify agent compliance.