---
phase: 1
plan: 2
type: execute
wave: 1
depends_on: []
files_modified:
  - .planning/research/OUTREACH.md
  - .planning/research/INTERVIEW-PROTOCOL.md
  - .planning/research/INTERVIEW-NOTES.md
autonomous: false
requirements: [USR-01, USR-02]
must_haves:
  truths:
    - "All 4 real users from SIGNAL.md (Lief/RyanTJoy, Elpolini, Jory Irving, Jasmeet Sidhu) have received a personal, by-name outreach message sent by Wes via GitHub, and the exact message + delivery channel + timestamp is recorded in OUTREACH.md"
    - "A 30-minute interview protocol exists in INTERVIEW-PROTOCOL.md with the 4-section structure from RESEARCH.md section G"
    - "At least 2 of the 4 users have completed a recorded interview (voice or chat) and the notes are filed in INTERVIEW-NOTES.md with structured sections (stack, problem, experience, forward)"
    - "Any REQUIREMENTS edits suggested by interview findings are surfaced to Wes in the SUMMARY — NOT silently applied"
  artifacts:
    - path: ".planning/research/OUTREACH.md"
      provides: "Personal outreach ledger with message drafts + delivery channel + sent/responded status for all 4 users"
      contains: "Lief"
    - path: ".planning/research/INTERVIEW-PROTOCOL.md"
      provides: "30-minute interview protocol with 4 sections: warm-up, problem, experience, forward"
      contains: "30-minute"
    - path: ".planning/research/INTERVIEW-NOTES.md"
      provides: "Interview findings for ≥2 users, structured by the protocol sections"
      contains: "Stack"
  key_links:
    - from: ".planning/research/OUTREACH.md"
      to: "GitHub issue/PR threads on RyanTJoy, elpolini, joryirving, jsidhu activity"
      via: "linked URLs in each outreach row so the response thread is reachable"
      pattern: "https://github.com"
    - from: ".planning/research/INTERVIEW-NOTES.md"
      to: "INTERVIEW-PROTOCOL.md section numbers"
      via: "each interview entry follows the 4-section structure"
      pattern: "Section [1234]"
---

<objective>
Run DashClaw's first-ever user research pass. The four real users identified in `.planning/research/SIGNAL.md` — Lief (RyanTJoy), Elpolini, Jory Irving, Jasmeet Sidhu — have never been contacted, thanked, or interviewed. This plan turns that zero into "all 4 thanked, ≥2 interviewed, findings written up."

**This plan is not autonomous.** Tasks 2 and 4 are human actions Wes performs via GitHub and during real calls. The AI executor scaffolds the documents, drafts the message content, and structures the note-taking template. Wes hits send, runs the interviews, and fills in the findings.

Purpose: convert USR-01 and USR-02 from intentions into filed artifacts, closing ROADMAP Phase 1 success criterion #5.

Output: `.planning/research/OUTREACH.md` (ledger + draft messages), `.planning/research/INTERVIEW-PROTOCOL.md` (30-min protocol), `.planning/research/INTERVIEW-NOTES.md` (findings template with ≥2 real interview entries).
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/REQUIREMENTS.md
@.planning/ROADMAP.md
@.planning/research/SIGNAL.md
@.planning/phases/01-foundation/01-RESEARCH.md
</context>

<tasks>

