---
name: pstack-office-hours
preamble-tier: 3
version: 0.3.0
description: |
  Wrap gstack `/office-hours` and post the result to the project's pinned
  Vision GitHub Issue via GitHub MCP. One-way data flow: gstack does its
  strategic brainstorming methodology, pstack imports the result into a
  team-shared GitHub Issue. gstack's local archive at ~/.gstack/projects/
  is left intact. Requires Claude Code + gstack + GitHub MCP.
  Use when asked to "brainstorm the vision", "office hours for this project",
  "import office-hours to vision", "update project vision", or when starting
  to define what a project is about.
triggers:
  - /pstack-office-hours
  - import office hours
  - update project vision
  - brainstorm project vision
allowed-tools:
  - Bash
  - Read
  - Write
  - Edit
  - Skill
---

# pstack-office-hours

Strategic brainstorming via gstack `/office-hours`, with the result posted
to a project-pinned Vision GitHub Issue. The Vision Issue is editable by
anyone with repo write access via the GitHub web UI — no PR ceremony.

## Dependencies

- **Claude Code** — gstack is a Claude Code skill; this skill orchestrates it.
- **gstack** — installed at `~/.claude/skills/gstack/`.
- **GitHub MCP server** — for all GitHub operations. No `gh` CLI required.

If running from Claude Desktop, this skill cannot invoke gstack. Use the
GitHub web UI to author the Vision Issue directly with the
`templates/vision.md` content; come back to `/pstack-office-hours` later
to import a gstack design doc.

## Args

```
/pstack-office-hours                  # default: invoke gstack interactively, then import
/pstack-office-hours --import-latest  # skip gstack /office-hours; import most recent existing doc
```

## Pre-conditions

Before running this skill, verify:

1. Current directory is a project root with `.pstack-version` (i.e.,
   `pstack-init` has been run).
2. GitHub MCP is loaded — call `mcp__github__get_me` to verify auth.
3. The project has a GitHub remote: `git remote get-url origin`.
4. gstack is installed: `test -d ~/.claude/skills/gstack`.

If any check fails, surface a clear error and stop.

## Workflow

### 1. Capture context

```bash
# Confirm we're in a pstack project
test -f .pstack-version || { echo "Not a pstack project. Run pstack-init first."; exit 1; }

# Project name (from package.json or directory)
PROJECT_NAME=$(node -e "console.log(require('./package.json').name||'')" 2>/dev/null || basename "$PWD")

# Repo owner/name (from git remote)
ORIGIN_URL=$(git remote get-url origin)
# Parse owner/repo from URL — format like https://github.com/owner/repo.git or git@github.com:owner/repo.git

# gstack's slug for this project (matches gstack's own logic)
SLUG=$(~/.claude/skills/gstack/bin/gstack-slug 2>/dev/null | grep -oE '[a-zA-Z0-9_-]+/[a-zA-Z0-9_-]+' | head -1 | tr '/' '-')
SLUG=${SLUG:-$(basename "$PWD")}

# Snapshot existing gstack design docs (so we know which is NEW)
GSTACK_DIR="${GSTACK_HOME:-$HOME/.gstack}/projects/$SLUG"
mkdir -p "$GSTACK_DIR"
SNAPSHOT_LIST=$(ls -1 "$GSTACK_DIR"/*-design-*.md 2>/dev/null | sort)
```

### 2. Invoke gstack /office-hours interactively (skipped with `--import-latest`)

If `--import-latest` flag is set, skip this step entirely and proceed to Step 3.

Otherwise, hand control to gstack. The user does the brainstorm. Gstack writes
its design doc into `~/.gstack/projects/<slug>/`.

```
Use the Skill tool to invoke `office-hours` (gstack).
Let gstack run interactively — do not summarize or short-circuit it.
```

When gstack returns, proceed to step 3.

### 3. Find the design doc to import

**Default mode** (Step 2 was run — looking for the file gstack just wrote):

```bash
NEW_DOC=$(ls -1t "$GSTACK_DIR"/*-design-*.md 2>/dev/null | head -1)

if [ -z "$NEW_DOC" ]; then
  echo "No design doc found. Did gstack /office-hours complete?"
  exit 1
fi

# Verify it's NEW vs the snapshot taken in Step 1
if echo "$SNAPSHOT_LIST" | grep -qF "$NEW_DOC"; then
  echo "No NEW design doc — gstack didn't write a new file."
  exit 1
fi
```

**`--import-latest` mode** (skipping Step 2 — picking up an existing doc):

```bash
NEW_DOC=$(ls -1t "$GSTACK_DIR"/*-design-*.md 2>/dev/null | head -1)
[ -z "$NEW_DOC" ] && { echo "No existing design docs at $GSTACK_DIR."; exit 1; }
```

If user declines this doc, list other available docs and let them pick.

### 4. Distill (or use raw)

Ask the user:

> "Gstack produced a design doc at: $NEW_DOC
>
> The Vision Issue body should be tighter than the raw brainstorm. Two options:
>   1. Distill the raw output into the Vision template structure (recommended)
>   2. Use the raw output as-is (longer, less structured)"

If 1: read `${CLAUDE_SKILL_DIR}/../../templates/vision.md`, fill in placeholders
by extracting answers to the six questions (Who/Problem/Why now/Narrowest
wedge/Future-fit/Out of scope) from the raw doc. Show the distilled version
to the user; ask for approval/edits.

