From 4dea228ee5dab06641f42b86b999925ba120550d Mon Sep 17 00:00:00 2001 From: tarcode2004 <66574422+tarcode2004@users.noreply.github.com> Date: Wed, 25 Feb 2026 13:58:55 -0500 Subject: [PATCH 1/3] Claude Guidance --- .claude/guides/README.md | 7 + .claude/guides/ai-assisted-workflow.md | 69 ++++++++ .claude/rules/branch-naming.md | 20 +++ .claude/rules/commit-conventions.md | 18 ++ .claude/rules/pr-conventions.md | 6 + .claude/skills/github-issues/SKILL.md | 90 ++++++++++ .claude/skills/iteration-planning/SKILL.md | 57 +++++++ .claude/skills/pr-workflow/SKILL.md | 80 +++++++++ .claude/skills/pr-workflow/reference.md | 73 +++++++++ .claude/skills/retrospective/SKILL.md | 60 +++++++ .claude/skills/skill-authoring/SKILL.md | 172 ++++++++++++++++++++ .claude/skills/skill-authoring/reference.md | 154 ++++++++++++++++++ CLAUDE.md | 90 ++++++++++ 13 files changed, 896 insertions(+) create mode 100644 .claude/guides/README.md create mode 100644 .claude/guides/ai-assisted-workflow.md create mode 100644 .claude/rules/branch-naming.md create mode 100644 .claude/rules/commit-conventions.md create mode 100644 .claude/rules/pr-conventions.md create mode 100644 .claude/skills/github-issues/SKILL.md create mode 100644 .claude/skills/iteration-planning/SKILL.md create mode 100644 .claude/skills/pr-workflow/SKILL.md create mode 100644 .claude/skills/pr-workflow/reference.md create mode 100644 .claude/skills/retrospective/SKILL.md create mode 100644 .claude/skills/skill-authoring/SKILL.md create mode 100644 .claude/skills/skill-authoring/reference.md create mode 100644 CLAUDE.md diff --git a/.claude/guides/README.md b/.claude/guides/README.md new file mode 100644 index 0000000..5242047 --- /dev/null +++ b/.claude/guides/README.md @@ -0,0 +1,7 @@ +# Guides + +Brief "How To" guides that explain both _what_ and _why_ for each topic. Aimed at students and anyone picking up this template for the first time. Each guide is ~100 lines — enough to understand the concept and get productive, not a reference manual. + +| Guide | What it covers | +| -------------------------------------------------- | --------------------------------------------------------------------------------- | +| [AI-Assisted Workflow](ai-assisted-workflow.md) | Using Claude Code skills to plan iterations, create issues, branch, commit, and PR | diff --git a/.claude/guides/ai-assisted-workflow.md b/.claude/guides/ai-assisted-workflow.md new file mode 100644 index 0000000..6a593cd --- /dev/null +++ b/.claude/guides/ai-assisted-workflow.md @@ -0,0 +1,69 @@ +# AI-Assisted Workflow Guide + +This guide walks you through using Claude Code and the skills in this repo to follow the team development workflow. Each section matches a phase of your iteration cycle. + +## Prerequisites + +- GitHub CLI authenticated: `gh auth login` +- Claude Code installed and working +- `docs/team-agreement.md` and `docs/product-requirements.md` are updated and committed to the repo + +## Step 1: Create GitHub Issues + +Ask Claude to turn the plan into issues: + +```plaintext +> Read the iteration 1 plan and create GitHub issues for each requirement + and task. The team members are listed in docs/team-agreement.md. + Use the "Iteration 1" milestone. +``` + +Check GitHub to verify: correct labels, milestone, assignees, and acceptance criteria on each issue. + +## Step 2: Work on an Issue (Branch, Commit, PR) + +> **Note:** Before you can work on actual features, you need to scaffold your tech stack and update `README.md` and `CLAUDE.md` with your project's setup, commands, and architecture. Without this, Claude won't know how to generate code that fits your project. + +**Branch:** Pick an issue and create a branch: + +```plaintext +> Create a branch for issue #3 (task: setup CI pipeline). I am . +``` + +Claude creates a branch following the naming convention: `/task/issue-3-setup-ci-pipeline` + +**Commit:** After making changes, commit with the issue reference: + +```plaintext +> Commit my changes +``` + +**PR:** Push and open a pull request: + +```plaintext +> /pr-workflow 3 +``` + +Claude verifies the branch name, checks diff size, pushes, and creates a PR with `Closes #3` and the PR template filled in. + +## Step 3: Retrospective + +At the end of an iteration, create the retrospective issue: + +```plaintext +> /retrospective 1 +``` + +Claude creates a GitHub issue with the right labels (`task` + `retrospective`), milestone, and all team members assigned. The three sections (what went well, what didn't, lessons learned) are for the team to fill in — be specific and actionable. + +## What to Verify on GitHub + +After completing these steps, your repo should show: + +- **Milestone view** — all iteration issues in one place with open/closed status +- **Issue list** — features and tasks with correct labels and assignees +- **PR list** — PRs linked to issues with review status +- **Commit history** — every commit references an issue number +- **Branch list** — branches follow the naming convention + +The analytics scripts parse labels, branch names, and PR metadata. If conventions are not followed, your work won't be attributed to you. diff --git a/.claude/rules/branch-naming.md b/.claude/rules/branch-naming.md new file mode 100644 index 0000000..fb6c972 --- /dev/null +++ b/.claude/rules/branch-naming.md @@ -0,0 +1,20 @@ +# Branch Naming Convention + +When creating branches, ALWAYS follow this pattern: + +`//issue--` + +Where: + +- `author` is the GitHub username of the branch creator +- `type` matches the issue label: `feature`, `bug`, or `task` +- `number` is the GitHub issue number +- `short-description` is 2-4 lowercase words separated by hyphens + +Examples: + +- `asmith/feature/issue-5-user-authentication` +- `jdoe/bug/issue-12-fix-login-redirect` +- `mchen/task/issue-3-setup-ci-pipeline` + +Never push directly to master. Always create a branch and open a PR. diff --git a/.claude/rules/commit-conventions.md b/.claude/rules/commit-conventions.md new file mode 100644 index 0000000..a961eb3 --- /dev/null +++ b/.claude/rules/commit-conventions.md @@ -0,0 +1,18 @@ +# Commit Conventions + +When creating commits: + +1. Reference the issue number in the commit message: `Add file validation (#12)` +2. Use imperative mood in the subject line: "Add feature" not "Added feature" +3. Keep the subject line under 72 characters + +Examples: + +- `Add login form component (#5)` +- `Fix redirect loop on logout (#12)` +- `Set up CI pipeline (#6)` + +Do not co-sign the commit! For example, do not end the commit with something like this: + +Co-Authored-By: Claude Opus 4.6 + diff --git a/.claude/rules/pr-conventions.md b/.claude/rules/pr-conventions.md new file mode 100644 index 0000000..3d42c6f --- /dev/null +++ b/.claude/rules/pr-conventions.md @@ -0,0 +1,6 @@ +# Pull Request Conventions + +- Include `Closes #` or `Fixes #` in every PR body +- Keep PRs under ~400 changed lines +- Use merge commits only — never squash or rebase +- See the `pr-workflow` skill for full details and the collaborative feature branch flow diff --git a/.claude/skills/github-issues/SKILL.md b/.claude/skills/github-issues/SKILL.md new file mode 100644 index 0000000..4e18b79 --- /dev/null +++ b/.claude/skills/github-issues/SKILL.md @@ -0,0 +1,90 @@ +--- +name: github-issues +description: Create and manage GitHub issues following project conventions. Use when creating issues, managing issue labels, assigning issues, setting up milestones, or asking about issue conventions and requirements. +argument-hint: "issue title or number" +allowed-tools: + - Read + - Grep + - Glob + - "Bash(gh issue *)" + - "Bash(gh api *)" + - "Bash(gh label *)" +--- + +# GitHub Issues Skill + +## Related Skills + +- `iteration-planning` — creates issues from the task breakdown +- `pr-workflow` — PRs reference issues via `Closes #` + +## Creating Issues + +Every issue must have: + +1. **Descriptive title** — clear and concise +2. **Description** — what needs to be done and why +3. **Acceptance criteria** — checklist of testable criteria +4. **Label** — exactly one of: `feature`, `task`, or `bug` +5. **Milestone** — the current iteration (e.g., "Iteration 1") +6. **Assignees** — see ownership rules below + +## Labels + +The project uses these labels: + +- `feature` — new functionality +- `task` — development work that isn't a feature or bug +- `bug` — something that's broken +- `retrospective` — added alongside `task` for retrospective issues + +If labels don't exist yet, create them: + +```bash +gh label create feature --description "New functionality" --color 0E8A16 +gh label create task --description "Development task" --color 1D76DB +gh label create bug --description "Something is broken" --color D93F0B +gh label create retrospective --description "Iteration retrospective" --color FBCA04 +``` + +## Milestones + +Milestones are named "Iteration 1" through "Iteration 4". Create them if they don't exist: + +```bash +gh api repos/{owner}/{repo}/milestones -f title="Iteration 1" +``` + +## Issue Ownership + +- **Feature issues** — assign one owner + one supporting (up to three if the feature is large) +- **Task and bug issues** — assign one person (optional supporting) +- **Retrospective issues** — assign all team members + +If you contribute to an issue but aren't assigned, analytics won't attribute the work to you. + +## Creating Issues via CLI + +Read the matching template in `.github/ISSUE_TEMPLATE/` (feature.yml, task.yml, or bug.yml) and use its structure for the `--body`. Example: + +```bash +gh issue create \ + --title "Add search-by-title to items list endpoint" \ + --label "feature" \ + --milestone "Iteration 1" \ + --assignee "owner,supporting" \ + --body "## Description +Add a query parameter to the items endpoint that filters by title. + +## Acceptance Criteria +- [ ] Search is case-insensitive +- [ ] Empty query returns all items +- [ ] Tests added for all cases" +``` + +For task and bug issues, follow the same pattern using the corresponding template structure. + +## Rules + +- Only create issues for the **current** iteration — never for future ones +- Use the GitHub issue templates (feature, task, or bug) when creating from the UI diff --git a/.claude/skills/iteration-planning/SKILL.md b/.claude/skills/iteration-planning/SKILL.md new file mode 100644 index 0000000..6da361a --- /dev/null +++ b/.claude/skills/iteration-planning/SKILL.md @@ -0,0 +1,57 @@ +--- +name: iteration-planning +description: Create and manage iteration plans. Use when starting a new iteration, writing an iteration plan, breaking down requirements into tasks, planning sprint work, or asking about iteration plan format and structure. +argument-hint: "iteration number" +allowed-tools: + - Read + - Write + - Edit + - Grep + - Glob + - "Bash(gh issue *)" + - "Bash(gh api *)" +--- + +# Iteration Planning Skill + +## Related Skills + +- `github-issues` — create the issues from the task breakdown +- `retrospective` — close out the iteration after work is done + +## Process + +1. Read the template at `docs/iteration-plan-template.md` +2. Ask the user for the iteration number and requirements (or read from a PRD if available) +3. **Draft** `docs/iteration--plan.md` with the 3 required sections: + - **Requirements & Acceptance Criteria** — each requirement gets a title, description, and testable acceptance criteria checklist + - **Coordination & Design Decisions** — architecture choices, API contracts, shared interfaces, responsibilities, dependencies + - **Task Breakdown** — table of tasks with type, assignee(s), and issue number +4. **Ask the user to review the draft** — the team owns the final plan, not the AI. In particular: + - Are the acceptance criteria complete? Any edge cases missing? + - Do the coordination decisions (API contracts, schemas, shared interfaces) match what the team agreed on? + - Is the task breakdown realistic? Are assignments correct? +5. Incorporate feedback and finalize the plan + +## Timeline + +- **Iteration plan due:** Tuesday 6 PM of Week 1 +- **Iteration work period:** remainder of Week 1 + Week 2 +- **Retrospective due:** Monday end-of-day after the iteration ends + +## Guidelines + +- Each requirement must have clear, testable acceptance criteria +- Break requirements into issues that can be completed by 1-2 people +- Follow issue ownership rules from the `github-issues` skill (not a fixed number of assignees) +- Only create issues for the current iteration — never for future iterations +- Apply the correct label to each issue: `feature`, `task`, or `bug` +- Set the milestone to the current iteration (e.g., "Iteration 1") + +## After Planning + +Offer to create the GitHub issues from the task breakdown using the `github-issues` skill conventions: + +- Each issue gets a descriptive title, description, and acceptance criteria +- Apply the correct label and milestone +- Assign the correct team members diff --git a/.claude/skills/pr-workflow/SKILL.md b/.claude/skills/pr-workflow/SKILL.md new file mode 100644 index 0000000..ec9a36d --- /dev/null +++ b/.claude/skills/pr-workflow/SKILL.md @@ -0,0 +1,80 @@ +--- +name: pr-workflow +description: Create pull requests and manage the PR workflow. Use when creating a PR, reviewing PRs, managing feature branch merges, or asking about PR conventions, code review process, or the collaborative feature branch workflow. +argument-hint: "PR or issue number" +allowed-tools: + - Read + - Grep + - Glob + - "Bash(gh pr *)" + - "Bash(gh api *)" + - "Bash(git *)" +--- + +# PR Workflow Skill + +## Related Skills + +- `github-issues` — PRs must reference an issue via `Closes #` +- Branch naming rules: `.claude/rules/branch-naming.md` + +## Before Creating a PR + +1. **Verify branch naming** — must match `//issue--` +2. **Check diff size** — warn if over ~400 changed lines and suggest splitting +3. **Ensure commits reference the issue** — e.g., `Add validation (#12)` +4. **Push the branch** to remote if not already pushed + +## Creating a PR + +Use the PR template (`.github/PULL_REQUEST_TEMPLATE.md`): + +```bash +gh pr create \ + --title "Short descriptive title" \ + --body "## Summary + +Closes # + +## Changes + +- Change 1 +- Change 2 + +## How to Test + +1. Step 1 +2. Step 2 + +## Checklist + +- [x] PR is under ~400 changed lines +- [x] Branch follows naming convention +- [x] Commits reference the issue number +- [ ] Tests pass +- [ ] At least one teammate has been requested for review" \ + --reviewer "teammate-username" +``` + +## Key Rules + +- Always include `Closes #` or `Fixes #` in the PR body +- Target the `master` branch (or parent feature branch for sub-branches) +- Request at least one teammate as reviewer +- Use **merge commits only** — never squash or rebase +- Delete the branch after merging + +## Collaborative Feature Branch Workflow + +When multiple people are actively coding the **same feature** in parallel: + +1. Feature owner creates a feature branch from `master` +2. Each contributor creates a sub-branch off the feature branch +3. Contributors open PRs targeting the feature branch (not master) +4. Feature owner reviews and merges contributor PRs +5. Each contributor is responsible for resolving conflicts in their own PR +6. When complete, feature owner PRs the feature branch into `master` + +If only one person is implementing a feature, skip this — PR directly to `master`. + +See [reference.md](reference.md) for the git commands. diff --git a/.claude/skills/pr-workflow/reference.md b/.claude/skills/pr-workflow/reference.md new file mode 100644 index 0000000..b898c49 --- /dev/null +++ b/.claude/skills/pr-workflow/reference.md @@ -0,0 +1,73 @@ +# PR Workflow Reference + +## Common Commands + +### Create a PR + +Use the PR template from `.github/PULL_REQUEST_TEMPLATE.md` for the body structure: + +```bash +gh pr create --title "Title" --body "body matching the template" --reviewer "username" +``` + +### List open PRs + +```bash +gh pr list +``` + +### View a PR + +```bash +gh pr view +``` + +### Check PR diff size + +```bash +gh pr diff --stat +``` + +### Merge a PR (merge commit only) + +```bash +gh pr merge --merge --delete-branch +``` + +## Collaborative Feature Branch Flow + +```plaintext +master + └── feature-branch (created by feature owner) + ├── contributor-1-branch → PR into feature-branch + └── contributor-2-branch → PR into feature-branch +``` + +### Create the feature branch + +```bash +git checkout master +git pull +git checkout -b //issue-- +git push -u origin //issue-- +``` + +### Create a sub-branch + +```bash +git checkout +git pull +git checkout -b //issue-- +``` + +### PR for sub-branch (targets feature branch, not master) + +```bash +gh pr create --base --title "Title" --body "Closes #N (partial)" +``` + +### Final PR to master + +```bash +gh pr create --base master --title "Feature title" --body "Closes #N" +``` diff --git a/.claude/skills/retrospective/SKILL.md b/.claude/skills/retrospective/SKILL.md new file mode 100644 index 0000000..bdd9856 --- /dev/null +++ b/.claude/skills/retrospective/SKILL.md @@ -0,0 +1,60 @@ +--- +name: retrospective +description: Create iteration retrospective issues. Use when writing a retrospective, closing out an iteration, reflecting on iteration progress, or asking about retrospective format. +argument-hint: "iteration number" +allowed-tools: + - Read + - Write + - Edit + - Grep + - Glob + - "Bash(gh issue *)" + - "Bash(gh api *)" +--- + +# Retrospective Skill + +## Related Skills + +- `iteration-planning` — the iteration plan this retrospective reviews +- `github-issues` — conventions for the retrospective issue + +## Process + +1. Ask for the iteration number (or infer from recent milestones) +2. Gather context by reading: + - The iteration plan (`docs/iteration--plan.md`) + - Closed issues and merged PRs in the iteration's milestone +3. Create a GitHub issue titled **"Iteration X Retrospective"** with the correct format (see below), including a brief summary of what was accomplished based on the data gathered +4. Tell the team to fill in the three sections themselves — the AI cannot know what went well or didn't from the team's perspective + +## Issue Format + +- **Labels:** `task`, `retrospective` +- **Milestone:** Current iteration (e.g., "Iteration 1") +- **Assignees:** All team members + +### Issue Body Structure + +```markdown +## What Went Well + +- (bullet points) + +## What Didn't Go Well + +- (bullet points) + +## Lessons Learned + +- (bullet points) +``` + +## Guidelines + +- Be specific — reference actual issues, PRs, or events +- Focus on process improvements, not blame +- Each section should have at least 2-3 bullet points +- The retrospective is due **Monday end-of-day** after the iteration ends +- Encourage the team to comment on the issue with their own reflections +- Leave the issue open — the instructor closes it after reviewing diff --git a/.claude/skills/skill-authoring/SKILL.md b/.claude/skills/skill-authoring/SKILL.md new file mode 100644 index 0000000..70db2d0 --- /dev/null +++ b/.claude/skills/skill-authoring/SKILL.md @@ -0,0 +1,172 @@ +--- +name: skill-authoring +description: Best practices for writing and auditing Claude Code SKILL.md files. Use when creating a new skill, editing an existing skill, auditing skills, improving skill frontmatter, optimizing skill descriptions for auto-triggering, or asking about skill file structure, frontmatter fields, or allowed-tools configuration. +allowed-tools: + - Read + - Write + - Edit + - Grep + - Glob +--- + +# Skill Authoring Guide + +Best practices for writing effective Claude Code skills. A skill is a `SKILL.md` file in `.claude/skills//` that teaches Claude how to handle specific tasks. + +## Quick Reference + +| Topic | File | Description | +| --------------- | ---------------------------- | ---------------------------------------- | +| **Frontmatter** | [reference.md](reference.md) | All YAML frontmatter fields with details | +| **Tool names** | [reference.md](reference.md) | Complete allowed-tools list | + +--- + +## Core Principles + +1. **Description is the trigger** — Claude decides whether to load a skill based solely on its `description`. Make it specific with concrete trigger phrases. +2. **Lean SKILL.md, heavy reference files** — Only the description is always in context. Full skill content loads on invocation. Keep SKILL.md focused; move detailed docs to separate files. +3. **Minimize permission friction** — List every tool the skill needs in `allowed-tools` so Claude doesn't pause to ask. +4. **No fluff** — Every line should teach Claude something actionable. Cut marketing language, redundant explanations, and obvious statements. + +--- + +## Writing the Description + +The `description` field is the single most important part of a skill. It controls auto-triggering. + +**Pattern:** `{What it does}. Use when {trigger phrase 1}, {trigger phrase 2}, ... or asking about {topic 1}, {topic 2}.` + +**Good:** + +```yaml +description: Component patterns and UI library usage. Use when creating components, using shadcn/ui, implementing theming, working with forms, or asking about component organization. +``` + +**Bad:** + +```yaml +description: Helps with frontend components and UI stuff. +``` + +Rules: + +- Include 3-8 specific trigger phrases that a user would naturally say +- Use action verbs: "creating", "implementing", "debugging", "adding", "configuring" +- Include tool/library names: "shadcn/ui", "Legend-State", "zod" +- Never use second person ("you") or marketing language + +--- + +## Choosing allowed-tools + +Only include tools the skill actually needs. Read-only tools (`Read`, `Grep`, `Glob`, `WebSearch`, `WebFetch`) don't require permission anyway, but listing them documents intent. + +**The tools that matter most** (these are the ones that prompt for permission): + +| Tool | Include when the skill... | +| ------- | ----------------------------------------------------- | +| `Write` | Creates new files | +| `Edit` | Modifies existing files | +| `Bash` | Runs shell commands (use patterns: `Bash(npm run *)`) | +| `Task` | Spawns subagents for parallel work | + +**Common combos:** + +- **Read-only skill:** `Read, Grep, Glob` +- **Code-writing skill:** `Read, Write, Edit, Grep, Glob` +- **Full autonomy skill:** `Read, Write, Edit, Grep, Glob, Bash, WebSearch, WebFetch` + +--- + +## SKILL.md Structure + +Follow this structure for consistency: + +```markdown +--- +name: my-skill +description: {What it does}. Use when {triggers}. +allowed-tools: + - {tools} +--- + +# {Skill Name} Guide + +One-line summary of what this skill covers. + +## Related Skills (optional) + +Links to related skills for cross-referencing. + +## Quick Reference (optional) + +Table linking to supporting files. + +## {Core Sections} + +The actual instructions, patterns, and examples. +Keep to what Claude needs to act. No preambles. + +## Checklist (optional) + +Steps for common tasks within this skill's domain. + +## Detailed Documentation (optional) + +Links to reference files for deep content. +``` + +--- + +## Content Guidelines + +**Do:** + +- Use tables for structured reference (locations, conventions, mappings) +- Show code examples from the actual codebase, not hypotheticals +- Use checklists for multi-step procedures +- Link to reference files for anything over ~20 lines of detail + +**Don't:** + +- Explain why skills exist or how Claude works +- Repeat information available in referenced files +- Add "Notes:", "Important:", or "Remember:" prefixes — just state the instruction +- Include code examples for things Claude already knows (basic JS, HTML, etc.) + +--- + +## Supporting Files + +Move heavy content out of SKILL.md into the skill's directory: + +```plaintext +my-skill/ +├── SKILL.md # Core instructions (~100-200 lines) +├── patterns.md # Code patterns and examples +├── reference.md # Detailed API/config reference +└── conventions.md # Naming and style rules +``` + +Claude loads these lazily — only when it follows a link or decides it needs more detail. This keeps the context window lean. + +--- + +## Auditing Checklist + +When reviewing an existing skill: + +- [ ] **Description** — Contains 3-8 specific trigger phrases? Uses action verbs? +- [ ] **allowed-tools** — Lists every tool the skill needs? No missing write/edit/bash? +- [ ] **Content length** — SKILL.md under ~200 lines? Heavy content in reference files? +- [ ] **No fluff** — Every line is actionable? No marketing, no obvious statements? +- [ ] **Code examples** — From the actual codebase, not generic? +- [ ] **Cross-references** — Links to related skills where relevant? +- [ ] **Frontmatter fields** — Using `argument-hint` if the skill takes args? `disable-model-invocation` for dangerous workflows? + +--- + +## Detailed Documentation + +- [reference.md](reference.md) — Complete frontmatter field reference and tool name list diff --git a/.claude/skills/skill-authoring/reference.md b/.claude/skills/skill-authoring/reference.md new file mode 100644 index 0000000..f7889fb --- /dev/null +++ b/.claude/skills/skill-authoring/reference.md @@ -0,0 +1,154 @@ +# Skill Authoring Reference + +Complete reference for all SKILL.md frontmatter fields, tool names, and variables. + +--- + +## All Frontmatter Fields + +### Core Fields + +| Field | Type | Default | Description | +| --------------- | ------ | --------------- | ------------------------------------------------------------------------------------------------ | +| `name` | string | directory name | Slash-command name. Lowercase, hyphens, max 64 chars. Must match directory name. | +| `description` | string | first paragraph | What the skill does + trigger phrases. **Primary signal for auto-triggering.** | +| `allowed-tools` | array | none | Tools Claude can use without permission during skill execution. Array or comma-separated string. | + +### Invocation Control + +| Field | Type | Default | Description | +| -------------------------- | ------- | ------- | --------------------------------------------------------------------------------------------- | +| `disable-model-invocation` | boolean | `false` | `true` = Claude cannot auto-invoke. Description not loaded into context. Manual `/name` only. | +| `user-invocable` | boolean | `true` | `false` = hidden from `/` menu. Claude can still auto-invoke. Use for background knowledge. | + +### Execution Context + +| Field | Type | Default | Description | +| --------- | ------ | ----------------- | -------------------------------------------------------------------------------------------------- | +| `model` | string | session default | Override model for this skill. Values: `opus`, `sonnet`, `haiku`, or full model ID. | +| `context` | string | none | `fork` = run in isolated subagent. Skill content becomes subagent prompt. No conversation history. | +| `agent` | string | `general-purpose` | Subagent type when `context: fork`. Options: `Explore`, `Plan`, `general-purpose`. | + +### User Experience + +| Field | Type | Default | Description | +| --------------- | ------ | ------- | ------------------------------------------------------------------ | +| `argument-hint` | string | none | Autocomplete hint for expected arguments. E.g., `"[issue-number]"` | + +### Skill-Scoped Hooks + +```yaml +hooks: + PreToolUse: + - matcher: "Bash" + hooks: + - type: command + command: "./scripts/validate.sh" + PostToolUse: + - matcher: "Edit|Write" + hooks: + - type: command + command: "./scripts/lint.sh" +``` + +Only `PreToolUse`, `PostToolUse`, and `Stop` events are supported in skill frontmatter. + +--- + +## Complete Tool Names for allowed-tools + +### Standard Tools + +| Tool | Permission needed | Purpose | +| ----------------- | ----------------- | ------------------------------ | +| `Read` | No | Read file contents | +| `Write` | Yes | Create or overwrite files | +| `Edit` | Yes | Replace text in existing files | +| `Glob` | No | Find files by pattern | +| `Grep` | No | Search file contents | +| `Bash` | Yes | Execute shell commands | +| `WebFetch` | No | Fetch and process web content | +| `WebSearch` | No | Search the web | +| `Task` | Yes | Spawn subagents | +| `NotebookEdit` | Yes | Edit Jupyter notebooks | +| `AskUserQuestion` | No | Request input from user | + +### Bash with Command Filtering + +Restrict Bash to specific commands using patterns: + +```yaml +allowed-tools: + - "Bash(npm run *)" + - "Bash(git commit *)" + - "Bash(npx shadcn@latest add *)" +``` + +`*` is a wildcard. `Bash` without a pattern allows all commands. + +### MCP Tools + +Format: `mcp____` + +```yaml +allowed-tools: + - "mcp__memory__create_entities" + - "mcp__filesystem__read_file" +``` + +--- + +## Variables Available in Skill Content + +| Variable | Description | +| ---------------------- | ---------------------------------------------------- | +| `$ARGUMENTS` | All arguments passed to the skill | +| `$ARGUMENTS[N]` | Nth argument (0-indexed) | +| `$0`, `$1`, `$2` | Shorthand for `$ARGUMENTS[0]`, `$ARGUMENTS[1]`, etc. | +| `${CLAUDE_SESSION_ID}` | Current session ID | + +### Shell Preprocessing + +Use `` !`command` `` to run shell commands before Claude sees the content: + +```markdown +Current branch: !`git branch --show-current` +Recent changes: !`git log --oneline -5` +``` + +The output replaces the placeholder before Claude processes the skill. + +--- + +## Frontmatter Template + +```yaml +--- +name: my-skill +description: What this does. Use when {trigger1}, {trigger2}, {trigger3}, or asking about {topic1}, {topic2}. +allowed-tools: + - Read + - Write + - Edit + - Grep + - Glob +# argument-hint: "[optional-args]" +# disable-model-invocation: false +# model: sonnet +# context: fork +# agent: Explore +--- +``` + +--- + +## Auto-Triggering Tips + +Skill descriptions compete for a ~16KB context budget. With many skills: + +- Keep descriptions under 2 sentences +- Front-load the most important trigger phrases +- Combine related skills if their descriptions overlap significantly +- Use `disable-model-invocation: true` for skills that should only run manually (deploys, destructive operations) + +If a skill isn't auto-triggering reliably, make the description more specific rather than longer. diff --git a/CLAUDE.md b/CLAUDE.md new file mode 100644 index 0000000..7f3845d --- /dev/null +++ b/CLAUDE.md @@ -0,0 +1,90 @@ +# CLAUDE.md + +This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository. + +## Project Overview + +Stacky is a Mastodon-compatible social media client built with Next.js. Users browse posts from a Mastodon instance, organize them into "stacks" (categorized discussion threads), and interact via favorites, bookmarks, and annotations. + +## Commands + +```bash +pnpm install # Install dependencies +pnpm dev # Start dev server at localhost:3000 +pnpm build # Production build +pnpm lint # ESLint via next lint +``` + +No test framework is configured. + +## Tech Stack + +- **Framework**: Next.js 14 (App Router) with TypeScript +- **Runtime**: Node.js 22.x +- **Package manager**: pnpm +- **UI library**: Mantine v7 (AppShell, components, hooks, notifications) +- **HTTP client**: axios +- **Icons**: @tabler/icons-react, lucide-react +- **Styling**: CSS Modules + PostCSS with Mantine preset +- **Backend**: Mastodon-compatible API at `https://beta.stacky.social:3002` + +## Architecture + +### Routing & Layout + +The app uses Next.js App Router with a **route group** `(shell)` that wraps all authenticated pages in a three-panel layout (`Shell.tsx`): +- **Left navbar**: `NavBar/Navbar` — navigation links +- **Center main**: page content +- **Right aside**: `@aside` parallel route slot — shows related stacks for the active post + +The landing page (`/`) handles Mastodon OAuth instance selection. `/callback` completes the OAuth flow and stores tokens in localStorage. + +### Parallel Routes + +`src/app/(shell)/@aside/` is a Next.js parallel route that renders the aside panel independently. Each route under `(shell)` has a corresponding `@aside` directory that controls what appears in the right panel. + +### State Management + +- **RelatedStacksContext** (`related-stacks-context.tsx`): Shared context in the shell layout. Manages which post's related stacks are shown in the aside panel. Provides toggle behavior — clicking the same post hides its stacks. +- **localStorage**: `accessToken`, `currentUser` (JSON), `authCode` +- **sessionStorage**: `scrollY:{path}` for scroll restoration, `previousPath` for back navigation + +### Post List Caching (PostList.tsx) + +`PostList` uses a module-level `Map` cache (not React state) that survives component remounts during SPA navigation: +- 5-minute TTL, LRU eviction at 20 entries +- Stale-While-Revalidate: serves cached posts instantly, revalidates in background +- Scroll position saved to sessionStorage on navigation, restored on return +- Stack data loaded in batches of 2 concurrent requests per post + +### API Integration + +All API calls go to `https://beta.stacky.social:3002`. Auth is via OAuth Bearer token from localStorage. Key patterns: +- `mastoActions.ts`: Mastodon interaction helpers (favorite, bookmark, boost) +- Stack-specific endpoints: `/stacks/{postId}/related`, `/api/stacks/{stackId}/questions` +- Standard Mastodon endpoints: `/api/v1/statuses/`, `/api/v1/timelines/`, etc. + +### Environment Variables + +Required in `.env.local`: +``` +NEXT_PUBLIC_MASTODON_OAUTH_CLIENT_ID=... +NEXT_PUBLIC_MASTODON_OAUTH_CLIENT_SECRET=... +NEXT_PUBLIC_MODE=development +``` + +## Key Directories + +- `src/app/(shell)/` — All authenticated routes and the shell layout +- `src/app/(shell)/@aside/` — Parallel route for right sidebar content +- `src/components/` — Reusable components (Posts/, Header/, NavBar/, SubmitPost/, etc.) +- `src/utils/` — Helpers (mastoActions.ts, useAccessToken.ts, emojiMapping.ts) +- `src/types/PostType.tsx` — Core TypeScript interfaces (PostType, ReplyType, PreviewCardType) +- `src/app/FakeData/` — Mock data for development + +## Git Conventions + +- **Branches**: `//issue--` (e.g., `asmith/feature/issue-5-user-auth`) +- **Commits**: Imperative mood, reference issue number: `Add login form (#5)`. No co-author signatures. +- **PRs**: Include `Closes #` in body. Keep under ~400 changed lines. Merge commits only — never squash or rebase. +- Never push directly to the main branch. From f05c32b86aa13fbd4eab0c9c44cbb2762cca9376 Mon Sep 17 00:00:00 2001 From: tarcode2004 <66574422+tarcode2004@users.noreply.github.com> Date: Wed, 25 Feb 2026 14:06:27 -0500 Subject: [PATCH 2/3] feat: replace `feature` label with `enhancement` and add `documentation` label across skill definitions and conventions --- .claude/rules/branch-naming.md | 4 ++-- .claude/skills/github-issues/SKILL.md | 13 +++++++------ .claude/skills/iteration-planning/SKILL.md | 2 +- CLAUDE.md | 2 +- 4 files changed, 11 insertions(+), 10 deletions(-) diff --git a/.claude/rules/branch-naming.md b/.claude/rules/branch-naming.md index fb6c972..3efd501 100644 --- a/.claude/rules/branch-naming.md +++ b/.claude/rules/branch-naming.md @@ -7,13 +7,13 @@ When creating branches, ALWAYS follow this pattern: Where: - `author` is the GitHub username of the branch creator -- `type` matches the issue label: `feature`, `bug`, or `task` +- `type` matches the issue label: `enhancement`, `bug`, or `task` - `number` is the GitHub issue number - `short-description` is 2-4 lowercase words separated by hyphens Examples: -- `asmith/feature/issue-5-user-authentication` +- `asmith/enhancement/issue-5-user-authentication` - `jdoe/bug/issue-12-fix-login-redirect` - `mchen/task/issue-3-setup-ci-pipeline` diff --git a/.claude/skills/github-issues/SKILL.md b/.claude/skills/github-issues/SKILL.md index 4e18b79..5b48e11 100644 --- a/.claude/skills/github-issues/SKILL.md +++ b/.claude/skills/github-issues/SKILL.md @@ -25,7 +25,7 @@ Every issue must have: 1. **Descriptive title** — clear and concise 2. **Description** — what needs to be done and why 3. **Acceptance criteria** — checklist of testable criteria -4. **Label** — exactly one of: `feature`, `task`, or `bug` +4. **Label** — exactly one of: `enhancement`, `task`, or `bug` 5. **Milestone** — the current iteration (e.g., "Iteration 1") 6. **Assignees** — see ownership rules below @@ -33,17 +33,18 @@ Every issue must have: The project uses these labels: -- `feature` — new functionality +- `enhancement` — new feature or request - `task` — development work that isn't a feature or bug -- `bug` — something that's broken +- `bug` — something isn't working +- `documentation` — improvements or additions to documentation - `retrospective` — added alongside `task` for retrospective issues If labels don't exist yet, create them: ```bash -gh label create feature --description "New functionality" --color 0E8A16 +gh label create enhancement --description "New feature or request" --color A2EEEF gh label create task --description "Development task" --color 1D76DB -gh label create bug --description "Something is broken" --color D93F0B +gh label create bug --description "Something isn't working" --color D73A4A gh label create retrospective --description "Iteration retrospective" --color FBCA04 ``` @@ -70,7 +71,7 @@ Read the matching template in `.github/ISSUE_TEMPLATE/` (feature.yml, task.yml, ```bash gh issue create \ --title "Add search-by-title to items list endpoint" \ - --label "feature" \ + --label "enhancement" \ --milestone "Iteration 1" \ --assignee "owner,supporting" \ --body "## Description diff --git a/.claude/skills/iteration-planning/SKILL.md b/.claude/skills/iteration-planning/SKILL.md index 6da361a..770ca00 100644 --- a/.claude/skills/iteration-planning/SKILL.md +++ b/.claude/skills/iteration-planning/SKILL.md @@ -45,7 +45,7 @@ allowed-tools: - Break requirements into issues that can be completed by 1-2 people - Follow issue ownership rules from the `github-issues` skill (not a fixed number of assignees) - Only create issues for the current iteration — never for future iterations -- Apply the correct label to each issue: `feature`, `task`, or `bug` +- Apply the correct label to each issue: `enhancement`, `task`, or `bug` - Set the milestone to the current iteration (e.g., "Iteration 1") ## After Planning diff --git a/CLAUDE.md b/CLAUDE.md index 7f3845d..7caba0b 100644 --- a/CLAUDE.md +++ b/CLAUDE.md @@ -84,7 +84,7 @@ NEXT_PUBLIC_MODE=development ## Git Conventions -- **Branches**: `//issue--` (e.g., `asmith/feature/issue-5-user-auth`) +- **Branches**: `//issue--` (e.g., `asmith/enhancement/issue-5-user-auth`) - **Commits**: Imperative mood, reference issue number: `Add login form (#5)`. No co-author signatures. - **PRs**: Include `Closes #` in body. Keep under ~400 changed lines. Merge commits only — never squash or rebase. - Never push directly to the main branch. From 24bc2454c5e2d6abf0f9b46b42d13d3fa9101933 Mon Sep 17 00:00:00 2001 From: tarcode2004 <66574422+tarcode2004@users.noreply.github.com> Date: Wed, 4 Mar 2026 03:39:48 -0500 Subject: [PATCH 3/3] Inline links in post body instead of separate link button (#135) Stop stripping external URLs from post HTML so links appear inline and clickable. Remove the separate link icon button from the action bar. Fix link click handler to use textRef instead of broken .post-content selector. --- src/components/Posts/Post.tsx | 38 ++++++++++------------------------- 1 file changed, 11 insertions(+), 27 deletions(-) diff --git a/src/components/Posts/Post.tsx b/src/components/Posts/Post.tsx index c1d1544..aa52390 100644 --- a/src/components/Posts/Post.tsx +++ b/src/components/Posts/Post.tsx @@ -2,7 +2,7 @@ import React, { useState, useRef, useEffect } from 'react'; import { useRouter } from 'next/navigation'; import { Text, Avatar, Group, Paper, UnstyledButton, Divider, Anchor } from '@mantine/core'; import { notifications } from '@mantine/notifications'; -import { IconHeart, IconBookmark, IconNote, IconMessageCircle, IconHeartFilled, IconBookmarkFilled, IconLink } from '@tabler/icons-react'; +import { IconHeart, IconBookmark, IconNote, IconMessageCircle, IconHeartFilled, IconBookmarkFilled } from '@tabler/icons-react'; import { format, formatDistanceToNow } from 'date-fns'; import StackCount from '../StackCount'; import axios from 'axios'; @@ -17,23 +17,13 @@ const MastodonInstanceUrl = 'https://beta.stacky.social'; interface CleanedPost { html: string; publishedDate: string | null; - articleUrl: string | null; } -/** Strip external URLs and extract "Published" date from post HTML. - * Only strips URLs when a preview card exists to preserve legitimate links in conversational posts. */ -function cleanPostHtml(html: string, card: PreviewCard | null | undefined): CleanedPost { +/** Extract "Published" date from post HTML and clean up empty tags. */ +function cleanPostHtml(html: string): CleanedPost { let cleaned = html; let publishedDate: string | null = null; - if (card) { - // Remove all tags linking to external URLs (entire tag + contents) - cleaned = cleaned.replace(/]*href=["']https?:\/\/[^"']+["'][^>]*>[\s\S]*?<\/a>/gi, ''); - - // Remove bare URLs in text (not inside tags) - cleaned = cleaned.replace(/https?:\/\/[^\s<]+/g, ''); - } - // Extract "Published: DATE" and remove from text cleaned = cleaned.replace(/Published:\s*(\d{4}-\d{2}-\d{2}T[\d:.]+Z?)/g, (_match, iso) => { try { @@ -54,7 +44,7 @@ function cleanPostHtml(html: string, card: PreviewCard | null | undefined): Clea // Collapse leftover empty