<task type="auto">
  <name>Task 1: Scaffold OUTREACH.md with per-user message drafts + delivery channels</name>
  <files>.planning/research/OUTREACH.md</files>
  <read_first>
    - .planning/research/SIGNAL.md (full file — all 4 user profiles, their actual commits/issues, the verbatim commit messages RESEARCH.md already quoted)
    - .planning/phases/01-foundation/01-RESEARCH.md sections E and F (contact info table + tone / channel priority)
  </read_first>
  <action>
    Create `.planning/research/OUTREACH.md` with the following exact structure (use this as the template — fill in the real message drafts, do not leave placeholders):

    ```markdown
    # DashClaw Personal Outreach Ledger

    **Created:** {today's date}
    **Purpose:** First-ever personal outreach to the four real users identified in SIGNAL.md. Closes USR-01.
    **Delivery rule:** GitHub only. None of the 4 users have public email, Twitter, or blog URLs (VERIFIED in RESEARCH.md section E).

    ---

    ## Response tracking

    | User | Channel | Sent | Response | Interview scheduled? |
    |---|---|---|---|---|
    | Lief (RyanTJoy) | GitHub issue comment | ☐ | — | — |
    | Elpolini | GitHub issue comment | ☐ | — | — |
    | Jory Irving (joryirving) | Comment on issue #18 | ☐ | — | — |
    | Jasmeet Sidhu (jsidhu) | Comment on merged PR #21 | ☐ | — | — |

    Set a 2-week response window. If no reply by {today+14}, mark as "sent-no-reply" and proceed.

    ---

    ## 1. Lief (GitHub: RyanTJoy) — LAN self-hoster

    **Channel:** Open a new issue in the upstream `DashClaw` repo titled "Thank you for your fork contributions — @RyanTJoy". @mention `@RyanTJoy` so GitHub notifies them.

    **Alt channel (if the new-issue approach feels off):** Comment on issue #71 (the lucide-react issue) with a thank-you noting their fork work. Still @mentions them.

    **Draft message (≤100 words, dev-to-dev tone):**

    > Hey @RyanTJoy — I'm Wes, I built DashClaw. I just spent some time reading through your fork at RyanTJoy/DashClaw, specifically `fa268c3`, `108be08`, and `49c8ae3`. Getting DashClaw running on a plain-HTTP LAN instance should not require you to silently rewrite half the CSP/cookie stack, and the fact that you did anyway — cleanly — is genuinely appreciated. I'm pulling those fixes upstream this week, with your co-author credit attached.
    >
    > I'd love 20 minutes of your time. No agenda beyond "what were you actually trying to do with DashClaw, and where did it fail you?" Zero pressure if you're busy. If you're up for it, just drop a preferred channel (email/Discord/jitsi/whatever) and a rough window.
    >
    > — Wes

    **Context to keep in mind during the conversation (do not put in the message):**
    - Lief is running DashClaw at `http://192.168.x.x:3000` on their own hardware — classic homelab signal (SIGNAL.md)
    - Their fix pattern (surgical, rooted in debugging the actual symptom) indicates senior-engineer-level work
    - They never opened a PR — classic homelab dev behavior. Be respectful of their preference for not engaging with upstream

    ---

    ## 2. Elpolini (GitHub: elpolini) — Self-host compat hardener

    **Channel:** Open a new issue in upstream titled "Thank you for your fork contributions — @elpolini". @mention `@elpolini`.

    **Draft message:**

    > Hey @elpolini — Wes from DashClaw. I read through your fork at elpolini/DashClaw this week. Your `dbf5463` (self-host + legacy schema compat) is doing real work — especially `migrate-api-keys-compat.mjs` and the `information_schema.columns` fallbacks in `guard/route.js` and `keys/route.js`. That's the kind of compat shim you only write when upgrading DashClaw has burned you personally. I'm porting the core changes upstream this week with your co-author credit.
    >
    > I'd love 20 minutes to ask you what your DashClaw setup looks like and what the upgrade path broke for you the first time. Totally optional. If you're up for it, just tell me a channel and a rough window.
    >
    > — Wes

    **Context for the conversation:**
    - Elpolini clearly upgraded from an older schema and got burned — find out WHICH version they came from
    - They cared about `docs/prompts` paths being configurable via env overrides — that signals a non-standard layout, probably alongside other self-hosted services
    - Ask whether they're running alongside Tailscale, Authentik, or similar homelab infra

    ---

    ## 3. Jory Irving (GitHub: joryirving) — Authentik / homelab user

    **Channel:** Add a new comment on [issue #18](https://github.com/ucsandman/DashClaw/issues/18) (the Authentik OIDC request Jory filed). @mention `@joryirving`.

    **Draft message:**

    > Hey @joryirving — Wes here. It's been {N} months since #18 and #26 and I realized I never actually followed up properly. Authentik support shipped the same day you asked, and the OIDC redirect fix landed the day after — because of you. Thank you.
    >
    > I'm running a first user-research pass on DashClaw and I'd love 20 minutes with you specifically. Your profile says "SRE/Devops/Kubernetes Jockey" and your Authentik request tells me everything I need to know about the stack you're running. I'd just want to hear what DashClaw fits into, and where the fit is rough. If you're open to it, any channel works — reply here and I'll send you a Calendly / jitsi / whatever suits you.
    >
    > — Wes

    **Context:**
    - Jory is the strongest validation of the homelab hypothesis — Authentik is a dead giveaway
    - If they say yes, prioritize this interview. It's the highest signal about the self-host audience

    ---

    ## 4. Jasmeet Sidhu (GitHub: jsidhu) — Upstream PR contributor

    **Channel:** Add a new comment on [PR #21](https://github.com/ucsandman/DashClaw/pull/21) (the `crypto TDZ` fix Jasmeet merged). @mention `@jsidhu`.

    **Draft message:**

    > Hey @jsidhu — Wes. PR #21 was a clean fix, and I'm realizing I never thanked you properly outside the merge comment. The const-shadowing crypto TDZ bug was a landmine and you walked in, found it, and fixed it without any back-and-forth.
    >
    > I'm doing a first user-research pass on DashClaw and would love 20 minutes with you. No agenda beyond "what were you actually trying to do with DashClaw the day you hit that bug?" Zero pressure if you're busy. If you're open to it, reply here with a channel and a rough window.
    >
    > — Wes

    **Context:**
    - Jasmeet was running the local-auth path — same pattern as everyone else in the data
    - Lower-priority interview than Jory but still worth 20 min
    - Their fix suggests they're a production-grade engineer, not a hobbyist — ask what kind of agent they were governing

    ---

    ## Notes on outreach hygiene

    - Send at most 1 message per user. Do not follow up until the 2-week window expires.
    - Do NOT ask a list of questions in the initial message. One ask: "20 minutes of your time."
    - Do NOT link the interview protocol in the initial message. Share it only if they say yes and ask for an agenda.
    - If any of them ask "what is this for?" — be honest: "First user-research pass DashClaw has ever run. I'm trying to understand who actually uses it, because the real answer and the marketing answer have drifted apart."
    ```
  </action>
  <verify>
    <automated>test -f .planning/research/OUTREACH.md && grep -c '@RyanTJoy\|@elpolini\|@joryirving\|@jsidhu' .planning/research/OUTREACH.md | xargs -I{} test {} -ge 4</automated>
  </verify>
  <acceptance_criteria>
    - `.planning/research/OUTREACH.md` exists
    - Contains all four handles: `@RyanTJoy`, `@elpolini`, `@joryirving`, `@jsidhu`
    - Contains a `## Response tracking` section with a 4-row table
    - Each user has a `## N. <Name>` section with both a `**Channel:**` line and a `**Draft message:**` block
    - Each draft message is ≤100 words (counted on the quoted block only)
    - No other files modified (check `git status`)
  </acceptance_criteria>
  <done>OUTREACH.md scaffolded, ready for Wes to hit send.</done>
</task>

<task type="checkpoint:human-action" gate="blocking">
  <name>Task 2: Wes sends outreach to all 4 users via GitHub</name>
  <what-needs-doing>
    Wes personally sends the four outreach messages drafted in `.planning/research/OUTREACH.md`. This is a human action — the AI executor MUST NOT send messages on Wes's behalf, because they'd be attributed to Wes's GitHub account from an AI and the tone would feel off.
  </what-needs-doing>
  <how-to-execute>
    1. Open `.planning/research/OUTREACH.md`.
    2. For each of the 4 users, go to the channel specified in `**Channel:**` (e.g., "Comment on issue #18" → open https://github.com/ucsandman/DashClaw/issues/18).
    3. Copy the `**Draft message:**` block verbatim (or edit to taste — the draft is a starting point, not a script).
    4. Send the message. @mention the user's handle exactly as specified.
    5. In `OUTREACH.md`, update the response tracking table: change ☐ to ☑ in the "Sent" column, paste the direct URL to the comment/issue in a new column or inline note.
    6. Record the timestamp (e.g., `Sent: 2026-04-11T14:30Z`).
    7. Commit the updated OUTREACH.md with message `docs(research): send first user outreach pass (USR-01)`.

    **Time estimate:** 15-20 minutes total for all 4 messages.

    **If GitHub notifications might not reach Lief or Elpolini** (they're fork-only contributors): that risk is acknowledged in RESEARCH.md Gotcha #4. Send anyway and set the 2-week response window.
  </how-to-execute>
  <resume-signal>Type "sent" after the 4 messages have been posted and OUTREACH.md is updated and committed. Or type "partial: sent X of 4" if some failed.</resume-signal>
</task>

<task type="auto">
  <name>Task 3: Scaffold INTERVIEW-PROTOCOL.md and INTERVIEW-NOTES.md templates</name>
  <files>.planning/research/INTERVIEW-PROTOCOL.md, .planning/research/INTERVIEW-NOTES.md</files>
  <read_first>
    - .planning/phases/01-foundation/01-RESEARCH.md section G (4-section 30-minute protocol structure)
    - .planning/research/SIGNAL.md (per-user context to pre-load into the protocol for each user)
  </read_first>
  <action>
    1. Create `.planning/research/INTERVIEW-PROTOCOL.md`:

    ```markdown
    # DashClaw User Interview Protocol

    **Created:** {today}
    **Purpose:** 30-minute interview protocol for DashClaw user research. Used for USR-02 (Phase 1) and every subsequent user interview.
    **Source:** `.planning/phases/01-foundation/01-RESEARCH.md` section G.

    ---

    ## Before the call

    - Confirm channel (Zoom / Jitsi / Discord call / whatever the user prefers)
    - Open a blank section in `INTERVIEW-NOTES.md` with the user's name as a header
    - Set a 30-minute timer visible to you (not the user)
    - **Do not record audio unless the user explicitly offers.** Take written notes live.

    ## The 30-minute structure

    ### Section 1 — Warm-up (5 min)

    Goal: get them talking, learn what they're actually building.

    - "Before we talk about DashClaw — what are you building right now? What's your stack?"
    - (Listen. Let them go 3-4 minutes. Don't interrupt.)
    - Follow-up probe if they're terse: "Is this a personal project or work or both?"

    ### Section 2 — The problem (10 min)

    Goal: find out what pain drove them to DashClaw.

    - "What made you try DashClaw? Walk me through the day you found it — what were you doing, what were you searching for?"
    - Follow-up: "What did you *think* DashClaw was going to do for you, before you tried it?"
    - Follow-up: "Before DashClaw, how were you handling [the problem they named]?"

    ### Section 3 — The experience (10 min)

    Goal: find out what actually worked, what broke, and what they had to fix themselves.

    - "What worked the first time? What broke?"
    - "What did you end up having to fix yourself?" (Be specific — if they have commits on a fork, reference them: "I saw you pushed `fa268c3` — what was that debugging like?")
    - "What made you stop using it, if you did?" (Or: "How often do you come back to it now?")

    ### Section 4 — Forward (5 min)

    Goal: find out what they want next, without anchoring on what you're building.

    - "If DashClaw could do ONE more thing for you right now, what would it be?"
    - (Do NOT pitch Claude Code integration. Do NOT pitch homelab positioning. Let them say it unprompted if it's real.)
    - "Is there anything I should have asked and didn't?"

    ## After the call

    - Write up the notes in `INTERVIEW-NOTES.md` within 30 minutes of hanging up (memory fades fast)
    - Extract 1-3 themes per interview, quote the user verbatim on at least one
    - If anything the user said contradicts or invalidates a REQUIREMENTS item, note it in the interview section — do NOT silently edit REQUIREMENTS

    ## Per-user pre-interview notes (what SIGNAL.md tells us to listen for)

    **Lief (RyanTJoy):** LAN homelab on `http://192.168.x.x:3000`. Ask: what hardware, what other services (Tailscale, Authentik?), what agent were they governing at home.

    **Elpolini:** Upgraded from older schema, cared about configurable `docs/prompts` paths. Ask: which DashClaw version they came from, what the upgrade break felt like, what other self-hosted tools they run alongside.

    **Jory Irving:** Authentik user. Ask: what their Authentik setup looks like, what else uses it, whether DashClaw was trying to slot into a Kubernetes workflow (bio says SRE/K8s).

    **Jasmeet Sidhu:** Running the local-auth path, found a real crypto bug. Ask: what agent they were governing, whether DashClaw was for a work project or a personal one.

    ## Anti-patterns (do NOT)

    - Do NOT ask leading questions ("Don't you think the homelab angle makes sense?")
    - Do NOT mention Claude Code or the pivot hypothesis in sections 1-3
    - Do NOT pitch the roadmap. You're listening, not selling.
    - Do NOT promise features. If they ask for something, say "I'll write that down" — nothing stronger.
    ```

    2. Create `.planning/research/INTERVIEW-NOTES.md` as a skeleton with empty per-user sections so Wes can fill them in as interviews happen:

    ```markdown
    # DashClaw User Interview Notes

    **Purpose:** Findings from user interviews conducted per `INTERVIEW-PROTOCOL.md`. Closes USR-02 when ≥2 interviews are completed.

    **Source:** Protocol `.planning/research/INTERVIEW-PROTOCOL.md` (30-min, 4-section).

    ---

    ## How to use this file

    1. After each interview, add a new `## Interview {N}: {Name} — {date}` section below.
    2. Structure each entry by the 4 protocol sections (Stack, Problem, Experience, Forward).
    3. Quote the user verbatim on at least one point per interview.
    4. Under the interview, add a short "Themes" list (1-3 bullets).
    5. Do NOT silently edit REQUIREMENTS.md based on interview findings. Surface suggested edits in the SUMMARY for Wes to approve.

    ---

    ## Interview template (copy for each new interview)

    ```
    ## Interview {N}: {Name} ({GitHub handle}) — YYYY-MM-DD
    **Duration:** 30 min
    **Channel:** {Zoom/Jitsi/Discord/etc}

    ### Section 1 — Stack
    - What they're building:
    - Stack:
    - Personal vs. work:

    ### Section 2 — Problem
    - What drove them to DashClaw:
    - What they thought it would do:
    - How they were handling the problem before:

    ### Section 3 — Experience
    - What worked:
    - What broke:
    - What they fixed themselves:
    - Why they stopped / how often they use it now:

    ### Section 4 — Forward
    - One thing they want next:
    - Anything I should have asked:

    ### Themes
    -
    -

    ### Suggested REQUIREMENTS edits (surface, do NOT apply)
    -
    ```

    ---

    ## Interviews completed

    _(Fill in as interviews happen. ≥2 required to close USR-02.)_
    ```

    Leave the `## Interviews completed` section empty — Tasks 4 and 5 below (human-action) populate it.
  </action>
  <verify>
    <automated>test -f .planning/research/INTERVIEW-PROTOCOL.md && test -f .planning/research/INTERVIEW-NOTES.md && grep -q "Section 1 — Warm-up" .planning/research/INTERVIEW-PROTOCOL.md && grep -q "Section 4 — Forward" .planning/research/INTERVIEW-PROTOCOL.md && grep -q "Interview template" .planning/research/INTERVIEW-NOTES.md</automated>
  </verify>
  <acceptance_criteria>
    - Both files exist
    - `INTERVIEW-PROTOCOL.md` contains the four section headers: `Section 1 — Warm-up`, `Section 2 — The problem`, `Section 3 — The experience`, `Section 4 — Forward`
    - `INTERVIEW-PROTOCOL.md` contains per-user pre-interview notes for all 4 users (Lief, Elpolini, Jory, Jasmeet)
    - `INTERVIEW-NOTES.md` contains a reusable interview template with the 4 sections + Themes + "Suggested REQUIREMENTS edits" subsection
    - `INTERVIEW-NOTES.md` `## Interviews completed` section exists but is empty (no fake entries)
  </acceptance_criteria>
  <done>Protocol and notes templates ready for real interviews.</done>
</task>

<task type="checkpoint:human-action" gate="blocking">
  <name>Task 4: Wes conducts ≥2 interviews and fills INTERVIEW-NOTES.md</name>
  <what-needs-doing>
    Wes runs at least 2 live 30-minute interviews with users who responded positively to Task 2. This is a human action — the AI executor MUST NOT simulate, hallucinate, or generate interview content. The entire point of user research is real words from real users.

    Expected wait: up to 2 weeks from the Task 2 send date. If fewer than 2 users respond within 2 weeks, the plan completes partially and that gap is surfaced in the SUMMARY.
  </what-needs-doing>
  <how-to-execute>
    1. When a user replies to the outreach, schedule the interview on whatever channel they prefer (Zoom, Jitsi, Discord voice, even written async chat counts if 30 minutes of real back-and-forth).
    2. During each interview: follow `INTERVIEW-PROTOCOL.md`. Keep the 4-section / 30-minute structure. Take notes live.
    3. Within 30 minutes of the call ending: open `INTERVIEW-NOTES.md`, copy the template from the "Interview template" section, fill in all 4 sections with what the user actually said. Quote verbatim at least once per interview.
    4. Write 1-3 themes at the bottom of each interview entry.
    5. If any user said something that invalidates a REQUIREMENTS item, add it to the "Suggested REQUIREMENTS edits (surface, do NOT apply)" list. DO NOT edit REQUIREMENTS.md as part of this plan — that's a later decision by Wes.
    6. Repeat for interview #2.
    7. Update `OUTREACH.md` to mark "Interview scheduled?" column appropriately (✅ completed, or a date if scheduled-but-not-done).
    8. Commit both `INTERVIEW-NOTES.md` and `OUTREACH.md` with message `docs(research): file first user interview notes (USR-02)`.

    **Minimum success:** 2 filled interview sections in `INTERVIEW-NOTES.md`. 3-4 is better but 2 closes USR-02 per the ROADMAP Phase 1 criterion.

    **If fewer than 2 users respond in 2 weeks:** DO NOT fake the gap. File whatever interviews DID happen, add a note in INTERVIEW-NOTES.md stating "X of 4 users responded within 2-week window; USR-02 closed partially at Y completed interviews; unresponsive users: Z." Phase 1 SUMMARY flags this for Wes.
  </how-to-execute>
  <resume-signal>Type "done: N interviews filed" where N is the actual count, OR "partial: only N responded in 2-week window" if the 2-user minimum wasn't hit.</resume-signal>
</task>

</tasks>

<verification>
- `.planning/research/OUTREACH.md` exists, contains drafts for all 4 users, Wes has updated the "Sent" column to ☑ for each with a real GitHub URL and timestamp
- `.planning/research/INTERVIEW-PROTOCOL.md` exists with the 4-section structure and per-user pre-interview notes
- `.planning/research/INTERVIEW-NOTES.md` contains at least 2 completed interview entries (or a partial-completion note if the 2-week window returned <2 responses)
- All 3 files are committed
- No files outside `files_modified` were touched
</verification>

<success_criteria>
- USR-01: All 4 users received personal outreach via GitHub with timestamps recorded in OUTREACH.md
- USR-02: ≥2 user interviews completed and filed in INTERVIEW-NOTES.md with verbatim quotes, themes, and suggested-REQUIREMENTS-edits (or a documented partial if responses were insufficient)
- Every interview entry follows the 4-section protocol structure
- No REQUIREMENTS.md edits applied silently — all suggestions surface in SUMMARY for Wes to review
</success_criteria>

<output>
After completion, create `.planning/phases/01-foundation/01-02-SUMMARY.md` including:
- USR-01 status (all 4 sent? which timestamps? any non-delivery?)
- USR-02 status (how many interviews completed? under/at/over the 2-minimum?)
- Consolidated themes across interviews (1-5 bullets)
- Suggested REQUIREMENTS.md edits (for Wes to approve/reject separately — this plan does NOT apply them)
- Positioning-validation signal (did interviews support or contradict the homelab/Claude-Code-beachhead direction in PROJECT.md?)
</output>
