Preamble
# Detect .jtbd/ directory
_JTBD_DIR=".jtbd"
_HAS_JTBD="no"
[ -d "$_JTBD_DIR" ] && _HAS_JTBD="yes"
echo "JTBD_DIR: $_HAS_JTBD"
# Detect gstack (optional integration)
_HAS_GSTACK="no"
[ -d "$HOME/.claude/skills/gstack" ] && _HAS_GSTACK="yes"
_ROOT=$(git rev-parse --show-toplevel 2>/dev/null)
[ -n "$_ROOT" ] && [ -d "$_ROOT/.claude/skills/gstack" ] && _HAS_GSTACK="yes"
echo "GSTACK: $_HAS_GSTACK"
# Detect git
_HAS_GIT="no"
git rev-parse --is-inside-work-tree 2>/dev/null && _HAS_GIT="yes"
echo "GIT: $_HAS_GIT"
# Check for python3 (YAML validation)
_HAS_PYTHON="no"
command -v python3 >/dev/null 2>&1 && _HAS_PYTHON="yes"
echo "PYTHON3: $_HAS_PYTHON"
# Read manifest if .jtbd/ exists
if [ "$_HAS_JTBD" = "yes" ] && [ -f "$_JTBD_DIR/manifest.yml" ]; then
echo "--- MANIFEST ---"
cat "$_JTBD_DIR/manifest.yml"
echo "--- END MANIFEST ---"
fi
# Count existing switch analyses
if [ "$_HAS_JTBD" = "yes" ] && [ -d "$_JTBD_DIR/switches" ]; then
_SWITCH_COUNT=$(ls "$_JTBD_DIR/switches/"*.yml 2>/dev/null | wc -l | tr -d ' ')
echo "SWITCH_COUNT: $_SWITCH_COUNT"
else
echo "SWITCH_COUNT: 0"
fi
# Detect jtbd skill locations. Order matches jtbd-demo: Claude plugin root, Antigravity
# plugin paths, the repo you are working in, global skills paths, then a pre-v1.6.0.0 clone last.
# Every branch tests for an actual SKILL.md, not just a directory.
_JTBD_SKILLS=""
if [ -n "$CLAUDE_PLUGIN_ROOT" ] && [ -f "$CLAUDE_PLUGIN_ROOT/jtbd-switch/SKILL.md" ]; then
_JTBD_SKILLS="$CLAUDE_PLUGIN_ROOT"
elif [ -f "$HOME/.gemini/config/plugins/jtbd/jtbd-switch/SKILL.md" ]; then
_JTBD_SKILLS="$HOME/.gemini/config/plugins/jtbd"
elif [ -f "$HOME/.gemini/config/plugins/savvides-jtbd/jtbd-switch/SKILL.md" ]; then
_JTBD_SKILLS="$HOME/.gemini/config/plugins/savvides-jtbd"
elif [ -n "$_ROOT" ] && [ -f "$_ROOT/jtbd-switch/SKILL.md" ]; then
_JTBD_SKILLS="$_ROOT"
elif [ -f "$HOME/.gemini/config/skills/jtbd/jtbd-switch/SKILL.md" ]; then
_JTBD_SKILLS="$HOME/.gemini/config/skills/jtbd"
elif [ -f "$HOME/.claude/skills/jtbd/jtbd-switch/SKILL.md" ]; then
_JTBD_SKILLS="$HOME/.claude/skills/jtbd"
fi
echo "JTBD_SKILLS: ${_JTBD_SKILLS:-not found}"
Initialize .jtbd/ (if needed)
If JTBD_DIR is no, create the .jtbd/ directory structure before proceeding.
- Use AskUserQuestion to gather product info:
"No .jtbd/ directory found. I'll create one. What's your product called, and what stage are you at?"
Options:
- A) Set up now (I'll provide product name and stage)
- B) Use defaults (product: "Unknown", stage: "pre-product")
If A: Ask for product name, one-line description, stage (pre-product / has-users / has-paying-customers), target user role, and target user context.
If B: Use defaults.
- Create the directory structure:
.jtbd/
├── manifest.yml
├── .gitignore
├── raw/
└── switches/
- Write
manifest.ymlwith the user's answers (or defaults):
schema_version: 1
product:
name: "{product_name}"
description: "{description}"
stage: "{stage}"
target_user:
role: "{role}"
context: "{context}"
settings:
auto_commit: true
gitignore_raw: true
evidence_threshold: 6
- Write
.jtbd/.gitignore:
# Raw interview transcripts contain PII - keep out of git by default
raw/
Discover Inputs
Determine the transcript source from the user's invocation:
If a directory path was provided: Glob for transcript files in that directory.
ls {directory}/*.txt {directory}/*.md 2>/dev/null
Count the files found. If zero, tell the user: "No .txt or .md files found in {directory}." and stop.
If Fireflies meeting IDs were provided (format: fireflies:id1,id2,id3): Use the fireflies_get_transcript MCP tool to fetch each transcript. If MCP is unavailable, tell the user and ask them to provide file paths instead.
If no argument: Use AskUserQuestion:
"Where are your interview transcripts? Provide a directory path containing .txt or .md files, or paste Fireflies meeting IDs."
Options:
- A) I'll provide a directory path
- B) I have Fireflies meeting IDs
- C) I'll paste transcripts directly (one at a time)
List the discovered transcripts for the user:
"Found {N} transcript(s):"
- {filename1} ({word_count} words)
- {filename2} ({word_count} words) ...
If any transcript is under 500 words, warn: "{filename} is very short ({word_count} words). Switch analysis works best with 5,000-10,000 word transcripts from 30-60 minute interviews. Include it anyway?"
Run Switch Analysis on Each Transcript
For each transcript, run the /jtbd-switch analysis. This is the core loop.
Execution Strategy
If 3 or fewer transcripts: Run sequentially. For each transcript:
- Read the transcript file
- Follow the
/jtbd-switchextraction rules (read them from$_JTBD_SKILLS/jtbd-switch/SKILL.md, substituting the path the preamble echoed forJTBD_SKILLS; a barejtbd-switch/SKILL.mddoes not resolve from the user's own project):- Extract the switching timeline (first thought, passive looking, active looking, deciding, consuming)
- Extract the four forces (push, pull, anxiety, habit) with verbatim quotes and intensity scores
- Generate a job story in Klement format
- Score evidence strength
- Write the YAML to
.jtbd/switches/{filename}.yml - Validate YAML if python3 is available
- Report: "Analyzed {name} ({role}): {job_story_summary}"
If 4 or more transcripts: Use the Agent tool to parallelize. Dispatch up to 4 agents concurrently, each running switch analysis on a different transcript.
Each agent prompt should include:
- The full transcript content
- The extraction rules from the "Extract Switch Analysis" section of
$_JTBD_SKILLS/jtbd-switch/SKILL.md(methodology, extraction rules, output format, filename convention). Read that file yourself and paste the rules into the agent prompt — the agent gets noJTBD_SKILLSvalue of its own, so a bare or unsubstituted path leaves it improvising the methodology from memory. - The
.jtbd/switches/output path - Instructions to write the YAML file and report the result
After all agents complete, verify each output file exists and is valid YAML.
Progress Reporting
After each transcript is analyzed (sequential or parallel), report progress:
"Progress: {completed}/{total} transcripts analyzed"
- {name} ({role}): "{one-line job story}" — evidence: {overall}/10
Error Handling
If a transcript fails analysis (too short, not an interview, invalid content):
- Skip it with a warning: "Skipped {filename}: {reason}"
- Continue with remaining transcripts
- Include the skip in the final summary
Human Review Gate
After all switch analyses are complete, present a summary for review:
Pipeline: Switch Analysis Complete
Analyzed: {N} transcripts → {M} switch files Skipped: {K} (if any, list reasons)
Interviewees: {For each: name, role, company, evidence score}
Job Stories: {For each: the job story}
Note: These files contain interview data including names, companies, and direct quotes. Make sure your repo is private, or redact sensitive information before committing.
Options:
- A) Looks good, continue to pattern analysis
- B) I want to review/edit individual analyses first
- C) Stop here (I'll run /jtbd-patterns manually later)
If B: Let the user specify which files to review. Present each for editing. Then re-present the summary.
If C: Commit the switch files and stop.
Run Pattern Analysis
If the user approved continuing AND there are 3+ switch analyses total (including any pre-existing ones):
- Read ALL switch analysis files in
.jtbd/switches/(not just the new ones) - Follow the
/jtbd-patternsanalysis workflow:- Cluster by job (overlapping push + pull forces)
- Analyze force patterns across all interviews
- Analyze timeline patterns
- Identify evidence gaps
- Generate recommendations
- Write the patterns YAML to
.jtbd/patterns/patterns-{YYYYMMDD}.yml - Validate YAML if python3 is available
If fewer than 3 total switch analyses: Skip patterns with a note: "Only {N} switch analyses available. Pattern analysis needs 3+. Run more interviews and then run /jtbd-patterns."
Commit and Summary
- Stage all new files. Add directories rather than globs: with fewer than 3
transcripts, pattern analysis is skipped and
.jtbd/patterns/never exists, and an unmatched glob aborts the wholegit addso nothing at all is staged.
git add .jtbd/manifest.yml .jtbd/.gitignore
[ -d .jtbd/switches ] && git add .jtbd/switches
[ -d .jtbd/patterns ] && git add .jtbd/patterns
git diff --cached --quiet && echo "STAGED: none" || echo "STAGED: $(git diff --cached --name-only | wc -l | tr -d ' ')"
- If
GITisyesand the manifest hasauto_commit: true, andSTAGEDis notnone:
Substitute the real transcript count for <N> before running this. It sits in a bash
block, so it gets copied verbatim unless you replace it — a commit reading
pipeline analysis of {N} interviews has shipped to this repo's own history once.
git commit -m "jtbd: pipeline analysis of <N> interviews"
If STAGED is none, do not commit and do not report the run as committed. Tell the
user the files were written but nothing was staged, and show them the paths.
- Present the final summary:
JTBD Pipeline Complete
Input: {N} transcripts from {source} Switch analyses: {M} created, {K} skipped Total in .jtbd/switches/: {total} (including pre-existing) Patterns: {generated | skipped (need 3+)} Committed: {yes | no, files written but not committed}
Key Findings: {If patterns were generated:}
- Primary job: "{top cluster job}" ({frequency})
- Strongest push: {description}
- Biggest evidence gap: {description}
- Top recommendation: {recommendation}
Next steps:
- Review individual switch files in
.jtbd/switches/- Run
/jtbd-interviewto generate scripts targeting evidence gaps- Run
/jtbd-forcesto generate a visual forces diagram- Run
/jtbd-mapto synthesize the patterns into a Job Map- Run
/jtbd-briefto turn that Job Map into a product brief- If using gstack: run
/office-hoursto turn your brief into a design doc