If 2: use the raw doc content with minimal wrapping (vision template's
`> Living document` callout at top, "Where to find related artifacts" at bottom).

In both cases, replace template placeholders:
- `{{PROJECT_NAME}}` → `$PROJECT_NAME`
- `{{DATE}}` → today's date (YYYY-MM-DD)

Hold the final body content as a string for the next step.

### 5. Find or create the Vision Issue via MCP

Search for an existing Vision Issue using **`mcp__github__search_issues`**:
- query: `repo:<owner>/<repo> label:vision is:open`
- limit: 5

Identify any open issue labeled `vision`. Fall back to title-match
(`Vision: $PROJECT_NAME`) for legacy issues without the label.

**If EXISTING:** ask the user before overwriting:

> "A Vision Issue already exists at #N. Three options:
>   1. Replace its body with the new content
>   2. Append new content as a comment (keeps existing body)
>   3. Skip — show me the new content but don't update GitHub"

- If 1: call **`mcp__github__issue_write`** with operation=`update`, issue number from search, body=new content.
- If 2: call **`mcp__github__add_issue_comment`** with the new content.
- If 3: print body content to stdout, exit.

**If no existing Vision Issue:** create one.

Note on labels: GitHub MCP doesn't expose a `create_label` operation. The
`vision` label must exist on the repo before the first run. If creation
fails with "label not found", surface a clear error:

> "Create a 'vision' label in the repo settings (color #5319E7 recommended),
> then re-run. Devs with `gh` CLI can: `gh label create vision --color '5319E7'`."

Call **`mcp__github__issue_write`** with:
- operation: `create`
- title: `Vision: $PROJECT_NAME`
- body: the final body content
- labels: `["vision"]`
- issue type: `Epic` (or omit if the repo doesn't use issue types)

Save the returned issue number and URL.

### 6. Pin the Vision Issue

GitHub MCP doesn't expose a `pin_issue` tool. Print instructions for the user:

> "Vision Issue created at <URL>. To pin it (so collaborators see it at the
> top of the Issues page):
>
> 1. Open the issue
> 2. Click the three-dot menu (top right) → 'Pin issue'
>
> Up to 3 issues can be pinned per repo. Pinning is a one-time action per Vision."

### 7. Append archive comment

To preserve the raw brainstorm history (gstack's value-add), call
**`mcp__github__add_issue_comment`** with:

- issue number: from Step 5
- body content (template):

```markdown
## Office-hours session — YYYY-MM-DD

Source: `<path to gstack design doc>`

<details>
<summary>Raw brainstorm output (click to expand)</summary>

<contents of $NEW_DOC>

</details>
```

This gives the team access to the full raw thinking without bloating the
issue body.

### 8. Print the result

```
✓ Vision imported.
  Issue:    https://github.com/<owner>/<repo>/issues/N
  Label:    vision
  Pinned:   [user action required — see Step 6]
  Source:   <NEW_DOC path> (preserved as comment)

Next: when /pstack-plan is invoked, it will discover this Vision Issue
automatically (by label) and load it as strategic context.
```

## How other skills discover the Vision

Other pstack skills (`/pstack-plan`, etc.) find the Vision Issue via
**`mcp__github__search_issues`** with query
`repo:<owner>/<repo> label:vision is:open`, returning the first open issue.
This replaces the earlier pattern of writing the Vision URL into the
project's CLAUDE.md — the `vision` label is the discovery mechanism. Works
equally in Claude Code and Claude Desktop.

## When Vision already exists (re-run scenario)

If the user runs `/pstack-office-hours` again later:
- Step 5's "existing issue found" branch handles it
- Recommended: choose option 2 (append as comment) for incremental refinements;
  option 1 (replace) only when doing a full strategic reset

## Failure modes and recovery

| Failure | Response |
|---|---|
| gstack not installed | Halt, print install instruction |
| Not a pstack project (no `.pstack-version`) | Halt, suggest `pstack-init` |
| GitHub MCP not loaded | Halt, link install instructions |
| `mcp__github__get_me` fails | Halt, suggest re-auth via host config |
| No GitHub remote / ambiguous repo | Halt, ask user for owner/repo |
| gstack /office-hours cancelled by user | Detect via "no new file" check (step 3); halt cleanly |
| `--import-latest` but no existing doc | Halt, suggest running without flag to invoke gstack interactively |
| Issue creation fails (`vision` label missing) | Surface the create-label instruction (above) |
| Issue creation fails (permissions) | Halt, print body content so user can paste manually via web UI |

## Do not

- Do not call `gh` CLI — use GitHub MCP.
- Do not delete or move the gstack original. It's gstack's archive.
- Do not auto-commit anything to git. This skill writes only to GitHub.
- Do not overwrite an existing Vision body without explicit user confirmation.
- Do not modify gstack's behavior — let `/office-hours` run as designed.
- Do not try to keep gstack's local file in sync with the Vision Issue.
  They diverge over time and that's fine.
- Do not write the Vision URL into the project's CLAUDE.md — the `vision`
  label is the discovery mechanism.

## See also

- `templates/vision.md` — the body template applied to the Vision Issue
- `IDEAS.md` — captures the architectural reasoning behind separating
  gstack's local files from team-shared GitHub state
- gstack `/office-hours` — the upstream brainstorming methodology