tags cleaned = cleaned.replace(/

\s*<\/p>/g, ''); - return { html: cleaned, publishedDate, articleUrl: card?.url ?? null }; + return { html: cleaned, publishedDate }; } @@ -119,7 +109,7 @@ export default function Post({ const [previewCards, setPreviewCards] = useState(initialCard ? [initialCard] : []); const [tempRelatedStacks, setTempRelatedStacks] = useState(relatedStacks); - const { html: displayText, publishedDate, articleUrl } = cleanPostHtml(text, previewCards[0]); + const { html: displayText, publishedDate } = cleanPostHtml(text); const [isOverflowing, setIsOverflowing] = useState(false); const textRef = useRef(null); @@ -276,11 +266,6 @@ export default function Post({ setAnnotationModalOpen(true); }; - const handleOpenInNewTab = () => { - const url = articleUrl || `${window.location.origin}/posts/${id}`; - window.open(url, '_blank'); - }; - const handleStackCountClick = async () => { setIsExpanded(true); const position = paperRef.current ? paperRef.current.getBoundingClientRect() : { top: 0, height: 0 }; @@ -352,8 +337,12 @@ export default function Post({ }; useEffect(() => { - const links = document.querySelectorAll('.post-content a'); + const container = textRef.current; + if (!container) return; + const links = container.querySelectorAll('a'); links.forEach(link => { + (link as HTMLElement).style.color = '#5a71a8'; + (link as HTMLElement).style.textDecoration = 'underline'; link.addEventListener('click', handleLinkClick as EventListener); }); return () => { @@ -361,7 +350,7 @@ export default function Post({ link.removeEventListener('click', handleLinkClick as EventListener); }); }; - }, [text]); + }, [text, displayText]); return (

@@ -544,11 +533,6 @@ export default function Post({ ariaLabel="Annotate" onClick={handleAnnotation} /> - } - ariaLabel="Open in new tab" - onClick={handleOpenInNewTab} - />