Compare commits
20 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b7023809f | |||
| d733ad0a2f | |||
| 2cf7471687 | |||
| 6b4e7441c9 | |||
| a7b207e689 | |||
| 6b2da83851 | |||
| cc3f2e5b13 | |||
| 1c217fae43 | |||
| 6230c0fa61 | |||
| 7a537105e3 | |||
| 8a7314d198 | |||
| e41844a13b | |||
| 11baaefe21 | |||
| 97a27fdfbf | |||
| d41471c818 | |||
| 3360e6f023 | |||
| 7d84959c15 | |||
| ded07d3a6b | |||
| 608f4b2231 | |||
| 6a64a98fbf |
@@ -0,0 +1 @@
|
||||
# CCPM epic/task store — see docs/projects/README.md
|
||||
@@ -0,0 +1 @@
|
||||
# CCPM PRD store — see docs/projects/README.md
|
||||
@@ -0,0 +1,87 @@
|
||||
---
|
||||
name: ccpm
|
||||
description: "CCPM - spec-driven project management: PRD → Epic → GitHub Issues → parallel agents → shipped code. Use this skill for anything in the software delivery lifecycle: writing a PRD ('write a PRD for X', 'let's plan X', 'scope this out'), parsing a PRD into an epic, decomposing an epic into tasks, syncing to GitHub ('sync the X epic', 'push tasks to github'), starting work on an issue ('start working on issue N', 'let's work on issue N'), analyzing parallel work streams, running standups ('standup', 'run the standup'), checking status ('what's next', 'what's blocked', 'what are we working on'), closing issues, or merging an epic. Use ccpm any time the user is talking about shipping a feature, managing work, or tracking progress — even if they don't say 'ccpm' or 'PRD'. Do NOT use for: debugging code, writing tests, reviewing PRs, or raw GitHub issue/PR operations with no delivery context."
|
||||
---
|
||||
|
||||
# CCPM - Claude Code Project Manager
|
||||
|
||||
A spec-driven development workflow: PRD → Epic → GitHub Issues → Parallel Agents → Shipped Code.
|
||||
|
||||
## Core Philosophy
|
||||
|
||||
Requirements live in files, not heads. Every feature starts as a PRD, becomes a technical epic, decomposes into GitHub issues, and gets executed by parallel agents with full traceability.
|
||||
|
||||
## File Conventions
|
||||
|
||||
Before doing anything, read `references/conventions.md` for path standards, frontmatter schemas, and GitHub operation rules. These apply to all phases.
|
||||
|
||||
## The Five Phases
|
||||
|
||||
### 1. Plan — Capture requirements
|
||||
|
||||
**When**: User wants to define a new feature, product requirement, or scope of work.
|
||||
**Read**: `references/plan.md`
|
||||
**Covers**: Writing PRDs through guided brainstorming, converting PRDs to technical epics.
|
||||
|
||||
### 2. Structure — Break it down
|
||||
|
||||
**When**: An epic exists and needs to be decomposed into concrete tasks.
|
||||
**Read**: `references/structure.md`
|
||||
**Covers**: Epic decomposition into numbered task files with dependencies and parallelization.
|
||||
|
||||
### 3. Sync — Push to GitHub
|
||||
|
||||
**When**: Local epic/tasks need to become GitHub issues, progress needs to be posted as comments, or a bug is found and needs a linked issue created.
|
||||
**Read**: `references/sync.md`
|
||||
**Covers**: Epic sync (epic + tasks → GitHub issues), issue sync (progress comments), closing issues/epics, bug reporting against completed issues.
|
||||
|
||||
### 4. Execute — Start building
|
||||
|
||||
**When**: User wants to start working on one or more GitHub issues with parallel agents.
|
||||
**Read**: `references/execute.md`
|
||||
**Covers**: Issue analysis (parallel work stream identification), launching parallel agents, coordinating worktrees.
|
||||
|
||||
### 5. Track — Know where things stand
|
||||
|
||||
**When**: User asks for status, standup report, what's blocked, what's next, or needs to validate state.
|
||||
**Read**: `references/track.md`
|
||||
**Covers**: Status, standup, search, in-progress, next priority, blocked items, validation.
|
||||
|
||||
---
|
||||
|
||||
## Script-First Rule
|
||||
|
||||
For deterministic operations — anything that reads and reports without needing reasoning — always run the bash script directly rather than doing the work manually:
|
||||
|
||||
| What the user wants | Script to run |
|
||||
|---|---|
|
||||
| Project status | `bash references/scripts/status.sh` |
|
||||
| Standup report | `bash references/scripts/standup.sh` |
|
||||
| List all epics | `bash references/scripts/epic-list.sh` |
|
||||
| Show epic details | `bash references/scripts/epic-show.sh <name>` |
|
||||
| Epic status | `bash references/scripts/epic-status.sh <name>` |
|
||||
| List PRDs | `bash references/scripts/prd-list.sh` |
|
||||
| PRD status | `bash references/scripts/prd-status.sh` |
|
||||
| Search issues/tasks | `bash references/scripts/search.sh <query>` |
|
||||
| What's in progress | `bash references/scripts/in-progress.sh` |
|
||||
| What's next | `bash references/scripts/next.sh` |
|
||||
| What's blocked | `bash references/scripts/blocked.sh` |
|
||||
| Validate project state | `bash references/scripts/validate.sh` |
|
||||
|
||||
Use the LLM for work that requires reasoning: writing PRDs, analyzing parallelism, launching agents, synthesizing updates.
|
||||
|
||||
---
|
||||
|
||||
## Quick Reference
|
||||
|
||||
```
|
||||
Plan a feature: "I want to build X" or "create a PRD for X"
|
||||
Parse to epic: "turn the X PRD into an epic"
|
||||
Decompose: "break down the X epic into tasks"
|
||||
Sync to GitHub: "push the X epic to GitHub"
|
||||
Start an issue: "start working on issue 42"
|
||||
Check status: "what's our status" / "standup"
|
||||
What's next: "what should I work on next"
|
||||
Merge epic: "merge the X epic"
|
||||
Report a bug: "found a bug in issue 42" / "testing issue 42 revealed X"
|
||||
```
|
||||
@@ -0,0 +1,178 @@
|
||||
# Conventions — File Formats, Paths & Rules
|
||||
|
||||
Read this before doing any file operations across all phases.
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
.claude/
|
||||
├── prds/
|
||||
│ └── <feature-name>.md # Product requirement documents
|
||||
├── epics/
|
||||
│ ├── <feature-name>/
|
||||
│ │ ├── epic.md # Technical epic
|
||||
│ │ ├── <N>.md # Task files (named by GitHub issue number after sync)
|
||||
│ │ ├── <N>-analysis.md # Parallel work stream analysis
|
||||
│ │ ├── github-mapping.md # Issue number → URL mapping
|
||||
│ │ ├── execution-status.md # Active agents tracker
|
||||
│ │ └── updates/
|
||||
│ │ └── <issue_N>/
|
||||
│ │ ├── stream-A.md # Per-agent progress
|
||||
│ │ ├── progress.md # Overall issue progress
|
||||
│ │ └── execution.md # Execution state
|
||||
│ └── archived/
|
||||
│ └── <feature-name>/ # Completed epics
|
||||
└── context/ # Project context docs (separate system)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontmatter Schemas
|
||||
|
||||
### PRD (.claude/prds/<name>.md)
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: <feature-name> # kebab-case, matches filename
|
||||
description: <one-liner> # used in lists and summaries
|
||||
status: backlog | active | completed
|
||||
created: <ISO 8601> # date -u +"%Y-%m-%dT%H:%M:%SZ"
|
||||
---
|
||||
```
|
||||
|
||||
### Epic (.claude/epics/<name>/epic.md)
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: <feature-name>
|
||||
status: backlog | in-progress | completed
|
||||
created: <ISO 8601>
|
||||
updated: <ISO 8601>
|
||||
progress: 0% # recalculated when tasks close
|
||||
prd: .claude/prds/<name>.md
|
||||
github: https://github.com/<owner>/<repo>/issues/<N> # set on sync
|
||||
---
|
||||
```
|
||||
|
||||
### Task (.claude/epics/<name>/<N>.md)
|
||||
|
||||
```yaml
|
||||
---
|
||||
name: <Task Title>
|
||||
status: open | in-progress | closed
|
||||
created: <ISO 8601>
|
||||
updated: <ISO 8601>
|
||||
github: https://github.com/<owner>/<repo>/issues/<N> # set on sync
|
||||
depends_on: [] # issue numbers this must wait for
|
||||
parallel: true # can run concurrently with non-conflicting tasks
|
||||
conflicts_with: [] # issue numbers that touch the same files
|
||||
---
|
||||
```
|
||||
|
||||
### Progress (.claude/epics/<name>/updates/<N>/progress.md)
|
||||
|
||||
```yaml
|
||||
---
|
||||
issue: <N>
|
||||
started: <ISO 8601>
|
||||
last_sync: <ISO 8601>
|
||||
completion: 0%
|
||||
---
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Datetime Rule
|
||||
|
||||
Always get real current datetime from the system — never use placeholder text:
|
||||
|
||||
```bash
|
||||
date -u +"%Y-%m-%dT%H:%M:%SZ"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Frontmatter Update Pattern
|
||||
|
||||
When updating a single frontmatter field in an existing file:
|
||||
|
||||
```bash
|
||||
sed -i.bak "/^<field>:/c\\<field>: <value>" <file>
|
||||
rm <file>.bak
|
||||
```
|
||||
|
||||
When stripping frontmatter to get body content for GitHub:
|
||||
|
||||
```bash
|
||||
sed '1,/^---$/d; 1,/^---$/d' <file> > /tmp/body.md
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## GitHub Operations
|
||||
|
||||
### Repository Safety Check (run before any write operation)
|
||||
|
||||
```bash
|
||||
remote_url=$(git remote get-url origin 2>/dev/null || echo "")
|
||||
if [[ "$remote_url" == *"automazeio/ccpm"* ]]; then
|
||||
echo "❌ Cannot write to the CCPM template repository."
|
||||
echo "Update remote: git remote set-url origin https://github.com/YOUR/REPO.git"
|
||||
exit 1
|
||||
fi
|
||||
REPO=$(echo "$remote_url" | sed 's|.*github.com[:/]||' | sed 's|\.git$||')
|
||||
```
|
||||
|
||||
### Authentication
|
||||
|
||||
Don't pre-check authentication. Run the `gh` command and handle failure:
|
||||
|
||||
```bash
|
||||
gh <command> || echo "❌ GitHub CLI failed. Run: gh auth login"
|
||||
```
|
||||
|
||||
### Getting Issue Numbers
|
||||
|
||||
```bash
|
||||
# From a task file's github field:
|
||||
grep 'github:' <file> | grep -oE '[0-9]+$'
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Git / Worktree Conventions
|
||||
|
||||
- One branch per epic: `epic/<name>`
|
||||
- Worktrees live at `../epic-<name>/` (sibling to project root)
|
||||
- Always start branches from an up-to-date main:
|
||||
|
||||
```bash
|
||||
git checkout main && git pull origin main
|
||||
git worktree add ../epic-<name> -b epic/<name>
|
||||
```
|
||||
|
||||
- Commit format inside epics: `Issue #<N>: <description>`
|
||||
- Never use `--force` in any git operation
|
||||
|
||||
---
|
||||
|
||||
## Naming Conventions
|
||||
|
||||
- Feature names: kebab-case, lowercase, letters/numbers/hyphens, starts with a letter
|
||||
- Task files before sync: `001.md`, `002.md`, ... (sequential)
|
||||
- Task files after sync: renamed to GitHub issue number (e.g., `1234.md`)
|
||||
- Labels applied on sync: `epic`, `epic:<name>`, `feature` (for epics); `task`, `epic:<name>` (for tasks)
|
||||
|
||||
---
|
||||
|
||||
## Epic Progress Calculation
|
||||
|
||||
```bash
|
||||
total=$(ls .claude/epics/<name>/[0-9]*.md 2>/dev/null | wc -l)
|
||||
closed=$(grep -l '^status: closed' .claude/epics/<name>/[0-9]*.md 2>/dev/null | wc -l)
|
||||
progress=$((closed * 100 / total))
|
||||
```
|
||||
|
||||
Update epic frontmatter when any task closes.
|
||||
@@ -0,0 +1,223 @@
|
||||
# Execute — Start Building with Parallel Agents
|
||||
|
||||
This phase covers analyzing GitHub issues for parallel work streams and launching agents to execute them.
|
||||
|
||||
---
|
||||
|
||||
## Issue Analysis
|
||||
|
||||
**Trigger**: User wants to understand how to parallelize work on an issue before starting.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Find the local task file: check `.claude/epics/*/<N>.md` first, then search for `github:.*issues/<N>` in frontmatter.
|
||||
- If not found: "❌ No local task for issue #<N>. Run a sync first."
|
||||
|
||||
### Process
|
||||
|
||||
Get issue details: `gh issue view <N> --json title,body,labels`
|
||||
|
||||
Read the local task file fully. Identify independent work streams by asking:
|
||||
|
||||
- Which files will be created/modified?
|
||||
- Which changes can happen simultaneously without conflict?
|
||||
- What are the dependencies between changes?
|
||||
|
||||
**Common stream patterns:**
|
||||
|
||||
- Database Layer: schema, migrations, models
|
||||
- Service Layer: business logic, data access
|
||||
- API Layer: endpoints, validation, middleware
|
||||
- UI Layer: components, pages, styles
|
||||
- Test Layer: unit tests, integration tests
|
||||
|
||||
Create `.claude/epics/<epic_name>/<N>-analysis.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
issue: <N>
|
||||
title: <title>
|
||||
analyzed: <run: date -u +"%Y-%m-%dT%H:%M:%SZ">
|
||||
estimated_hours: <total>
|
||||
parallelization_factor: <1.0-5.0>
|
||||
---
|
||||
|
||||
# Parallel Work Analysis: Issue #<N>
|
||||
|
||||
## Overview
|
||||
|
||||
## Parallel Streams
|
||||
|
||||
### Stream A: <Name>
|
||||
**Scope**:
|
||||
**Files**:
|
||||
**Can Start**: immediately
|
||||
**Estimated Hours**:
|
||||
**Dependencies**: none
|
||||
|
||||
### Stream B: <Name>
|
||||
**Scope**:
|
||||
**Files**:
|
||||
**Can Start**: after Stream A
|
||||
**Dependencies**: Stream A
|
||||
|
||||
## Coordination Points
|
||||
### Shared Files
|
||||
### Sequential Requirements
|
||||
|
||||
## Conflict Risk Assessment
|
||||
|
||||
## Parallelization Strategy
|
||||
|
||||
## Expected Timeline
|
||||
- With parallel execution: <max_stream_hours>h wall time
|
||||
- Without: <sum_all_hours>h
|
||||
- Efficiency gain: <pct>%
|
||||
```
|
||||
|
||||
**Output**: "✅ Analysis complete for issue #<N> — N parallel streams identified. Ready to start? Say: start issue <N>"
|
||||
|
||||
---
|
||||
|
||||
## Starting an Issue
|
||||
|
||||
**Trigger**: User wants to begin work on a specific GitHub issue.
|
||||
|
||||
### Preflight
|
||||
|
||||
1. Verify issue exists and is open: `gh issue view <N> --json state,title,labels,body`
|
||||
2. Find local task file (as above).
|
||||
3. Check for analysis file: `.claude/epics/*/<N>-analysis.md` — if missing, run analysis first (or do both in sequence: analyze then start).
|
||||
4. Verify epic worktree exists: `git worktree list | grep "epic-<name>"` — if not: "❌ No worktree. Sync the epic first."
|
||||
|
||||
### Process
|
||||
|
||||
**Step 1 — Read the analysis**, identify which streams can start immediately vs. which have dependencies.
|
||||
|
||||
**Step 2 — Create progress tracking:**
|
||||
|
||||
```bash
|
||||
mkdir -p .claude/epics/<epic>/updates/<N>
|
||||
current_date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
```
|
||||
|
||||
Create `.claude/epics/<epic>/updates/<N>/stream-<X>.md` for each stream:
|
||||
|
||||
```markdown
|
||||
---
|
||||
issue: <N>
|
||||
stream: <stream_name>
|
||||
started: <datetime>
|
||||
status: in_progress
|
||||
---
|
||||
## Scope
|
||||
## Progress
|
||||
- Starting implementation
|
||||
```
|
||||
|
||||
**Step 3 — Launch parallel agents** for each stream that can start immediately:
|
||||
|
||||
```yaml
|
||||
Task:
|
||||
description: "Issue #<N> Stream <X>"
|
||||
subagent_type: "general-purpose"
|
||||
prompt: |
|
||||
You are working on Issue #<N> in the epic worktree at: ../epic-<name>/
|
||||
|
||||
Your stream: <stream_name>
|
||||
Your scope — files to modify: <file_patterns>
|
||||
Work to complete: <stream_description>
|
||||
|
||||
Instructions:
|
||||
1. Read full task from: .claude/epics/<epic>/<N>.md
|
||||
2. Read analysis from: .claude/epics/<epic>/<N>-analysis.md
|
||||
3. Work ONLY in your assigned files
|
||||
4. Commit frequently: "Issue #<N>: <specific change>"
|
||||
5. Update progress in: .claude/epics/<epic>/updates/<N>/stream-<X>.md
|
||||
6. If you need to touch files outside your scope, note it in your progress file and wait
|
||||
7. Never use --force on git operations
|
||||
|
||||
Complete your stream's work and mark status: completed when done.
|
||||
```
|
||||
|
||||
Streams with unmet dependencies are queued — launch them as their dependencies complete.
|
||||
|
||||
**Step 4 — Assign on GitHub:**
|
||||
|
||||
```bash
|
||||
gh issue edit <N> --add-assignee @me --add-label "in-progress"
|
||||
```
|
||||
|
||||
**Step 5 — Create execution status file** at `.claude/epics/<epic>/updates/<N>/execution.md`:
|
||||
|
||||
```markdown
|
||||
## Active Streams
|
||||
- Stream A: <name> — Started <time>
|
||||
- Stream B: <name> — Started <time>
|
||||
|
||||
## Queued
|
||||
- Stream C: <name> — Waiting on Stream A
|
||||
|
||||
## Completed
|
||||
(none yet)
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||
```
|
||||
✅ Started work on issue #<N>
|
||||
|
||||
Launched N agents:
|
||||
Stream A: <name> ✓ Started
|
||||
Stream B: <name> ✓ Started
|
||||
Stream C: <name> ⏸ Waiting (depends on A)
|
||||
|
||||
Monitor: check progress in .claude/epics/<epic>/updates/<N>/
|
||||
Sync updates: "sync issue <N>"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Starting a Full Epic
|
||||
|
||||
**Trigger**: User wants to launch parallel agents across all ready issues in an epic at once.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Verify `.claude/epics/<name>/epic.md` exists and has a `github:` field (i.e., it's been synced).
|
||||
- Check for uncommitted changes: `git status --porcelain` — block if dirty.
|
||||
- Verify epic branch exists: `git branch -a | grep "epic/<name>"`
|
||||
|
||||
### Process
|
||||
|
||||
**Step 1 — Read all task files** in `.claude/epics/<name>/`. Parse frontmatter for `status`, `depends_on`, `parallel`.
|
||||
|
||||
**Step 2 — Categorize tasks:**
|
||||
|
||||
- Ready: status=open, no unmet depends_on
|
||||
- Blocked: has unmet depends_on
|
||||
- In Progress: already has an execution file
|
||||
- Complete: status=closed
|
||||
|
||||
**Step 3 — Analyze any ready tasks** that don't have an analysis file yet (run issue analysis inline).
|
||||
|
||||
**Step 4 — Launch agents** for all ready tasks following the same per-issue agent launch pattern above.
|
||||
|
||||
**Step 5 — Create/update** `.claude/epics/<name>/execution-status.md` with all active agents and queued issues.
|
||||
|
||||
**Step 6 — As agents complete**, check if blocked issues are now unblocked and launch those agents.
|
||||
|
||||
---
|
||||
|
||||
## Agent Coordination Rules
|
||||
|
||||
When multiple agents work in the same worktree simultaneously:
|
||||
|
||||
- Each agent works only on files in its assigned stream scope.
|
||||
- Agents commit frequently with `Issue #<N>: <description>` format.
|
||||
- Before modifying a shared file, check `git status <file>` — if another agent has it modified, wait and pull first.
|
||||
- Agents sync via commits: `git pull --rebase origin epic/<name>` before starting new file work.
|
||||
- Conflicts are never auto-resolved — agents report them and pause.
|
||||
- No `--force` flags ever.
|
||||
|
||||
Shared files that commonly need coordination (types, config, package.json) should be handled by one designated stream; others pull after that commit.
|
||||
@@ -0,0 +1,111 @@
|
||||
# Plan — Capture Requirements
|
||||
|
||||
This phase turns an idea into a structured PRD, then converts the PRD into a technical epic ready for decomposition.
|
||||
|
||||
---
|
||||
|
||||
## Writing a PRD
|
||||
|
||||
**Trigger**: User wants to plan a new feature, product requirement, or area of work.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Check if `.claude/prds/<name>.md` already exists — if so, confirm overwrite before proceeding.
|
||||
- Ensure `.claude/prds/` directory exists; create it if not.
|
||||
- Feature name must be kebab-case (lowercase, letters/numbers/hyphens, starts with a letter). If not: "❌ Feature name must be kebab-case. Example: user-auth, payment-v2"
|
||||
|
||||
### Process
|
||||
|
||||
Conduct a genuine brainstorming session before writing anything. Ask the user:
|
||||
|
||||
- What problem does this solve?
|
||||
- Who are the users affected?
|
||||
- What does success look like?
|
||||
- What's explicitly out of scope?
|
||||
- What are the constraints (tech, time, resources)?
|
||||
|
||||
Then write `.claude/prds/<name>.md` with this frontmatter and structure:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: <feature-name>
|
||||
description: <one-line summary>
|
||||
status: backlog
|
||||
created: <run: date -u +"%Y-%m-%dT%H:%M:%SZ">
|
||||
---
|
||||
|
||||
# PRD: <feature-name>
|
||||
|
||||
## Executive Summary
|
||||
## Problem Statement
|
||||
## User Stories
|
||||
## Functional Requirements
|
||||
## Non-Functional Requirements
|
||||
## Success Criteria
|
||||
## Constraints & Assumptions
|
||||
## Out of Scope
|
||||
## Dependencies
|
||||
```
|
||||
|
||||
**Quality gates before saving:**
|
||||
|
||||
- No placeholder text in any section
|
||||
- User stories include acceptance criteria
|
||||
- Success criteria are measurable
|
||||
- Out of scope is explicitly listed
|
||||
|
||||
**After creation**: Confirm "✅ PRD created: `.claude/prds/<name>.md`" and suggest: "Ready to create technical epic? Say: parse the <name> PRD"
|
||||
|
||||
---
|
||||
|
||||
## Parsing a PRD into a Technical Epic
|
||||
|
||||
**Trigger**: User wants to convert an existing PRD into a technical implementation plan.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Verify `.claude/prds/<name>.md` exists with valid frontmatter (name, description, status, created).
|
||||
- Check if `.claude/epics/<name>/epic.md` already exists — confirm overwrite if so.
|
||||
|
||||
### Process
|
||||
|
||||
Read the PRD fully, then produce `.claude/epics/<name>/epic.md`:
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: <feature-name>
|
||||
status: backlog
|
||||
created: <run: date -u +"%Y-%m-%dT%H:%M:%SZ">
|
||||
progress: 0%
|
||||
prd: .claude/prds/<name>.md
|
||||
github: (will be set on sync)
|
||||
---
|
||||
|
||||
# Epic: <feature-name>
|
||||
|
||||
## Overview
|
||||
## Architecture Decisions
|
||||
## Technical Approach
|
||||
### Frontend Components
|
||||
### Backend Services
|
||||
### Infrastructure
|
||||
## Implementation Strategy
|
||||
## Task Breakdown Preview
|
||||
## Dependencies
|
||||
## Success Criteria (Technical)
|
||||
## Estimated Effort
|
||||
```
|
||||
|
||||
**Key constraints:**
|
||||
|
||||
- Aim for ≤10 tasks total — prefer simplicity over completeness.
|
||||
- Look for ways to leverage existing functionality before creating new code.
|
||||
- Identify parallelization opportunities in the task breakdown preview.
|
||||
|
||||
**After creation**: Confirm "✅ Epic created: `.claude/epics/<name>/epic.md`" and suggest: "Ready to decompose into tasks? Say: decompose the <name> epic"
|
||||
|
||||
---
|
||||
|
||||
## Editing a PRD or Epic
|
||||
|
||||
Read the file first, make targeted edits preserving all frontmatter. Update the `updated` frontmatter field with current datetime.
|
||||
@@ -0,0 +1,67 @@
|
||||
#!/bin/bash
|
||||
echo "Getting tasks..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "🚫 Blocked Tasks"
|
||||
echo "================"
|
||||
echo ""
|
||||
|
||||
found=0
|
||||
|
||||
for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
epic_name=$(basename "$epic_dir")
|
||||
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
|
||||
# Check if task is open
|
||||
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check for dependencies
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//' | sed 's/^\[//' | sed 's/\]$//' | sed 's/,/ /g' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
|
||||
if [ -n "$deps" ] && [ "$deps" != "depends_on:" ]; then
|
||||
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
||||
task_num=$(basename "$task_file" .md)
|
||||
|
||||
echo "⏸️ Task #$task_num - $task_name"
|
||||
echo " Epic: $epic_name"
|
||||
echo " Blocked by: [$deps]"
|
||||
|
||||
# Check status of dependencies
|
||||
open_deps=""
|
||||
for dep in $deps; do
|
||||
dep_file="$epic_dir$dep.md"
|
||||
if [ -f "$dep_file" ]; then
|
||||
dep_status=$(grep "^status:" "$dep_file" | head -1 | sed 's/^status: *//')
|
||||
[ "$dep_status" = "open" ] && open_deps="$open_deps #$dep"
|
||||
fi
|
||||
done
|
||||
|
||||
[ -n "$open_deps" ] && echo " Waiting for:$open_deps"
|
||||
echo ""
|
||||
((found++))
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
if [ $found -eq 0 ]; then
|
||||
echo "No blocked tasks found!"
|
||||
echo ""
|
||||
echo "💡 All tasks with dependencies are either completed or in progress."
|
||||
else
|
||||
echo "📊 Total blocked: $found tasks"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,94 @@
|
||||
#!/bin/bash
|
||||
echo "Getting epics..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
[ ! -d ".claude/epics" ] && echo "📁 No epics directory found. Create your first epic with: /pm:prd-parse <feature-name>" && exit 0
|
||||
[ -z "$(ls -d .claude/epics/*/ 2>/dev/null)" ] && echo "📁 No epics found. Create your first epic with: /pm:prd-parse <feature-name>" && exit 0
|
||||
|
||||
echo "📚 Project Epics"
|
||||
echo "================"
|
||||
echo ""
|
||||
|
||||
# Initialize arrays to store epics by status
|
||||
planning_epics=""
|
||||
in_progress_epics=""
|
||||
completed_epics=""
|
||||
|
||||
# Process all epics
|
||||
for dir in .claude/epics/*/; do
|
||||
[ -d "$dir" ] || continue
|
||||
[ -f "$dir/epic.md" ] || continue
|
||||
|
||||
# Extract metadata
|
||||
n=$(grep "^name:" "$dir/epic.md" | head -1 | sed 's/^name: *//')
|
||||
s=$(grep "^status:" "$dir/epic.md" | head -1 | sed 's/^status: *//' | tr '[:upper:]' '[:lower:]')
|
||||
p=$(grep "^progress:" "$dir/epic.md" | head -1 | sed 's/^progress: *//')
|
||||
g=$(grep "^github:" "$dir/epic.md" | head -1 | sed 's/^github: *//')
|
||||
|
||||
# Defaults
|
||||
[ -z "$n" ] && n=$(basename "$dir")
|
||||
[ -z "$p" ] && p="0%"
|
||||
|
||||
# Count tasks
|
||||
t=$(ls "$dir"/[0-9]*.md 2>/dev/null | wc -l)
|
||||
|
||||
# Format output with GitHub issue number if available
|
||||
if [ -n "$g" ]; then
|
||||
i=$(echo "$g" | grep -o '/[0-9]*$' | tr -d '/')
|
||||
entry=" 📋 ${dir}epic.md (#$i) - $p complete ($t tasks)"
|
||||
else
|
||||
entry=" 📋 ${dir}epic.md - $p complete ($t tasks)"
|
||||
fi
|
||||
|
||||
# Categorize by status (handle various status values)
|
||||
case "$s" in
|
||||
planning|draft|"")
|
||||
planning_epics="${planning_epics}${entry}\n"
|
||||
;;
|
||||
in-progress|in_progress|active|started)
|
||||
in_progress_epics="${in_progress_epics}${entry}\n"
|
||||
;;
|
||||
completed|complete|done|closed|finished)
|
||||
completed_epics="${completed_epics}${entry}\n"
|
||||
;;
|
||||
*)
|
||||
# Default to planning for unknown statuses
|
||||
planning_epics="${planning_epics}${entry}\n"
|
||||
;;
|
||||
esac
|
||||
done
|
||||
|
||||
# Display categorized epics
|
||||
echo "📝 Planning:"
|
||||
if [ -n "$planning_epics" ]; then
|
||||
echo -e "$planning_epics" | sed '/^$/d'
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🚀 In Progress:"
|
||||
if [ -n "$in_progress_epics" ]; then
|
||||
echo -e "$in_progress_epics" | sed '/^$/d'
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "✅ Completed:"
|
||||
if [ -n "$completed_epics" ]; then
|
||||
echo -e "$completed_epics" | sed '/^$/d'
|
||||
else
|
||||
echo " (none)"
|
||||
fi
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "📊 Summary"
|
||||
total=$(ls -d .claude/epics/*/ 2>/dev/null | wc -l)
|
||||
tasks=$(find .claude/epics -name "[0-9]*.md" 2>/dev/null | wc -l)
|
||||
echo " Total epics: $total"
|
||||
echo " Total tasks: $tasks"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,91 @@
|
||||
#!/bin/bash
|
||||
|
||||
epic_name="$1"
|
||||
|
||||
if [ -z "$epic_name" ]; then
|
||||
echo "❌ Please provide an epic name"
|
||||
echo "Usage: /pm:epic-show <epic-name>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Getting epic..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
epic_dir=".claude/epics/$epic_name"
|
||||
epic_file="$epic_dir/epic.md"
|
||||
|
||||
if [ ! -f "$epic_file" ]; then
|
||||
echo "❌ Epic not found: $epic_name"
|
||||
echo ""
|
||||
echo "Available epics:"
|
||||
for dir in .claude/epics/*/; do
|
||||
[ -d "$dir" ] && echo " • $(basename "$dir")"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
# Display epic details
|
||||
echo "📚 Epic: $epic_name"
|
||||
echo "================================"
|
||||
echo ""
|
||||
|
||||
# Extract metadata
|
||||
status=$(grep "^status:" "$epic_file" | head -1 | sed 's/^status: *//')
|
||||
progress=$(grep "^progress:" "$epic_file" | head -1 | sed 's/^progress: *//')
|
||||
github=$(grep "^github:" "$epic_file" | head -1 | sed 's/^github: *//')
|
||||
created=$(grep "^created:" "$epic_file" | head -1 | sed 's/^created: *//')
|
||||
|
||||
echo "📊 Metadata:"
|
||||
echo " Status: ${status:-planning}"
|
||||
echo " Progress: ${progress:-0%}"
|
||||
[ -n "$github" ] && echo " GitHub: $github"
|
||||
echo " Created: ${created:-unknown}"
|
||||
echo ""
|
||||
|
||||
# Show tasks
|
||||
echo "📝 Tasks:"
|
||||
task_count=0
|
||||
open_count=0
|
||||
closed_count=0
|
||||
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
|
||||
task_num=$(basename "$task_file" .md)
|
||||
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
||||
task_status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
parallel=$(grep "^parallel:" "$task_file" | head -1 | sed 's/^parallel: *//')
|
||||
|
||||
if [ "$task_status" = "closed" ] || [ "$task_status" = "completed" ]; then
|
||||
echo " ✅ #$task_num - $task_name"
|
||||
((closed_count++))
|
||||
else
|
||||
echo " ⬜ #$task_num - $task_name"
|
||||
[ "$parallel" = "true" ] && echo -n " (parallel)"
|
||||
((open_count++))
|
||||
fi
|
||||
|
||||
((task_count++))
|
||||
done
|
||||
|
||||
if [ $task_count -eq 0 ]; then
|
||||
echo " No tasks created yet"
|
||||
echo " Run: /pm:epic-decompose $epic_name"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📈 Statistics:"
|
||||
echo " Total tasks: $task_count"
|
||||
echo " Open: $open_count"
|
||||
echo " Closed: $closed_count"
|
||||
[ $task_count -gt 0 ] && echo " Completion: $((closed_count * 100 / task_count))%"
|
||||
|
||||
# Next actions
|
||||
echo ""
|
||||
echo "💡 Actions:"
|
||||
[ $task_count -eq 0 ] && echo " • Decompose into tasks: /pm:epic-decompose $epic_name"
|
||||
[ -z "$github" ] && [ $task_count -gt 0 ] && echo " • Sync to GitHub: /pm:epic-sync $epic_name"
|
||||
[ -n "$github" ] && [ "$status" != "completed" ] && echo " • Start work: /pm:epic-start $epic_name"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,90 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Getting status..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
epic_name="$1"
|
||||
|
||||
if [ -z "$epic_name" ]; then
|
||||
echo "❌ Please specify an epic name"
|
||||
echo "Usage: /pm:epic-status <epic-name>"
|
||||
echo ""
|
||||
echo "Available epics:"
|
||||
for dir in .claude/epics/*/; do
|
||||
[ -d "$dir" ] && echo " • $(basename "$dir")"
|
||||
done
|
||||
exit 1
|
||||
else
|
||||
# Show status for specific epic
|
||||
epic_dir=".claude/epics/$epic_name"
|
||||
epic_file="$epic_dir/epic.md"
|
||||
|
||||
if [ ! -f "$epic_file" ]; then
|
||||
echo "❌ Epic not found: $epic_name"
|
||||
echo ""
|
||||
echo "Available epics:"
|
||||
for dir in .claude/epics/*/; do
|
||||
[ -d "$dir" ] && echo " • $(basename "$dir")"
|
||||
done
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "📚 Epic Status: $epic_name"
|
||||
echo "================================"
|
||||
echo ""
|
||||
|
||||
# Extract metadata
|
||||
status=$(grep "^status:" "$epic_file" | head -1 | sed 's/^status: *//')
|
||||
progress=$(grep "^progress:" "$epic_file" | head -1 | sed 's/^progress: *//')
|
||||
github=$(grep "^github:" "$epic_file" | head -1 | sed 's/^github: *//')
|
||||
|
||||
# Count tasks
|
||||
total=0
|
||||
open=0
|
||||
closed=0
|
||||
blocked=0
|
||||
|
||||
# Use find to safely iterate over task files
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
((total++))
|
||||
|
||||
task_status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
deps=$(grep "^depends_on:" "$task_file" | head -1 | sed 's/^depends_on: *\[//' | sed 's/\]//')
|
||||
|
||||
if [ "$task_status" = "closed" ] || [ "$task_status" = "completed" ]; then
|
||||
((closed++))
|
||||
elif [ -n "$deps" ] && [ "$deps" != "depends_on:" ]; then
|
||||
((blocked++))
|
||||
else
|
||||
((open++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Display progress bar
|
||||
if [ $total -gt 0 ]; then
|
||||
percent=$((closed * 100 / total))
|
||||
filled=$((percent * 20 / 100))
|
||||
empty=$((20 - filled))
|
||||
|
||||
echo -n "Progress: ["
|
||||
[ $filled -gt 0 ] && printf '%0.s█' $(seq 1 $filled)
|
||||
[ $empty -gt 0 ] && printf '%0.s░' $(seq 1 $empty)
|
||||
echo "] $percent%"
|
||||
else
|
||||
echo "Progress: No tasks created"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📊 Breakdown:"
|
||||
echo " Total tasks: $total"
|
||||
echo " ✅ Completed: $closed"
|
||||
echo " 🔄 Available: $open"
|
||||
echo " ⏸️ Blocked: $blocked"
|
||||
|
||||
[ -n "$github" ] && echo ""
|
||||
[ -n "$github" ] && echo "🔗 GitHub: $github"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
echo "Helping..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "📚 Claude Code PM - Project Management System"
|
||||
echo "============================================="
|
||||
echo ""
|
||||
echo "🎯 Quick Start Workflow"
|
||||
echo " 1. /pm:prd-new <name> - Create a new PRD"
|
||||
echo " 2. /pm:prd-parse <name> - Convert PRD to epic"
|
||||
echo " 3. /pm:epic-decompose <name> - Break into tasks"
|
||||
echo " 4. /pm:epic-sync <name> - Push to GitHub"
|
||||
echo " 5. /pm:epic-start <name> - Start parallel execution"
|
||||
echo ""
|
||||
echo "📄 PRD Commands"
|
||||
echo " /pm:prd-new <name> - Launch brainstorming for new product requirement"
|
||||
echo " /pm:prd-parse <name> - Convert PRD to implementation epic"
|
||||
echo " /pm:prd-list - List all PRDs"
|
||||
echo " /pm:prd-edit <name> - Edit existing PRD"
|
||||
echo " /pm:prd-status - Show PRD implementation status"
|
||||
echo ""
|
||||
echo "📚 Epic Commands"
|
||||
echo " /pm:epic-decompose <name> - Break epic into task files"
|
||||
echo " /pm:epic-sync <name> - Push epic and tasks to GitHub"
|
||||
echo " /pm:epic-oneshot <name> - Decompose and sync in one command"
|
||||
echo " /pm:epic-list - List all epics"
|
||||
echo " /pm:epic-show <name> - Display epic and its tasks"
|
||||
echo " /pm:epic-status [name] - Show epic progress"
|
||||
echo " /pm:epic-close <name> - Mark epic as complete"
|
||||
echo " /pm:epic-edit <name> - Edit epic details"
|
||||
echo " /pm:epic-refresh <name> - Update epic progress from tasks"
|
||||
echo " /pm:epic-start <name> - Launch parallel agent execution"
|
||||
echo ""
|
||||
echo "📝 Issue Commands"
|
||||
echo " /pm:issue-show <num> - Display issue and sub-issues"
|
||||
echo " /pm:issue-status <num> - Check issue status"
|
||||
echo " /pm:issue-start <num> - Begin work with specialized agent"
|
||||
echo " /pm:issue-sync <num> - Push updates to GitHub"
|
||||
echo " /pm:issue-close <num> - Mark issue as complete"
|
||||
echo " /pm:issue-reopen <num> - Reopen closed issue"
|
||||
echo " /pm:issue-edit <num> - Edit issue details"
|
||||
echo " /pm:issue-analyze <num> - Analyze for parallel work streams"
|
||||
echo ""
|
||||
echo "🔄 Workflow Commands"
|
||||
echo " /pm:next - Show next priority tasks"
|
||||
echo " /pm:status - Overall project dashboard"
|
||||
echo " /pm:standup - Daily standup report"
|
||||
echo " /pm:blocked - Show blocked tasks"
|
||||
echo " /pm:in-progress - List work in progress"
|
||||
echo ""
|
||||
echo "🔗 Sync Commands"
|
||||
echo " /pm:sync - Full bidirectional sync with GitHub"
|
||||
echo " /pm:import <issue> - Import existing GitHub issues"
|
||||
echo ""
|
||||
echo "🔧 Maintenance Commands"
|
||||
echo " /pm:validate - Check system integrity"
|
||||
echo " /pm:clean - Archive completed work"
|
||||
echo " /pm:search <query> - Search across all content"
|
||||
echo ""
|
||||
echo "⚙️ Setup Commands"
|
||||
echo " /pm:init - Install dependencies and configure GitHub"
|
||||
echo " /pm:help - Show this help message"
|
||||
echo ""
|
||||
echo "💡 Tips"
|
||||
echo " • Use /pm:next to find available work"
|
||||
echo " • Run /pm:status for quick overview"
|
||||
echo " • Epic workflow: prd-new → prd-parse → epic-decompose → epic-sync"
|
||||
echo " • View README.md for complete documentation"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,74 @@
|
||||
#!/bin/bash
|
||||
echo "Getting status..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "🔄 In Progress Work"
|
||||
echo "==================="
|
||||
echo ""
|
||||
|
||||
# Check for active work in updates directories
|
||||
found=0
|
||||
|
||||
if [ -d ".claude/epics" ]; then
|
||||
for updates_dir in .claude/epics/*/updates/*/; do
|
||||
[ -d "$updates_dir" ] || continue
|
||||
|
||||
issue_num=$(basename "$updates_dir")
|
||||
epic_name=$(basename $(dirname $(dirname "$updates_dir")))
|
||||
|
||||
if [ -f "$updates_dir/progress.md" ]; then
|
||||
completion=$(grep "^completion:" "$updates_dir/progress.md" | head -1 | sed 's/^completion: *//')
|
||||
[ -z "$completion" ] && completion="0%"
|
||||
|
||||
# Get task name from the task file
|
||||
task_file=".claude/epics/$epic_name/$issue_num.md"
|
||||
if [ -f "$task_file" ]; then
|
||||
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
||||
else
|
||||
task_name="Unknown task"
|
||||
fi
|
||||
|
||||
echo "📝 Issue #$issue_num - $task_name"
|
||||
echo " Epic: $epic_name"
|
||||
echo " Progress: $completion complete"
|
||||
|
||||
# Check for recent updates
|
||||
if [ -f "$updates_dir/progress.md" ]; then
|
||||
last_update=$(grep "^last_sync:" "$updates_dir/progress.md" | head -1 | sed 's/^last_sync: *//')
|
||||
[ -n "$last_update" ] && echo " Last update: $last_update"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
((found++))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
|
||||
# Also check for in-progress epics
|
||||
echo "📚 Active Epics:"
|
||||
for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
[ -f "$epic_dir/epic.md" ] || continue
|
||||
|
||||
status=$(grep "^status:" "$epic_dir/epic.md" | head -1 | sed 's/^status: *//')
|
||||
if [ "$status" = "in-progress" ] || [ "$status" = "active" ]; then
|
||||
epic_name=$(grep "^name:" "$epic_dir/epic.md" | head -1 | sed 's/^name: *//')
|
||||
progress=$(grep "^progress:" "$epic_dir/epic.md" | head -1 | sed 's/^progress: *//')
|
||||
[ -z "$epic_name" ] && epic_name=$(basename "$epic_dir")
|
||||
[ -z "$progress" ] && progress="0%"
|
||||
|
||||
echo " • $epic_name - $progress complete"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
if [ $found -eq 0 ]; then
|
||||
echo "No active work items found."
|
||||
echo ""
|
||||
echo "💡 Start work with: /pm:next"
|
||||
else
|
||||
echo "📊 Total active items: $found"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,192 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Initializing..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo " ██████╗ ██████╗██████╗ ███╗ ███╗"
|
||||
echo "██╔════╝██╔════╝██╔══██╗████╗ ████║"
|
||||
echo "██║ ██║ ██████╔╝██╔████╔██║"
|
||||
echo "╚██████╗╚██████╗██║ ██║ ╚═╝ ██║"
|
||||
echo " ╚═════╝ ╚═════╝╚═╝ ╚═╝ ╚═╝"
|
||||
|
||||
echo "┌─────────────────────────────────┐"
|
||||
echo "│ Claude Code Project Management │"
|
||||
echo "│ by https://x.com/aroussi │"
|
||||
echo "└─────────────────────────────────┘"
|
||||
echo "https://github.com/automazeio/ccpm"
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "🚀 Initializing Claude Code PM System"
|
||||
echo "======================================"
|
||||
echo ""
|
||||
|
||||
# Check for required tools
|
||||
echo "🔍 Checking dependencies..."
|
||||
|
||||
# Check gh CLI
|
||||
if command -v gh &> /dev/null; then
|
||||
echo " ✅ GitHub CLI (gh) installed"
|
||||
else
|
||||
echo " ❌ GitHub CLI (gh) not found"
|
||||
echo ""
|
||||
echo " Installing gh..."
|
||||
if command -v brew &> /dev/null; then
|
||||
brew install gh
|
||||
elif command -v apt-get &> /dev/null; then
|
||||
sudo apt-get update && sudo apt-get install gh
|
||||
else
|
||||
echo " Please install GitHub CLI manually: https://cli.github.com/"
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
# Check gh auth status
|
||||
echo ""
|
||||
echo "🔐 Checking GitHub authentication..."
|
||||
if gh auth status &> /dev/null; then
|
||||
echo " ✅ GitHub authenticated"
|
||||
else
|
||||
echo " ⚠️ GitHub not authenticated"
|
||||
echo " Running: gh auth login"
|
||||
gh auth login
|
||||
fi
|
||||
|
||||
# Check for gh-sub-issue extension
|
||||
echo ""
|
||||
echo "📦 Checking gh extensions..."
|
||||
if gh extension list | grep -q "yahsan2/gh-sub-issue"; then
|
||||
echo " ✅ gh-sub-issue extension installed"
|
||||
else
|
||||
echo " 📥 Installing gh-sub-issue extension..."
|
||||
gh extension install yahsan2/gh-sub-issue
|
||||
fi
|
||||
|
||||
# Create directory structure
|
||||
echo ""
|
||||
echo "📁 Creating directory structure..."
|
||||
mkdir -p .claude/prds
|
||||
mkdir -p .claude/epics
|
||||
mkdir -p .claude/rules
|
||||
mkdir -p .claude/agents
|
||||
mkdir -p .claude/scripts/pm
|
||||
echo " ✅ Directories created"
|
||||
|
||||
# Copy scripts if in main repo
|
||||
if [ -d "scripts/pm" ] && [ ! "$(pwd)" = *"/.claude"* ]; then
|
||||
echo ""
|
||||
echo "📝 Copying PM scripts..."
|
||||
cp -r scripts/pm/* .claude/scripts/pm/
|
||||
chmod +x .claude/scripts/pm/*.sh
|
||||
echo " ✅ Scripts copied and made executable"
|
||||
fi
|
||||
|
||||
# Check for git
|
||||
echo ""
|
||||
echo "🔗 Checking Git configuration..."
|
||||
if git rev-parse --git-dir > /dev/null 2>&1; then
|
||||
echo " ✅ Git repository detected"
|
||||
|
||||
# Check remote
|
||||
if git remote -v | grep -q origin; then
|
||||
remote_url=$(git remote get-url origin)
|
||||
echo " ✅ Remote configured: $remote_url"
|
||||
|
||||
# Check if remote is the CCPM template repository
|
||||
if [[ "$remote_url" == *"automazeio/ccpm"* ]] || [[ "$remote_url" == *"automazeio/ccpm.git"* ]]; then
|
||||
echo ""
|
||||
echo " ⚠️ WARNING: Your remote origin points to the CCPM template repository!"
|
||||
echo " This means any issues you create will go to the template repo, not your project."
|
||||
echo ""
|
||||
echo " To fix this:"
|
||||
echo " 1. Fork the repository or create your own on GitHub"
|
||||
echo " 2. Update your remote:"
|
||||
echo " git remote set-url origin https://github.com/YOUR_USERNAME/YOUR_REPO.git"
|
||||
echo ""
|
||||
else
|
||||
# Create GitHub labels if this is a GitHub repository
|
||||
if gh repo view &> /dev/null; then
|
||||
echo ""
|
||||
echo "🏷️ Creating GitHub labels..."
|
||||
|
||||
# Create base labels with improved error handling
|
||||
epic_created=false
|
||||
task_created=false
|
||||
|
||||
if gh label create "epic" --color "0E8A16" --description "Epic issue containing multiple related tasks" --force 2>/dev/null; then
|
||||
epic_created=true
|
||||
elif gh label list 2>/dev/null | grep -q "^epic"; then
|
||||
epic_created=true # Label already exists
|
||||
fi
|
||||
|
||||
if gh label create "task" --color "1D76DB" --description "Individual task within an epic" --force 2>/dev/null; then
|
||||
task_created=true
|
||||
elif gh label list 2>/dev/null | grep -q "^task"; then
|
||||
task_created=true # Label already exists
|
||||
fi
|
||||
|
||||
# Report results
|
||||
if $epic_created && $task_created; then
|
||||
echo " ✅ GitHub labels created (epic, task)"
|
||||
elif $epic_created || $task_created; then
|
||||
echo " ⚠️ Some GitHub labels created (epic: $epic_created, task: $task_created)"
|
||||
else
|
||||
echo " ❌ Could not create GitHub labels (check repository permissions)"
|
||||
fi
|
||||
else
|
||||
echo " ℹ️ Not a GitHub repository - skipping label creation"
|
||||
fi
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ No remote configured"
|
||||
echo " Add with: git remote add origin <url>"
|
||||
fi
|
||||
else
|
||||
echo " ⚠️ Not a git repository"
|
||||
echo " Initialize with: git init"
|
||||
fi
|
||||
|
||||
# Create CLAUDE.md if it doesn't exist
|
||||
if [ ! -f "CLAUDE.md" ]; then
|
||||
echo ""
|
||||
echo "📄 Creating CLAUDE.md..."
|
||||
cat > CLAUDE.md << 'EOF'
|
||||
# CLAUDE.md
|
||||
|
||||
> Think carefully and implement the most concise solution that changes as little code as possible.
|
||||
|
||||
## Project-Specific Instructions
|
||||
|
||||
Add your project-specific instructions here.
|
||||
|
||||
## Testing
|
||||
|
||||
Always run tests before committing:
|
||||
- `npm test` or equivalent for your stack
|
||||
|
||||
## Code Style
|
||||
|
||||
Follow existing patterns in the codebase.
|
||||
EOF
|
||||
echo " ✅ CLAUDE.md created"
|
||||
fi
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "✅ Initialization Complete!"
|
||||
echo "=========================="
|
||||
echo ""
|
||||
echo "📊 System Status:"
|
||||
gh --version | head -1
|
||||
echo " Extensions: $(gh extension list | wc -l) installed"
|
||||
echo " Auth: $(gh auth status 2>&1 | grep -o 'Logged in to [^ ]*' || echo 'Not authenticated')"
|
||||
echo ""
|
||||
echo "🎯 Next Steps:"
|
||||
echo " 1. Create your first PRD: /pm:prd-new <feature-name>"
|
||||
echo " 2. View help: /pm:help"
|
||||
echo " 3. Check status: /pm:status"
|
||||
echo ""
|
||||
echo "📚 Documentation: README.md"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,61 @@
|
||||
#!/bin/bash
|
||||
echo "Getting status..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "📋 Next Available Tasks"
|
||||
echo "======================="
|
||||
echo ""
|
||||
|
||||
# Find tasks that are open and have no dependencies or whose dependencies are closed
|
||||
found=0
|
||||
|
||||
for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
epic_name=$(basename "$epic_dir")
|
||||
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
|
||||
# Check if task is open
|
||||
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
# Check dependencies
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//' | sed 's/^\[//' | sed 's/\]$//' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
|
||||
# If no dependencies or empty, task is available
|
||||
if [ -z "$deps" ] || [ "$deps" = "depends_on:" ]; then
|
||||
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
||||
task_num=$(basename "$task_file" .md)
|
||||
parallel=$(grep "^parallel:" "$task_file" | head -1 | sed 's/^parallel: *//')
|
||||
|
||||
echo "✅ Ready: #$task_num - $task_name"
|
||||
echo " Epic: $epic_name"
|
||||
[ "$parallel" = "true" ] && echo " 🔄 Can run in parallel"
|
||||
echo ""
|
||||
((found++))
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
if [ $found -eq 0 ]; then
|
||||
echo "No available tasks found."
|
||||
echo ""
|
||||
echo "💡 Suggestions:"
|
||||
echo " • Check blocked tasks: /pm:blocked"
|
||||
echo " • View all tasks: /pm:epic-list"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📊 Summary: $found tasks ready to start"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,89 @@
|
||||
# !/bin/bash
|
||||
# Check if PRD directory exists
|
||||
if [ ! -d ".claude/prds" ]; then
|
||||
echo "📁 No PRD directory found. Create your first PRD with: /pm:prd-new <feature-name>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Check for PRD files
|
||||
if ! ls .claude/prds/*.md >/dev/null 2>&1; then
|
||||
echo "📁 No PRDs found. Create your first PRD with: /pm:prd-new <feature-name>"
|
||||
exit 0
|
||||
fi
|
||||
|
||||
# Initialize counters
|
||||
backlog_count=0
|
||||
in_progress_count=0
|
||||
implemented_count=0
|
||||
total_count=0
|
||||
|
||||
echo "Getting PRDs..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
|
||||
echo "📋 PRD List"
|
||||
echo "==========="
|
||||
echo ""
|
||||
|
||||
# Display by status groups
|
||||
echo "🔍 Backlog PRDs:"
|
||||
for file in .claude/prds/*.md; do
|
||||
[ -f "$file" ] || continue
|
||||
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
||||
if [ "$status" = "backlog" ] || [ "$status" = "draft" ] || [ -z "$status" ]; then
|
||||
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
||||
desc=$(grep "^description:" "$file" | head -1 | sed 's/^description: *//')
|
||||
[ -z "$name" ] && name=$(basename "$file" .md)
|
||||
[ -z "$desc" ] && desc="No description"
|
||||
# echo " 📋 $name - $desc"
|
||||
echo " 📋 $file - $desc"
|
||||
((backlog_count++))
|
||||
fi
|
||||
((total_count++))
|
||||
done
|
||||
[ $backlog_count -eq 0 ] && echo " (none)"
|
||||
|
||||
echo ""
|
||||
echo "🔄 In-Progress PRDs:"
|
||||
for file in .claude/prds/*.md; do
|
||||
[ -f "$file" ] || continue
|
||||
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
||||
if [ "$status" = "in-progress" ] || [ "$status" = "active" ]; then
|
||||
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
||||
desc=$(grep "^description:" "$file" | head -1 | sed 's/^description: *//')
|
||||
[ -z "$name" ] && name=$(basename "$file" .md)
|
||||
[ -z "$desc" ] && desc="No description"
|
||||
# echo " 📋 $name - $desc"
|
||||
echo " 📋 $file - $desc"
|
||||
((in_progress_count++))
|
||||
fi
|
||||
done
|
||||
[ $in_progress_count -eq 0 ] && echo " (none)"
|
||||
|
||||
echo ""
|
||||
echo "✅ Implemented PRDs:"
|
||||
for file in .claude/prds/*.md; do
|
||||
[ -f "$file" ] || continue
|
||||
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
||||
if [ "$status" = "implemented" ] || [ "$status" = "completed" ] || [ "$status" = "done" ]; then
|
||||
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
||||
desc=$(grep "^description:" "$file" | head -1 | sed 's/^description: *//')
|
||||
[ -z "$name" ] && name=$(basename "$file" .md)
|
||||
[ -z "$desc" ] && desc="No description"
|
||||
# echo " 📋 $name - $desc"
|
||||
echo " 📋 $file - $desc"
|
||||
((implemented_count++))
|
||||
fi
|
||||
done
|
||||
[ $implemented_count -eq 0 ] && echo " (none)"
|
||||
|
||||
# Display summary
|
||||
echo ""
|
||||
echo "📊 PRD Summary"
|
||||
echo " Total PRDs: $total_count"
|
||||
echo " Backlog: $backlog_count"
|
||||
echo " In-Progress: $in_progress_count"
|
||||
echo " Implemented: $implemented_count"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,63 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "📄 PRD Status Report"
|
||||
echo "===================="
|
||||
echo ""
|
||||
|
||||
if [ ! -d ".claude/prds" ]; then
|
||||
echo "No PRD directory found."
|
||||
exit 0
|
||||
fi
|
||||
|
||||
total=$(ls .claude/prds/*.md 2>/dev/null | wc -l)
|
||||
[ $total -eq 0 ] && echo "No PRDs found." && exit 0
|
||||
|
||||
# Count by status
|
||||
backlog=0
|
||||
in_progress=0
|
||||
implemented=0
|
||||
|
||||
for file in .claude/prds/*.md; do
|
||||
[ -f "$file" ] || continue
|
||||
status=$(grep "^status:" "$file" | head -1 | sed 's/^status: *//')
|
||||
|
||||
case "$status" in
|
||||
backlog|draft|"") ((backlog++)) ;;
|
||||
in-progress|active) ((in_progress++)) ;;
|
||||
implemented|completed|done) ((implemented++)) ;;
|
||||
*) ((backlog++)) ;;
|
||||
esac
|
||||
done
|
||||
|
||||
echo "Getting status..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
# Display chart
|
||||
echo "📊 Distribution:"
|
||||
echo "================"
|
||||
|
||||
echo ""
|
||||
echo " Backlog: $(printf '%-3d' $backlog) [$(printf '%0.s█' $(seq 1 $((backlog*20/total))))]"
|
||||
echo " In Progress: $(printf '%-3d' $in_progress) [$(printf '%0.s█' $(seq 1 $((in_progress*20/total))))]"
|
||||
echo " Implemented: $(printf '%-3d' $implemented) [$(printf '%0.s█' $(seq 1 $((implemented*20/total))))]"
|
||||
echo ""
|
||||
echo " Total PRDs: $total"
|
||||
|
||||
# Recent activity
|
||||
echo ""
|
||||
echo "📅 Recent PRDs (last 5 modified):"
|
||||
ls -t .claude/prds/*.md 2>/dev/null | head -5 | while read file; do
|
||||
name=$(grep "^name:" "$file" | head -1 | sed 's/^name: *//')
|
||||
[ -z "$name" ] && name=$(basename "$file" .md)
|
||||
echo " • $name"
|
||||
done
|
||||
|
||||
# Suggestions
|
||||
echo ""
|
||||
echo "💡 Next Actions:"
|
||||
[ $backlog -gt 0 ] && echo " • Parse backlog PRDs to epics: /pm:prd-parse <name>"
|
||||
[ $in_progress -gt 0 ] && echo " • Check progress on active PRDs: /pm:epic-status <name>"
|
||||
[ $total -eq 0 ] && echo " • Create your first PRD: /pm:prd-new <name>"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,71 @@
|
||||
#!/bin/bash
|
||||
|
||||
query="$1"
|
||||
|
||||
if [ -z "$query" ]; then
|
||||
echo "❌ Please provide a search query"
|
||||
echo "Usage: /pm:search <query>"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
echo "Searching for '$query'..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "🔍 Search results for: '$query'"
|
||||
echo "================================"
|
||||
echo ""
|
||||
|
||||
# Search in PRDs
|
||||
if [ -d ".claude/prds" ]; then
|
||||
echo "📄 PRDs:"
|
||||
results=$(grep -l -i "$query" .claude/prds/*.md 2>/dev/null)
|
||||
if [ -n "$results" ]; then
|
||||
for file in $results; do
|
||||
name=$(basename "$file" .md)
|
||||
matches=$(grep -c -i "$query" "$file")
|
||||
echo " • $name ($matches matches)"
|
||||
done
|
||||
else
|
||||
echo " No matches"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Search in Epics
|
||||
if [ -d ".claude/epics" ]; then
|
||||
echo "📚 Epics:"
|
||||
results=$(find .claude/epics -name "epic.md" -exec grep -l -i "$query" {} \; 2>/dev/null)
|
||||
if [ -n "$results" ]; then
|
||||
for file in $results; do
|
||||
epic_name=$(basename $(dirname "$file"))
|
||||
matches=$(grep -c -i "$query" "$file")
|
||||
echo " • $epic_name ($matches matches)"
|
||||
done
|
||||
else
|
||||
echo " No matches"
|
||||
fi
|
||||
echo ""
|
||||
fi
|
||||
|
||||
# Search in Tasks
|
||||
if [ -d ".claude/epics" ]; then
|
||||
echo "📝 Tasks:"
|
||||
results=$(find .claude/epics -name "[0-9]*.md" -exec grep -l -i "$query" {} \; 2>/dev/null | head -10)
|
||||
if [ -n "$results" ]; then
|
||||
for file in $results; do
|
||||
epic_name=$(basename $(dirname "$file"))
|
||||
task_num=$(basename "$file" .md)
|
||||
echo " • Task #$task_num in $epic_name"
|
||||
done
|
||||
else
|
||||
echo " No matches"
|
||||
fi
|
||||
fi
|
||||
|
||||
# Summary
|
||||
total=$(find .claude -name "*.md" -exec grep -l -i "$query" {} \; 2>/dev/null | wc -l)
|
||||
echo ""
|
||||
echo "📊 Total files with matches: $total"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,86 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "📅 Daily Standup - $(date '+%Y-%m-%d')"
|
||||
echo "================================"
|
||||
echo ""
|
||||
|
||||
today=$(date '+%Y-%m-%d')
|
||||
|
||||
echo "Getting status..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "📝 Today's Activity:"
|
||||
echo "===================="
|
||||
echo ""
|
||||
|
||||
# Find files modified today
|
||||
recent_files=$(find .claude -name "*.md" -mtime -1 2>/dev/null)
|
||||
|
||||
if [ -n "$recent_files" ]; then
|
||||
# Count by type
|
||||
prd_count=$(echo "$recent_files" | grep -c "/prds/" 2>/dev/null | tr -d '[:space:]')
|
||||
epic_count=$(echo "$recent_files" | grep -c "/epic.md" 2>/dev/null | tr -d '[:space:]')
|
||||
task_count=$(echo "$recent_files" | grep -c "/[0-9]*.md" 2>/dev/null | tr -d '[:space:]')
|
||||
update_count=$(echo "$recent_files" | grep -c "/updates/" 2>/dev/null | tr -d '[:space:]')
|
||||
prd_count=${prd_count:-0}; epic_count=${epic_count:-0}; task_count=${task_count:-0}; update_count=${update_count:-0}
|
||||
|
||||
[ "$prd_count" -gt 0 ] && echo " • Modified $prd_count PRD(s)"
|
||||
[ "$epic_count" -gt 0 ] && echo " • Updated $epic_count epic(s)"
|
||||
[ "$task_count" -gt 0 ] && echo " • Worked on $task_count task(s)"
|
||||
[ "$update_count" -gt 0 ] && echo " • Posted $update_count progress update(s)"
|
||||
else
|
||||
echo " No activity recorded today"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "🔄 Currently In Progress:"
|
||||
# Show active work items
|
||||
for updates_dir in .claude/epics/*/updates/*/; do
|
||||
[ -d "$updates_dir" ] || continue
|
||||
if [ -f "$updates_dir/progress.md" ]; then
|
||||
issue_num=$(basename "$updates_dir")
|
||||
epic_name=$(basename $(dirname $(dirname "$updates_dir")))
|
||||
completion=$(grep "^completion:" "$updates_dir/progress.md" | head -1 | sed 's/^completion: *//')
|
||||
echo " • Issue #$issue_num ($epic_name) - ${completion:-0%} complete"
|
||||
fi
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "⏭️ Next Available Tasks:"
|
||||
# Show top 3 available tasks
|
||||
count=0
|
||||
for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
for task_file in "$epic_dir"/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
status=$(grep "^status:" "$task_file" | head -1 | sed 's/^status: *//')
|
||||
if [ "$status" != "open" ] && [ -n "$status" ]; then
|
||||
continue
|
||||
fi
|
||||
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//' | sed 's/^\[//' | sed 's/\]$//' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
if [ -z "$deps" ] || [ "$deps" = "depends_on:" ]; then
|
||||
task_name=$(grep "^name:" "$task_file" | head -1 | sed 's/^name: *//')
|
||||
task_num=$(basename "$task_file" .md)
|
||||
echo " • #$task_num - $task_name"
|
||||
((count++))
|
||||
[ $count -ge 3 ] && break 2
|
||||
fi
|
||||
done
|
||||
done
|
||||
|
||||
echo ""
|
||||
echo "📊 Quick Stats:"
|
||||
total_tasks=$(find .claude/epics -name "[0-9]*.md" 2>/dev/null | wc -l)
|
||||
open_tasks=$(find .claude/epics -name "[0-9]*.md" -exec grep -l "^status: *open" {} \; 2>/dev/null | wc -l)
|
||||
closed_tasks=$(find .claude/epics -name "[0-9]*.md" -exec grep -l "^status: *closed" {} \; 2>/dev/null | wc -l)
|
||||
echo " Tasks: $open_tasks open, $closed_tasks closed, $total_tasks total"
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,42 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Getting status..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
|
||||
echo "📊 Project Status"
|
||||
echo "================"
|
||||
echo ""
|
||||
|
||||
echo "📄 PRDs:"
|
||||
if [ -d ".claude/prds" ]; then
|
||||
total=$(ls .claude/prds/*.md 2>/dev/null | wc -l)
|
||||
echo " Total: $total"
|
||||
else
|
||||
echo " No PRDs found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📚 Epics:"
|
||||
if [ -d ".claude/epics" ]; then
|
||||
total=$(ls -d .claude/epics/*/ 2>/dev/null | grep -v '/archived/$' | wc -l)
|
||||
echo " Total: $total"
|
||||
else
|
||||
echo " No epics found"
|
||||
fi
|
||||
|
||||
echo ""
|
||||
echo "📝 Tasks:"
|
||||
if [ -d ".claude/epics" ]; then
|
||||
total=$(find .claude/epics -path "*/archived/*" -prune -o -name "[0-9]*.md" -print 2>/dev/null | wc -l)
|
||||
open=$(find .claude/epics -path "*/archived/*" -prune -o -name "[0-9]*.md" -print 2>/dev/null | xargs grep -l "^status: *open" 2>/dev/null | wc -l)
|
||||
closed=$(find .claude/epics -path "*/archived/*" -prune -o -name "[0-9]*.md" -print 2>/dev/null | xargs grep -l "^status: *closed" 2>/dev/null | wc -l)
|
||||
echo " Open: $open"
|
||||
echo " Closed: $closed"
|
||||
echo " Total: $total"
|
||||
else
|
||||
echo " No tasks found"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,96 @@
|
||||
#!/bin/bash
|
||||
|
||||
echo "Validating PM System..."
|
||||
echo ""
|
||||
echo ""
|
||||
|
||||
echo "🔍 Validating PM System"
|
||||
echo "======================="
|
||||
echo ""
|
||||
|
||||
errors=0
|
||||
warnings=0
|
||||
|
||||
# Check directory structure
|
||||
echo "📁 Directory Structure:"
|
||||
[ -d ".claude" ] && echo " ✅ .claude directory exists" || { echo " ❌ .claude directory missing"; ((errors++)); }
|
||||
[ -d ".claude/prds" ] && echo " ✅ PRDs directory exists" || echo " ⚠️ PRDs directory missing"
|
||||
[ -d ".claude/epics" ] && echo " ✅ Epics directory exists" || echo " ⚠️ Epics directory missing"
|
||||
[ -d ".claude/rules" ] && echo " ✅ Rules directory exists" || echo " ⚠️ Rules directory missing"
|
||||
echo ""
|
||||
|
||||
# Check for orphaned files
|
||||
echo "🗂️ Data Integrity:"
|
||||
|
||||
# Check epics have epic.md files
|
||||
for epic_dir in .claude/epics/*/; do
|
||||
[ -d "$epic_dir" ] || continue
|
||||
if [ ! -f "$epic_dir/epic.md" ]; then
|
||||
echo " ⚠️ Missing epic.md in $(basename "$epic_dir")"
|
||||
((warnings++))
|
||||
fi
|
||||
done
|
||||
|
||||
# Check for tasks without epics
|
||||
orphaned=$(find .claude -name "[0-9]*.md" -not -path ".claude/epics/*/*" 2>/dev/null | wc -l)
|
||||
[ $orphaned -gt 0 ] && echo " ⚠️ Found $orphaned orphaned task files" && ((warnings++))
|
||||
|
||||
# Check for broken references
|
||||
echo ""
|
||||
echo "🔗 Reference Check:"
|
||||
|
||||
for task_file in .claude/epics/*/[0-9]*.md; do
|
||||
[ -f "$task_file" ] || continue
|
||||
|
||||
deps_line=$(grep "^depends_on:" "$task_file" | head -1)
|
||||
if [ -n "$deps_line" ]; then
|
||||
deps=$(echo "$deps_line" | sed 's/^depends_on: *//' | sed 's/^\[//' | sed 's/\]$//' | sed 's/,/ /g' | sed 's/^[[:space:]]*//' | sed 's/[[:space:]]*$//')
|
||||
[ -z "$deps" ] && deps=""
|
||||
else
|
||||
deps=""
|
||||
fi
|
||||
if [ -n "$deps" ] && [ "$deps" != "depends_on:" ]; then
|
||||
epic_dir=$(dirname "$task_file")
|
||||
for dep in $deps; do
|
||||
if [ ! -f "$epic_dir/$dep.md" ]; then
|
||||
echo " ⚠️ Task $(basename "$task_file" .md) references missing task: $dep"
|
||||
((warnings++))
|
||||
fi
|
||||
done
|
||||
fi
|
||||
done
|
||||
|
||||
if [ $warnings -eq 0 ] && [ $errors -eq 0 ]; then
|
||||
echo " ✅ All references valid"
|
||||
fi
|
||||
|
||||
# Check frontmatter
|
||||
echo ""
|
||||
echo "📝 Frontmatter Validation:"
|
||||
invalid=0
|
||||
|
||||
for file in $(find .claude -name "*.md" -path "*/epics/*" -o -path "*/prds/*" 2>/dev/null); do
|
||||
if ! grep -q "^---" "$file"; then
|
||||
echo " ⚠️ Missing frontmatter: $(basename "$file")"
|
||||
((invalid++))
|
||||
fi
|
||||
done
|
||||
|
||||
[ $invalid -eq 0 ] && echo " ✅ All files have frontmatter"
|
||||
|
||||
# Summary
|
||||
echo ""
|
||||
echo "📊 Validation Summary:"
|
||||
echo " Errors: $errors"
|
||||
echo " Warnings: $warnings"
|
||||
echo " Invalid files: $invalid"
|
||||
|
||||
if [ $errors -eq 0 ] && [ $warnings -eq 0 ] && [ $invalid -eq 0 ]; then
|
||||
echo ""
|
||||
echo "✅ System is healthy!"
|
||||
else
|
||||
echo ""
|
||||
echo "💡 Run /pm:clean to fix some issues automatically"
|
||||
fi
|
||||
|
||||
exit 0
|
||||
@@ -0,0 +1,111 @@
|
||||
# Structure — Break Down an Epic
|
||||
|
||||
This phase converts a technical epic into concrete, numbered task files with dependency and parallelization metadata.
|
||||
|
||||
---
|
||||
|
||||
## Epic Decomposition
|
||||
|
||||
**Trigger**: User wants to break an epic into actionable tasks.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Verify `.claude/epics/<name>/epic.md` exists with valid frontmatter.
|
||||
- If numbered task files (001.md, 002.md...) already exist in the epic directory, list them and confirm deletion before recreating.
|
||||
- If epic status is "completed", warn the user before proceeding.
|
||||
|
||||
### Process
|
||||
|
||||
Read the epic fully. Analyze for parallelism — which pieces of work can happen simultaneously without file conflicts?
|
||||
|
||||
**Task types to consider:**
|
||||
|
||||
- Setup: environment, scaffolding, dependencies
|
||||
- Data: models, schemas, migrations
|
||||
- API: endpoints, services, integration
|
||||
- UI: components, pages, styling
|
||||
- Tests: unit, integration, e2e
|
||||
- Docs: README, API docs, changelogs
|
||||
|
||||
**Parallelization strategy by epic size:**
|
||||
|
||||
- Small (<5 tasks): create sequentially
|
||||
- Medium (5–10 tasks): batch into 2–3 groups, spawn parallel Task agents
|
||||
- Large (>10 tasks): analyze dependencies first, launch parallel agents (max 5 concurrent), create dependent tasks after prerequisites
|
||||
|
||||
For parallel creation, use the Task tool:
|
||||
|
||||
```yaml
|
||||
Task:
|
||||
description: "Create task files batch N"
|
||||
subagent_type: "general-purpose"
|
||||
prompt: |
|
||||
Create task files for epic: <name>
|
||||
Tasks to create: [list 3-4 tasks]
|
||||
Save to: .claude/epics/<name>/001.md, 002.md, etc.
|
||||
Follow the task file format exactly.
|
||||
Return: list of files created.
|
||||
```
|
||||
|
||||
### Task File Format
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: <Task Title>
|
||||
status: open
|
||||
created: <run: date -u +"%Y-%m-%dT%H:%M:%SZ">
|
||||
updated: <same as created>
|
||||
github: (will be set on sync)
|
||||
depends_on: []
|
||||
parallel: true
|
||||
conflicts_with: []
|
||||
---
|
||||
|
||||
# Task: <Task Title>
|
||||
|
||||
## Description
|
||||
|
||||
## Acceptance Criteria
|
||||
- [ ]
|
||||
|
||||
## Technical Details
|
||||
|
||||
## Dependencies
|
||||
|
||||
## Effort Estimate
|
||||
- Size: XS/S/M/L/XL
|
||||
- Hours: N
|
||||
|
||||
## Definition of Done
|
||||
- [ ] Code implemented
|
||||
- [ ] Tests written and passing
|
||||
- [ ] Code reviewed
|
||||
```
|
||||
|
||||
**Numbering**: sequential 001.md, 002.md, etc. Tasks are renamed to GitHub issue numbers after sync — do not hard-code dependencies by filename, use the `depends_on` array.
|
||||
|
||||
### After Creating All Tasks
|
||||
|
||||
Append a summary to the epic file:
|
||||
|
||||
```markdown
|
||||
## Tasks Created
|
||||
- [ ] 001.md - <Title> (parallel: true/false)
|
||||
- [ ] 002.md - <Title> (parallel: true/false)
|
||||
|
||||
Total tasks: N
|
||||
Parallel tasks: N
|
||||
Sequential tasks: N
|
||||
Estimated total effort: N hours
|
||||
```
|
||||
|
||||
**After completion**: Confirm "✅ Created N tasks for epic: <name>" and suggest: "Ready to push to GitHub? Say: sync the <name> epic"
|
||||
|
||||
---
|
||||
|
||||
## Dependency Rules
|
||||
|
||||
- `depends_on` lists task numbers that must complete before this task can start.
|
||||
- `parallel: true` means the task can run concurrently with others it doesn't conflict with.
|
||||
- `conflicts_with` lists tasks that touch the same files — these cannot run in parallel.
|
||||
- Circular dependencies are an error — check before finalizing.
|
||||
@@ -0,0 +1,315 @@
|
||||
# Sync — Push to GitHub & Track Progress
|
||||
|
||||
This phase covers pushing local epics/tasks to GitHub as issues, syncing progress as comments, and closing issues when work is done.
|
||||
|
||||
---
|
||||
|
||||
## Repository Safety Check
|
||||
|
||||
**Always run this before any GitHub write operation:**
|
||||
|
||||
```bash
|
||||
remote_url=$(git remote get-url origin 2>/dev/null || echo "")
|
||||
if [[ "$remote_url" == *"automazeio/ccpm"* ]]; then
|
||||
echo "❌ Cannot sync to the CCPM template repository."
|
||||
echo "Update remote: git remote set-url origin https://github.com/YOUR/REPO.git"
|
||||
exit 1
|
||||
fi
|
||||
REPO=$(echo "$remote_url" | sed 's|.*github.com[:/]||' | sed 's|\.git$||')
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Epic Sync — Push Epic + Tasks to GitHub
|
||||
|
||||
**Trigger**: User wants to push a local epic and its tasks to GitHub as issues.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Verify `.claude/epics/<name>/epic.md` exists.
|
||||
- Verify numbered task files exist — if none: "❌ No tasks to sync. Decompose the epic first."
|
||||
|
||||
### Process
|
||||
|
||||
**Step 1 — Create epic issue:**
|
||||
|
||||
Strip frontmatter from epic.md, then:
|
||||
|
||||
```bash
|
||||
sed '1,/^---$/d; 1,/^---$/d' .claude/epics/<name>/epic.md > /tmp/epic-body.md
|
||||
epic_number=$(gh issue create \
|
||||
--repo "$REPO" \
|
||||
--title "Epic: <name>" \
|
||||
--body-file /tmp/epic-body.md \
|
||||
--label "epic,epic:<name>,feature" \
|
||||
--json number -q .number)
|
||||
```
|
||||
|
||||
**Step 2 — Create task sub-issues:**
|
||||
|
||||
Check if `gh-sub-issue` extension is available:
|
||||
|
||||
```bash
|
||||
if gh extension list | grep -q "yahsan2/gh-sub-issue"; then
|
||||
use_subissues=true
|
||||
fi
|
||||
```
|
||||
|
||||
For <5 tasks: create sequentially.
|
||||
For ≥5 tasks: use parallel Task agents (3-4 tasks per batch).
|
||||
|
||||
Per task:
|
||||
|
||||
```bash
|
||||
sed '1,/^---$/d; 1,/^---$/d' <task_file> > /tmp/task-body.md
|
||||
task_number=$(gh issue create \
|
||||
--repo "$REPO" \
|
||||
--title "<task_name>" \
|
||||
--body-file /tmp/task-body.md \
|
||||
--label "task,epic:<name>" \
|
||||
--json number -q .number)
|
||||
# or with sub-issues:
|
||||
# gh sub-issue create --parent $epic_number ...
|
||||
```
|
||||
|
||||
**Step 3 — Rename task files and update references:**
|
||||
|
||||
After all issues are created, rename `001.md` → `<issue_number>.md` and update all `depends_on`/`conflicts_with` arrays to use real issue numbers (not sequential numbers).
|
||||
|
||||
```bash
|
||||
# Build old→new mapping, then for each task file:
|
||||
sed -i.bak "s/\b001\b/<new_num_1>/g" <file> # repeat for each mapping
|
||||
mv 001.md <new_num>.md
|
||||
```
|
||||
|
||||
**Step 4 — Update frontmatter:**
|
||||
|
||||
```bash
|
||||
current_date=$(date -u +"%Y-%m-%dT%H:%M:%SZ")
|
||||
# Update github: and updated: fields in epic.md and each task file
|
||||
github_url="https://github.com/$REPO/issues/<number>"
|
||||
sed -i.bak "/^github:/c\\github: $github_url" <file>
|
||||
sed -i.bak "/^updated:/c\\updated: $current_date" <file>
|
||||
rm <file>.bak
|
||||
```
|
||||
|
||||
**Step 5 — Create worktree for the epic:**
|
||||
|
||||
```bash
|
||||
git checkout main && git pull origin main
|
||||
git worktree add ../epic-<name> -b epic/<name>
|
||||
```
|
||||
|
||||
**Step 6 — Create github-mapping.md:**
|
||||
|
||||
```markdown
|
||||
# GitHub Issue Mapping
|
||||
Epic: #<N> - https://github.com/<repo>/issues/<N>
|
||||
Tasks:
|
||||
- #<N>: <title> - https://github.com/<repo>/issues/<N>
|
||||
Synced: <datetime>
|
||||
```
|
||||
|
||||
**Output:**
|
||||
|
||||
```
|
||||
✅ Synced epic <name> to GitHub
|
||||
Epic: #<N>
|
||||
Tasks: N sub-issues
|
||||
Worktree: ../epic-<name>
|
||||
Next: "start working on issue <N>" or "start the <name> epic"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Issue Sync — Post Progress to GitHub
|
||||
|
||||
**Trigger**: User wants to sync local development progress to a GitHub issue as a comment.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Verify issue exists: `gh issue view <N> --json state`
|
||||
- Check `.claude/epics/*/updates/<N>/` exists with a `progress.md` file.
|
||||
- Check `last_sync` in progress.md — if synced <5 minutes ago, confirm before proceeding.
|
||||
|
||||
### Process
|
||||
|
||||
Gather updates from `.claude/epics/<epic>/updates/<N>/` (progress.md, notes.md, commits.md).
|
||||
|
||||
Format and post a comment:
|
||||
|
||||
```bash
|
||||
gh issue comment <N> --body-file /tmp/update-comment.md
|
||||
```
|
||||
|
||||
Comment format:
|
||||
|
||||
```markdown
|
||||
## 🔄 Progress Update - <date>
|
||||
|
||||
### ✅ Completed Work
|
||||
### 🔄 In Progress
|
||||
### 📝 Technical Notes
|
||||
### 📊 Acceptance Criteria Status
|
||||
### 🚀 Next Steps
|
||||
### ⚠️ Blockers
|
||||
|
||||
---
|
||||
*Progress: N% | Synced at <timestamp>*
|
||||
```
|
||||
|
||||
After posting: update `last_sync` in progress.md frontmatter, update `updated` in the task file.
|
||||
|
||||
Add sync marker to local files to prevent duplicate comments:
|
||||
|
||||
```markdown
|
||||
<!-- SYNCED: <datetime> -->
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Closing an Issue
|
||||
|
||||
**Trigger**: User marks a task complete.
|
||||
|
||||
### Process
|
||||
|
||||
1. Find the local task file (`.claude/epics/*/<N>.md`).
|
||||
2. Update frontmatter: `status: closed`, `updated: <now>`.
|
||||
3. Post completion comment:
|
||||
|
||||
```bash
|
||||
echo "✅ Task completed — all acceptance criteria met." | gh issue comment <N> --body-file -
|
||||
gh issue close <N>
|
||||
```
|
||||
1. Check off the task in the epic issue body:
|
||||
|
||||
```bash
|
||||
gh issue view <epic_N> --json body -q .body > /tmp/epic-body.md
|
||||
sed -i "s/- \[ \] #<N>/- [x] #<N>/" /tmp/epic-body.md
|
||||
gh issue edit <epic_N> --body-file /tmp/epic-body.md
|
||||
```
|
||||
1. Recalculate and update epic progress: `progress = closed_tasks / total_tasks * 100`
|
||||
|
||||
---
|
||||
|
||||
## Merging an Epic
|
||||
|
||||
**Trigger**: User wants to merge a completed epic back to main.
|
||||
|
||||
### Preflight
|
||||
|
||||
- Verify worktree `../epic-<name>` exists.
|
||||
- Check for uncommitted changes in the worktree — block if dirty.
|
||||
- Warn if any task issues are still open.
|
||||
|
||||
### Process
|
||||
|
||||
```bash
|
||||
# From worktree: run project tests if detectable
|
||||
cd ../epic-<name>
|
||||
# detect and run: npm test / pytest / cargo test / go test / etc.
|
||||
|
||||
# From main repo:
|
||||
git checkout main && git pull origin main
|
||||
git merge epic/<name> --no-ff -m "Merge epic: <name>"
|
||||
git push origin main
|
||||
|
||||
# Cleanup
|
||||
git worktree remove ../epic-<name>
|
||||
git branch -d epic/<name>
|
||||
git push origin --delete epic/<name>
|
||||
|
||||
# Archive
|
||||
mkdir -p .claude/epics/archived/
|
||||
mv .claude/epics/<name> .claude/epics/archived/
|
||||
|
||||
# Close GitHub issues
|
||||
epic_issue=$(grep 'github:' .claude/epics/archived/<name>/epic.md | grep -oE '[0-9]+$')
|
||||
gh issue close $epic_issue -c "Epic completed and merged to main"
|
||||
```
|
||||
|
||||
Update epic.md frontmatter: `status: completed`.
|
||||
|
||||
---
|
||||
|
||||
## Reporting a Bug Against a Completed Issue
|
||||
|
||||
**Trigger**: User finds a bug while testing a completed or in-progress issue — e.g. "found a bug in issue 42", "email validation is broken, came up while testing issue 42".
|
||||
|
||||
The workflow should stay automated: create a linked bug task without losing context from the original issue.
|
||||
|
||||
### Process
|
||||
|
||||
**Step 1 — Read the original issue for context:**
|
||||
|
||||
```bash
|
||||
gh issue view <original_N> --json title,body,labels
|
||||
```
|
||||
|
||||
Also read the local task file if it exists: `.claude/epics/*/<original_N>.md`
|
||||
|
||||
**Step 2 — Create a local bug task file:**
|
||||
|
||||
```markdown
|
||||
---
|
||||
name: Bug: <short description>
|
||||
status: open
|
||||
created: <run: date -u +"%Y-%m-%dT%H:%M:%SZ">
|
||||
updated: <same>
|
||||
github: (will be set on sync)
|
||||
depends_on: []
|
||||
parallel: false
|
||||
conflicts_with: []
|
||||
bug_for: <original_N>
|
||||
---
|
||||
|
||||
# Bug: <short description>
|
||||
|
||||
## Context
|
||||
Found while working on / testing issue #<original_N>: <original title>
|
||||
|
||||
## Description
|
||||
<what's broken>
|
||||
|
||||
## Steps to Reproduce
|
||||
<steps>
|
||||
|
||||
## Expected vs Actual
|
||||
- Expected:
|
||||
- Actual:
|
||||
|
||||
## Acceptance Criteria
|
||||
- [ ] Bug is fixed
|
||||
- [ ] Original issue #<original_N> behaviour is unaffected
|
||||
|
||||
## Effort Estimate
|
||||
- Size: XS/S
|
||||
```
|
||||
|
||||
Save to `.claude/epics/<same_epic_as_original>/bug-<original_N>-<slug>.md`
|
||||
|
||||
**Step 3 — Create a linked GitHub issue:**
|
||||
|
||||
```bash
|
||||
gh issue create \
|
||||
--repo "$REPO" \
|
||||
--title "Bug: <short description>" \
|
||||
--body "$(cat /tmp/bug-body.md)" \
|
||||
--label "bug,epic:<epic_name>" \
|
||||
--json number -q .number
|
||||
```
|
||||
|
||||
The issue body should open with `Fixes / follow-up to #<original_N>` so GitHub auto-links them.
|
||||
|
||||
**Step 4 — Update the local file** with the GitHub issue number and rename to `<new_N>.md`.
|
||||
|
||||
**Output:**
|
||||
|
||||
```
|
||||
✅ Bug issue created: #<new_N> — "Bug: <short description>"
|
||||
Linked to: #<original_N>
|
||||
Epic: <epic_name>
|
||||
|
||||
Start fixing it: "start working on issue <new_N>"
|
||||
```
|
||||
@@ -0,0 +1,165 @@
|
||||
# Track — Know Where Things Stand
|
||||
|
||||
Tracking operations use bash scripts directly for speed and consistency. The LLM is not needed for these — just run the script and present the output.
|
||||
|
||||
---
|
||||
|
||||
## Script-First Rule
|
||||
|
||||
All tracking operations have a corresponding bash script. Run the script; do not reconstruct the output manually.
|
||||
|
||||
Scripts live in `references/scripts/` relative to this skill, but need to run from the **project root** (where `.claude/` lives). Run them as:
|
||||
|
||||
```bash
|
||||
bash <skill_path>/references/scripts/<script>.sh [args]
|
||||
```
|
||||
|
||||
Or if ccpm is installed project-locally:
|
||||
|
||||
```bash
|
||||
bash ccpm/scripts/pm/<script>.sh [args]
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Project Status
|
||||
|
||||
**Trigger**: "what's our status", "project status", "overview"
|
||||
|
||||
```bash
|
||||
bash references/scripts/status.sh
|
||||
```
|
||||
|
||||
Shows: active epics, open issues count, recent activity.
|
||||
|
||||
---
|
||||
|
||||
## Standup Report
|
||||
|
||||
**Trigger**: "standup", "daily standup", "what did we do", "morning update"
|
||||
|
||||
```bash
|
||||
bash references/scripts/standup.sh
|
||||
```
|
||||
|
||||
Shows: what was completed yesterday, what's in progress today, any blockers.
|
||||
|
||||
---
|
||||
|
||||
## List Epics
|
||||
|
||||
**Trigger**: "list epics", "show epics", "what epics do we have"
|
||||
|
||||
```bash
|
||||
bash references/scripts/epic-list.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Show Epic Details
|
||||
|
||||
**Trigger**: "show the <name> epic", "epic details for <name>"
|
||||
|
||||
```bash
|
||||
bash references/scripts/epic-show.sh <name>
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Epic Status
|
||||
|
||||
**Trigger**: "status of the <name> epic", "how far along is <name>"
|
||||
|
||||
```bash
|
||||
bash references/scripts/epic-status.sh <name>
|
||||
```
|
||||
|
||||
Shows: task completion breakdown, active agents, blocking issues.
|
||||
|
||||
---
|
||||
|
||||
## List PRDs
|
||||
|
||||
**Trigger**: "list PRDs", "what PRDs do we have", "show backlog"
|
||||
|
||||
```bash
|
||||
bash references/scripts/prd-list.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## PRD Status
|
||||
|
||||
**Trigger**: "PRD status", "which PRDs are parsed", "what's in backlog"
|
||||
|
||||
```bash
|
||||
bash references/scripts/prd-status.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Search
|
||||
|
||||
**Trigger**: "search for <query>", "find issues about <topic>", "look for <term>"
|
||||
|
||||
```bash
|
||||
bash references/scripts/search.sh "<query>"
|
||||
```
|
||||
|
||||
Searches local task files, PRDs, and epics for the query term.
|
||||
|
||||
---
|
||||
|
||||
## What's In Progress
|
||||
|
||||
**Trigger**: "what's in progress", "what are we working on", "active work"
|
||||
|
||||
```bash
|
||||
bash references/scripts/in-progress.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## What's Next
|
||||
|
||||
**Trigger**: "what should I work on next", "what's next", "next priority"
|
||||
|
||||
```bash
|
||||
bash references/scripts/next.sh
|
||||
```
|
||||
|
||||
Shows highest-priority open tasks with no blocking dependencies.
|
||||
|
||||
---
|
||||
|
||||
## What's Blocked
|
||||
|
||||
**Trigger**: "what's blocked", "any blockers", "what can't we move on"
|
||||
|
||||
```bash
|
||||
bash references/scripts/blocked.sh
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Validate Project State
|
||||
|
||||
**Trigger**: "validate", "check project state", "is everything consistent"
|
||||
|
||||
```bash
|
||||
bash references/scripts/validate.sh
|
||||
```
|
||||
|
||||
Checks: frontmatter consistency, orphaned files, missing GitHub links, dependency integrity.
|
||||
|
||||
---
|
||||
|
||||
## When Scripts Fail
|
||||
|
||||
If a script fails or the output needs interpretation (e.g., an error in the output, or the user asks "what does this mean"), then step in to explain. But always run the script first — don't guess at what status/standup output would look like.
|
||||
|
||||
If `.claude/` directory doesn't exist at all, the project hasn't been initialized. Direct the user to run:
|
||||
|
||||
```bash
|
||||
bash references/scripts/init.sh
|
||||
```
|
||||
@@ -3,3 +3,4 @@ node_modules/
|
||||
bin/
|
||||
CLAUDE.md
|
||||
.claude/skills/mermaid/
|
||||
.claude/skills/ccpm/
|
||||
|
||||
@@ -10,9 +10,10 @@
|
||||
"type": "http",
|
||||
"url": "https://api.githubcopilot.com/mcp",
|
||||
"headers": {
|
||||
"Authorization": "Bearer ${GITHUB_TOKEN}"
|
||||
"Authorization": "Bearer ${GITHUB_TOKEN}",
|
||||
"X-MCP-Toolsets": "actions,code_security,context,dependabot,discussions,gists,issues,notifications,orgs,projects,pull_requests,repos,secret_protection,security_advisories,stargazers,users"
|
||||
},
|
||||
"comment": "Фаза 0 #3 — официальный hosted GitHub MCP (https://github.com/github/github-mcp-server). Требует env GITHUB_TOKEN с PAT (scopes: repo, read:org, не давать admin/delete). Раньше использовали deprecated @modelcontextprotocol/server-github — заменён 06.05.2026."
|
||||
"comment": "Фаза 0 #3 — официальный hosted GitHub MCP (https://github.com/github/github-mcp-server). Требует env GITHUB_TOKEN с PAT (scopes: repo, read:org, не давать admin/delete). Раньше использовали deprecated @modelcontextprotocol/server-github — заменён 06.05.2026. X-MCP-Toolsets явно перечисляет toolset'ы, включая `projects` (GitHub Projects v2 — доски/спринты/milestones) для раздела C9 «Управление проектами» — план docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md (GH1). Заголовок заменяет default-набор: список явный, чтобы не сузить поверхность."
|
||||
},
|
||||
"laravel-boost": {
|
||||
"command": "php",
|
||||
|
||||
@@ -14,6 +14,7 @@
|
||||
import { computed, onMounted, ref } from 'vue';
|
||||
import { impersonationActive, type ImpersonationActiveSession } from '../../api/admin';
|
||||
import { usePolling } from '../../composables/usePolling';
|
||||
import { POLLING_INTERVAL_MS } from '../../constants/polling';
|
||||
|
||||
const sessions = ref<ImpersonationActiveSession[]>([]);
|
||||
|
||||
@@ -37,7 +38,7 @@ const label = computed(() => {
|
||||
});
|
||||
|
||||
onMounted(load);
|
||||
usePolling(load, { intervalMs: 30_000 });
|
||||
usePolling(load, { intervalMs: POLLING_INTERVAL_MS });
|
||||
|
||||
defineExpose({ sessions, load });
|
||||
</script>
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { onBeforeUnmount, onMounted } from 'vue';
|
||||
import { POLLING_INTERVAL_MS } from '../constants/polling';
|
||||
|
||||
/**
|
||||
* Polling-composable для авто-обновления view-данных.
|
||||
@@ -15,14 +16,14 @@ import { onBeforeUnmount, onMounted } from 'vue';
|
||||
* Cleanup на onBeforeUnmount: clearInterval + removeEventListener.
|
||||
*/
|
||||
export interface PollingOptions {
|
||||
/** Период polling в миллисекундах. По умолчанию 30_000. */
|
||||
/** Период polling в миллисекундах. По умолчанию POLLING_INTERVAL_MS (30 с). */
|
||||
intervalMs?: number;
|
||||
/** Если false — composable не стартует interval (для disable-флага). */
|
||||
enabled?: boolean;
|
||||
}
|
||||
|
||||
export function usePolling(loader: () => void | Promise<void>, options: PollingOptions = {}): void {
|
||||
const intervalMs = options.intervalMs ?? 30_000;
|
||||
const intervalMs = options.intervalMs ?? POLLING_INTERVAL_MS;
|
||||
const enabled = options.enabled ?? true;
|
||||
|
||||
if (!enabled) return;
|
||||
|
||||
@@ -0,0 +1,11 @@
|
||||
/**
|
||||
* Интервалы polling-обновления view-данных — единый источник «магических»
|
||||
* чисел для usePolling. До приезда SSE/WebSocket в production это покрывает
|
||||
* «real-time»-паттерн (см. composables/usePolling.ts).
|
||||
*/
|
||||
|
||||
/** Базовый интервал авто-обновления для большинства view-данных (30 с). */
|
||||
export const POLLING_INTERVAL_MS = 30_000;
|
||||
|
||||
/** Интервал для менее срочных счётчиков (напоминания в сайдбаре). */
|
||||
export const POLLING_REMINDERS_INTERVAL_MS = 60_000;
|
||||
@@ -38,6 +38,9 @@ const route = useRoute();
|
||||
const router = useRouter();
|
||||
const auth = useAuthStore();
|
||||
|
||||
/** DEV-режим: показываем баннер о застабленном auth-gate админки (B6). */
|
||||
const isDevEnv = import.meta.env.DEV;
|
||||
|
||||
const userInitials = computed(() => {
|
||||
const u = auth.user;
|
||||
if (!u) return 'АО';
|
||||
@@ -131,6 +134,19 @@ const currentPageTitle = computed(() => {
|
||||
</v-app-bar>
|
||||
|
||||
<v-main class="admin-main">
|
||||
<v-alert
|
||||
v-if="isDevEnv"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
density="compact"
|
||||
class="ma-4"
|
||||
data-testid="dev-auth-gap-banner"
|
||||
>
|
||||
DEV-режим: доступ к админке открыт без SSO-проверки — middleware
|
||||
<code>EnsureSaasAdmin</code> в dev пропускает все запросы. В production
|
||||
требуется вход через Yandex 360 + роль <code>super_admin</code> (Б-1);
|
||||
неавторизованные запросы получают 503.
|
||||
</v-alert>
|
||||
<ImpersonationBanner />
|
||||
<RouterView />
|
||||
</v-main>
|
||||
|
||||
@@ -15,6 +15,7 @@ import { useAuthStore } from '../stores/auth';
|
||||
import { useNotificationsStore } from '../stores/notifications';
|
||||
import { useRemindersStore } from '../stores/reminders';
|
||||
import { usePolling } from '../composables/usePolling';
|
||||
import { POLLING_INTERVAL_MS, POLLING_REMINDERS_INTERVAL_MS } from '../constants/polling';
|
||||
import AppSidebar from '../components/layout/AppSidebar.vue';
|
||||
import AppTopbar from '../components/layout/AppTopbar.vue';
|
||||
import DevIndexBadge from '../components/DevIndexBadge.vue';
|
||||
@@ -57,8 +58,8 @@ onMounted(() => {
|
||||
void loadNotifications();
|
||||
void loadReminderCounts();
|
||||
});
|
||||
usePolling(loadNotifications, { intervalMs: 30_000, enabled: true });
|
||||
usePolling(loadReminderCounts, { intervalMs: 60_000, enabled: true });
|
||||
usePolling(loadNotifications, { intervalMs: POLLING_INTERVAL_MS, enabled: true });
|
||||
usePolling(loadReminderCounts, { intervalMs: POLLING_REMINDERS_INTERVAL_MS, enabled: true });
|
||||
</script>
|
||||
|
||||
<template>
|
||||
|
||||
@@ -167,33 +167,6 @@ onUnmounted(() => store.stopPolling());
|
||||
grid-template-columns: repeat(auto-fill, minmax(320px, 1fr));
|
||||
gap: 16px;
|
||||
}
|
||||
/* Workaround: MDI-шрифт не подключён в проекте (Диз-4),
|
||||
`<i class="mdi-close-circle">` рендерится пустым. Подменяем глиф на Unicode `✕`
|
||||
и показываем только когда поле имеет значение (Vuetify ставит `.v-field--dirty`). */
|
||||
.projects-view :deep(.v-field__clearable) {
|
||||
position: relative;
|
||||
}
|
||||
.projects-view :deep(.v-field__clearable .v-icon) {
|
||||
color: transparent;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
.projects-view :deep(.v-field--dirty .v-field__clearable)::after {
|
||||
content: '✕';
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
color: rgba(1, 32, 25, 0.55);
|
||||
font-size: 14px;
|
||||
font-family: 'Inter', system-ui, sans-serif;
|
||||
pointer-events: none;
|
||||
transition: color 150ms ease;
|
||||
}
|
||||
.projects-view :deep(.v-field--dirty .v-field__clearable:hover)::after {
|
||||
color: var(--liderra-noir, #012019);
|
||||
}
|
||||
.toolbar-check {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
|
||||
@@ -12,6 +12,7 @@ import { computed, onMounted, ref } from 'vue';
|
||||
import { cancelReportJob, createReportJob, deleteReportJob, listReportJobs, retryReportJob } from '../api/reports';
|
||||
import { extractErrorMessage, extractValidationErrors } from '../api/client';
|
||||
import { usePolling } from '../composables/usePolling';
|
||||
import { POLLING_INTERVAL_MS } from '../constants/polling';
|
||||
import { type ReportFormat, type ReportJob, type ReportType } from '../composables/mockReports';
|
||||
import { mapApiReportJob, uiTypeToApi } from '../composables/reportsMapper';
|
||||
import ReportRequestForm from '../components/reports/ReportRequestForm.vue';
|
||||
@@ -59,7 +60,7 @@ onMounted(() => {
|
||||
void loadJobs();
|
||||
});
|
||||
|
||||
usePolling(loadJobs, { intervalMs: 30_000 });
|
||||
usePolling(loadJobs, { intervalMs: POLLING_INTERVAL_MS });
|
||||
|
||||
async function submitForm(): Promise<void> {
|
||||
submitting.value = true;
|
||||
|
||||
@@ -163,6 +163,7 @@ defineExpose({ settingsState, editOpen, editSetting, openEdit, onSettingUpdated,
|
||||
size="small"
|
||||
density="comfortable"
|
||||
prepend-icon="mdi-pencil"
|
||||
:aria-label="`Изменить настройку ${setting.key}`"
|
||||
:data-testid="`edit-${setting.key}-btn`"
|
||||
@click="openEdit(setting)"
|
||||
>
|
||||
|
||||
@@ -86,11 +86,22 @@ async function handleSubmit() {
|
||||
placeholder="Минимум 8 символов"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:append-inner-icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
||||
required
|
||||
:error-messages="errors.password"
|
||||
@click:append-inner="showPassword = !showPassword"
|
||||
/>
|
||||
>
|
||||
<template #append-inner>
|
||||
<v-icon
|
||||
class="password-toggle"
|
||||
:icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
||||
:aria-label="showPassword ? 'Скрыть пароль' : 'Показать пароль'"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="showPassword = !showPassword"
|
||||
@keydown.enter.prevent="showPassword = !showPassword"
|
||||
@keydown.space.prevent="showPassword = !showPassword"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
|
||||
<div class="d-flex justify-end mb-2">
|
||||
<RouterLink to="/forgot" class="text-body-2 text-primary"> Забыли пароль? </RouterLink>
|
||||
@@ -141,4 +152,10 @@ async function handleSubmit() {
|
||||
.yandex-sso-wrap {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.password-toggle:focus-visible {
|
||||
outline: 2px solid currentColor;
|
||||
outline-offset: 1px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -102,11 +102,22 @@ async function handleSubmit() {
|
||||
placeholder="Минимум 8 символов"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:append-inner-icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
||||
required
|
||||
:error-messages="errors.password"
|
||||
@click:append-inner="showPassword = !showPassword"
|
||||
/>
|
||||
>
|
||||
<template #append-inner>
|
||||
<v-icon
|
||||
class="password-toggle"
|
||||
:icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
||||
:aria-label="showPassword ? 'Скрыть пароль' : 'Показать пароль'"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="showPassword = !showPassword"
|
||||
@keydown.enter.prevent="showPassword = !showPassword"
|
||||
@keydown.space.prevent="showPassword = !showPassword"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
|
||||
<div v-if="password" class="strength-block mb-2">
|
||||
<v-progress-linear
|
||||
@@ -184,4 +195,10 @@ async function handleSubmit() {
|
||||
gap: 4px;
|
||||
margin-bottom: 8px;
|
||||
}
|
||||
|
||||
.password-toggle:focus-visible {
|
||||
outline: 2px solid currentColor;
|
||||
outline-offset: 1px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -112,11 +112,22 @@ async function handleSubmit() {
|
||||
placeholder="Минимум 10 символов"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
:append-inner-icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
||||
required
|
||||
:error-messages="errors.password"
|
||||
@click:append-inner="showPassword = !showPassword"
|
||||
/>
|
||||
>
|
||||
<template #append-inner>
|
||||
<v-icon
|
||||
class="password-toggle"
|
||||
:icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
||||
:aria-label="showPassword ? 'Скрыть пароль' : 'Показать пароль'"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="showPassword = !showPassword"
|
||||
@keydown.enter.prevent="showPassword = !showPassword"
|
||||
@keydown.space.prevent="showPassword = !showPassword"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
|
||||
<v-text-field
|
||||
v-model="passwordConfirmation"
|
||||
@@ -165,4 +176,10 @@ async function handleSubmit() {
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
|
||||
.password-toggle:focus-visible {
|
||||
outline: 2px solid currentColor;
|
||||
outline-offset: 1px;
|
||||
border-radius: 2px;
|
||||
}
|
||||
</style>
|
||||
|
||||
@@ -60,6 +60,10 @@ const mountAdminLayout = async (path = '/admin/tenants', user: AuthUser | null =
|
||||
};
|
||||
|
||||
describe('AdminLayout.vue', () => {
|
||||
afterEach(() => {
|
||||
vi.unstubAllEnvs();
|
||||
});
|
||||
|
||||
it('монтируется без ошибок', async () => {
|
||||
const { wrapper } = await mountAdminLayout();
|
||||
expect(wrapper.exists()).toBe(true);
|
||||
@@ -214,4 +218,16 @@ describe('AdminLayout.vue', () => {
|
||||
const nav = wrapper.find('[aria-label="Админ навигация"]');
|
||||
expect(nav.exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('B6: показывает DEV-баннер auth-gap в dev-режиме', async () => {
|
||||
vi.stubEnv('DEV', true);
|
||||
const { wrapper } = await mountAdminLayout();
|
||||
expect(wrapper.find('[data-testid="dev-auth-gap-banner"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('B6: скрывает DEV-баннер в production-режиме', async () => {
|
||||
vi.stubEnv('DEV', false);
|
||||
const { wrapper } = await mountAdminLayout();
|
||||
expect(wrapper.find('[data-testid="dev-auth-gap-banner"]').exists()).toBe(false);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -149,4 +149,14 @@ describe('AdminSystemView.vue', () => {
|
||||
expect(row?.value).toBe('7');
|
||||
expect(row?.updated_at).toBe('2026-05-09T11:30:00');
|
||||
});
|
||||
|
||||
it('G9: edit-кнопки имеют aria-label с ключом настройки', async () => {
|
||||
const wrapper = await mountView();
|
||||
const editBtns = wrapper.findAll('[data-testid^="edit-"]');
|
||||
expect(editBtns.length).toBeGreaterThan(0);
|
||||
for (const btn of editBtns) {
|
||||
const label = btn.attributes('aria-label') ?? '';
|
||||
expect(label).toMatch(/^Изменить настройку .+/);
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
@@ -87,4 +87,17 @@ describe('LoginView.vue', () => {
|
||||
expect(ssoBtn).toBeDefined();
|
||||
expect(ssoBtn!.classes()).toContain('v-btn--disabled');
|
||||
});
|
||||
|
||||
it('A9: переключатель видимости пароля имеет accessible-name и работает', async () => {
|
||||
const wrapper = await mountLoginView();
|
||||
const toggle = wrapper.find('[aria-label="Показать пароль"]');
|
||||
expect(toggle.exists()).toBe(true);
|
||||
expect(toggle.attributes('role')).toBe('button');
|
||||
await toggle.trigger('click');
|
||||
expect(wrapper.find('[aria-label="Скрыть пароль"]').exists()).toBe(true);
|
||||
|
||||
// keyboard activation (Enter) — toggle back
|
||||
await wrapper.find('[aria-label="Скрыть пароль"]').trigger('keydown', { key: 'Enter' });
|
||||
expect(wrapper.find('[aria-label="Показать пароль"]').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -53,4 +53,17 @@ describe('RegisterView.vue', () => {
|
||||
const links = wrapper.findAll('a').map((a) => a.text());
|
||||
expect(links.some((t) => t.includes('Войдите'))).toBe(true);
|
||||
});
|
||||
|
||||
it('A9: переключатель видимости пароля имеет accessible-name и работает', async () => {
|
||||
const wrapper = await mountRegister();
|
||||
const toggle = wrapper.find('[aria-label="Показать пароль"]');
|
||||
expect(toggle.exists()).toBe(true);
|
||||
expect(toggle.attributes('role')).toBe('button');
|
||||
await toggle.trigger('click');
|
||||
expect(wrapper.find('[aria-label="Скрыть пароль"]').exists()).toBe(true);
|
||||
|
||||
// keyboard activation (Enter) — toggle back
|
||||
await wrapper.find('[aria-label="Скрыть пароль"]').trigger('keydown', { key: 'Enter' });
|
||||
expect(wrapper.find('[aria-label="Показать пароль"]').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -112,4 +112,17 @@ describe('ResetPasswordView.vue', () => {
|
||||
await wrapper.vm.$nextTick();
|
||||
expect(wrapper.text()).toContain('Пароли не совпадают');
|
||||
});
|
||||
|
||||
it('A9: переключатель видимости пароля имеет accessible-name и работает', async () => {
|
||||
const wrapper = await mountReset();
|
||||
const toggle = wrapper.find('[aria-label="Показать пароль"]');
|
||||
expect(toggle.exists()).toBe(true);
|
||||
expect(toggle.attributes('role')).toBe('button');
|
||||
await toggle.trigger('click');
|
||||
expect(wrapper.find('[aria-label="Скрыть пароль"]').exists()).toBe(true);
|
||||
|
||||
// keyboard activation (Enter) — toggle back
|
||||
await wrapper.find('[aria-label="Скрыть пароль"]').trigger('keydown', { key: 'Enter' });
|
||||
expect(wrapper.find('[aria-label="Показать пароль"]').exists()).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -1321,6 +1321,7 @@ mmdc
|
||||
inertiajs
|
||||
Sev
|
||||
вендоренный
|
||||
вендорен
|
||||
|
||||
# D3 audit-risk tooling integration (Прил. Н #39-40)
|
||||
unvetted
|
||||
@@ -1330,3 +1331,32 @@ triada
|
||||
trailofbits
|
||||
hackathon
|
||||
субсет
|
||||
|
||||
# A11 ML/AI tooling integration — brainstorming spec + plan (2026-05-17)
|
||||
CCPM
|
||||
REU
|
||||
promptfoo
|
||||
promptfooconfig
|
||||
datalayer
|
||||
scikit
|
||||
XGBoost
|
||||
Jupyter
|
||||
pandas
|
||||
alirezarezvani
|
||||
Anthropic
|
||||
RAG
|
||||
venv
|
||||
Helicone
|
||||
Langfuse
|
||||
|
||||
# SG #40 Security Guidance correction (2026-05-17)
|
||||
резолва
|
||||
шим
|
||||
characterisation
|
||||
|
||||
Arclio
|
||||
Cowork
|
||||
PRD
|
||||
automazeio
|
||||
prds
|
||||
Vivek
|
||||
|
||||
+2
-1
@@ -23,7 +23,8 @@
|
||||
"package-lock.json",
|
||||
"*.svg",
|
||||
"**/*.sql",
|
||||
".claude/skills/mermaid/**"
|
||||
".claude/skills/mermaid/**",
|
||||
".claude/skills/ccpm/**"
|
||||
],
|
||||
"ignoreRegExpList": [
|
||||
"Email",
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
# Plugin Stack Rules — Superpowers + Frontend Design (v3.4)
|
||||
# Plugin Stack Rules — Superpowers + Frontend Design (v3.6)
|
||||
|
||||
**Дата:** 17.05.2026
|
||||
**Назначение:** свод правил совместного использования плагинов Claude Code в проекте Лидерра — paired-stack ядро `obra/superpowers` (14 skills) + `anthropics/frontend-design`, плюс расширенный пул UI-инструментов `ui-ux-pro-max` (skill, marketplace `nextlevelbuilder/ui-ux-pro-max-skill`) и `21st.dev Magic MCP` (MCP-сервер `magic`), плюс инфраструктурный `claude-md-management` (skills, marketplace `anthropics/claude-plugins-official`), плюс **debug-runtime MCP** `@sentry/mcp-server` + `@modelcontextprotocol/server-redis` (v2.1+, R10.1 Блок 3).
|
||||
|
||||
**v3.6** — C9 project-management: R10.1 Блок 1 (`enabledPlugins`) +2 строки — **CCPM** (`automazeio/ccpm`, вендорен в `.claude/skills/ccpm/`) + **product-management** (`anthropics/knowledge-work-plugins`, Anthropic Verified). Блок 1 +note про **CCPM** (вендоренный скил, аналог mermaid-skill). Новая категория **project-management** (Tooling #41-42, раздел C9 карты) — не UI → вне R6.0/R6.1/R14, как architecture-tooling/audit-security. Содержательных изменений R0–R14: 0. Связано: Tooling v2.6, Pravila v1.20, CLAUDE.md v2.6; план `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`.
|
||||
|
||||
**v3.5** — фактическая правка R10.1 Блок 1 строки **security-guidance**: это **блокирующий** PreToolUse-хук (`sys.exit(2)`, одноразовый speed-bump per «файл+правило» за сессию, retry проходит), не warn-only. Содержательных изменений R0–R14: 0. Связано: Tooling v2.5, Pravila v1.19, CLAUDE.md v2.5; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`.
|
||||
|
||||
**v3.4** — D3 audit-security: R10.1 Блок 1 (`enabledPlugins`) +2 строки — **Trail of Bits Skills** (`trailofbits/skills`, субсет 8 плагинов) + **security-guidance** (`anthropics/claude-plugins-official`). Новая категория **audit-security** (Tooling #39-40, раздел D3 карты) — не UI → вне R6.0/R6.1/R14, как debug-runtime/infrastructure/architecture-tooling. Содержательных изменений R0–R9/R11–R14: 0. Связано: Tooling v2.4, Pravila v1.18, CLAUDE.md v2.4.
|
||||
|
||||
**v3.3** — A6 architecture-tooling: R10.1 Блок 1 (`enabledPlugins`) +2 строки — **adr-kit** (`rvdbreemen/adr-kit`) + **architecture-patterns** (`secondsky/claude-skills`); Блок 1 +note про **mermaid-skill** (вендоренный сторонний скил). Новая категория **architecture-tooling** (Tooling #36-38, раздел A6 карты) — не UI → вне R6.0/R6.1/R14, как debug-runtime/infrastructure. Содержательных изменений R0–R9/R11–R14: 0. Связано: Tooling v2.3, Pravila v1.17, CLAUDE.md v2.3.
|
||||
@@ -399,10 +403,14 @@ Stack — **головной**. Все плагины вне stack'а — **ин
|
||||
| **adr-kit** *(8 skills + агент `adr-generator`)* | `rvdbreemen/adr-kit` | Architecture Decision Records — `/adr-kit:adr` авторинг, `/adr-kit:lint` проверка, `adr-judge` enforcement. Категория: **architecture-tooling** (Tooling #36, вне UI-пула) | при авторинге/ревизии архитектурного решения в `docs/adr/`. `adr-judge` врезан в lefthook job 9 (декларативно, без `--llm`). Не UI → вне R6.0/R6.1/R14 |
|
||||
| **architecture-patterns** *(1 skill)* | `secondsky/claude-skills` | справочник архитектурных паттернов (Clean / Hexagonal / layered / DDD). Категория: **architecture-tooling** (Tooling #38). Knowledge-only, не решатель | при проектировании/рефакторинге подсистемы — справка по паттернам. Не источник истины (R11), как UPM |
|
||||
| **Trail of Bits Skills** *(субсет 8 плагинов)* | `trailofbits/skills` (marketplace `trailofbits`) | аудит безопасности — security-аудит diff, supply-chain риск зависимостей, поиск вариантов уязвимостей. Категория: **audit-security** (Tooling #39, вне UI-пула). CC-BY-SA-4.0, marketplace-плагин (не вендорен) | при глубокой аудит-кампании раздела D3 «Аудит и управление рисками». Не UI → вне R6.0/R6.1/R14 |
|
||||
| **security-guidance** *(1 PreToolUse warn-хук)* | `anthropics/claude-plugins-official` | inline-предупреждения уязвимостей при правке кода (warn-only, не блокирует, 8 категорий). Категория: **audit-security** (Tooling #40) | автоматически — PreToolUse-хук на Write/Edit. Не решатель, не UI → вне R6.0/R6.1/R14 |
|
||||
| **security-guidance** *(1 PreToolUse-хук, блокирующий)* | `anthropics/claude-plugins-official` | inline-предупреждения уязвимостей при правке кода — **блокирующий** хук (`sys.exit 2`, одноразовый speed-bump per «файл+правило» за сессию, retry проходит), 8 контентных правил + 1 path-правило. Категория: **audit-security** (Tooling #40) | автоматически — PreToolUse-хук на Write/Edit/MultiEdit. Не решатель, не UI → вне R6.0/R6.1/R14 |
|
||||
| **CCPM** *(vendored standalone skill, `/pm` flow, 14 bash-скриптов)* | `automazeio/ccpm` (вендорен в `.claude/skills/ccpm/`) | PRD→эпик→GitHub-issue→код с полной трассируемостью. GitHub-issue-backed модель (ADR-004). PRD/epic store в `.claude/prds/`/`.claude/epics/`. Категория: **project-management** (Tooling #41, вне UI-пула). Bus-factor mitigation — вендорен (community-проект). 0 хуков | при авторинге PRD/epic и создании GitHub-issue из CCPM flow. Не UI → вне R6.0/R6.1/R14 |
|
||||
| **product-management** *(6 команд `/write-spec`, `/roadmap-update` и др.)* | `anthropics/knowledge-work-plugins` (plugin `product-management@knowledge-work-plugins`, Anthropic Verified) | product-strategy церемонии (problem→spec, roadmap, stakeholder updates, research synthesis, competitive analysis, metrics review). Категория: **project-management** (Tooling #42). 0 хуков | при product-strategy work: написание спеки, обновление роадмапа, анализ конкурентов. Не UI → вне R6.0/R6.1/R14 |
|
||||
|
||||
**Блок 1 — note (v3.3):** **mermaid-skill** (Tooling #37, генератор C4/architecture-диаграмм) — вендоренный сторонний скил в `.claude/skills/mermaid/` (`WH-2099/mermaid-skill`, MIT), **не** через marketplace и **не** в `enabledPlugins`. Пассивная утилита (генерация Mermaid-исходника), не решатель — формально вне типологии трёх блоков; регистрируется здесь для полноты. Категория **architecture-tooling**, вне R6/R14.
|
||||
|
||||
**Блок 1 — note (v3.6):** **CCPM** (Tooling #41) — аналогично mermaid-skill: вендоренный сторонний скил в `.claude/skills/ccpm/` (`automazeio/ccpm`, MIT), **не** через marketplace и **не** в `enabledPlugins`. Активируется через `/pm` в Claude Code. Категория **project-management**, вне R6/R14.
|
||||
|
||||
**Отмена:** через удаление из `enabledPlugins` в `~/.claude/settings.json` или через live-override `/имя-плагина` (R0.4.B) на одно действие.
|
||||
|
||||
#### Блок 2: Built-in skills Claude Code (всегда доступны через `Skill` tool по `/имя`)
|
||||
@@ -757,6 +765,10 @@ Pipeline активируется при одновременном выполн
|
||||
|
||||
## История версий
|
||||
|
||||
- **v3.6 (2026-05-17)** — C9 project-management: R10.1 Блок 1 (`enabledPlugins`) +2 строки (**CCPM** `automazeio/ccpm` вендорен в `.claude/skills/ccpm/`, **product-management** `anthropics/knowledge-work-plugins` Anthropic Verified) + Блок 1 note про CCPM (vendored скил, аналог mermaid-skill). Новая категория **project-management** (Tooling #41-42, раздел C9 карты «Управление проектами») — 7-я off-phase подкатегория, не UI → вне R6.0/R6.1/R14. Содержательных изменений R0–R14: 0. Связано: Tooling v2.6, Pravila v1.20, CLAUDE.md v2.6. План `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`.
|
||||
|
||||
- **v3.5 (2026-05-17)** — фактическая правка R10.1 Блок 1 (security-guidance): хук **блокирующий** (`sys.exit(2)`, одноразовый speed-bump per «файл+правило» за сессию), не warn-only. Содержательных изменений R0–R14: 0. Связано: Tooling v2.5, Pravila v1.19, CLAUDE.md v2.5. План `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`.
|
||||
|
||||
- **v3.4 (2026-05-17)** — D3 audit-security: R10.1 Блок 1 (`enabledPlugins`) +2 строки (Trail of Bits Skills #39, security-guidance #40) — новая 6-я off-phase подкатегория audit-security. Связано: Tooling v2.4, Pravila v1.18, CLAUDE.md v2.4. План `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`.
|
||||
|
||||
- **v3.3 (2026-05-17)** — A6 architecture-tooling: R10.1 Блок 1 (`enabledPlugins`) +2 строки — **adr-kit** (`rvdbreemen/adr-kit`, 8 skills + агент `adr-generator`; `adr-judge` врезан в lefthook pre-commit job 9 декларативно, без `--llm` → 0 вызовов Claude API) + **architecture-patterns** (`secondsky/claude-skills`, knowledge-only справочник паттернов). Блок 1 +note про **mermaid-skill** (вендоренный сторонний скил `.claude/skills/mermaid/`, генератор C4-диаграмм — пассивная утилита вне типологии 3 блоков). Новая категория **architecture-tooling** (Tooling #36-38, раздел A6 карты «Архитектура систем») — не UI → вне R6.0/R6.1/R14 pipeline, как debug-runtime и infrastructure. Содержательных изменений R0–R9/R11–R14: 0. Связано: Tooling v2.2→v2.3, Pravila v1.16→v1.17, CLAUDE.md v2.2→v2.3. Через manual Edit. План `docs/superpowers/plans/2026-05-17-a6-architecture-tooling-integration.md`.
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
# Правила работы Claude в проекте «Лидерра»
|
||||
|
||||
**Версия:** v1.18 (17.05.2026)
|
||||
**Версия:** v1.20 (17.05.2026)
|
||||
**Дата:** 17.05.2026
|
||||
**Назначение:** настройки проекта (Project instructions) — Claude читает этот файл в каждом чате и следует правилам ниже.
|
||||
**Статус документа:** ✅ утверждён. Содержимое скопировано в поле "Project instructions" Claude.ai. Файл хранится в архиве как служебный документ.
|
||||
|
||||
**Что изменилось в v1.20 относительно v1.19:** §13.2 +абзац «Off-phase project-management» — формализованы 2 инструмента раздела C9 карты «Управление проектами» (#41 CCPM, #42 product-management) как седьмая off-phase категория; §13.2 PSR_v1 cross-ref v3.5+ → v3.6+. Связано: Tooling v2.6 / PSR_v1 v3.6 / CLAUDE.md v2.6; план `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`.
|
||||
|
||||
**Что изменилось в v1.19 относительно v1.18:** §13.2 абзац «Off-phase audit-security» — фактическая правка характеристики #40 Security Guidance: это **блокирующий** PreToolUse-хук (`sys.exit 2`, одноразовый speed-bump per «файл+правило» за сессию), не warn-only. §13.2 PSR_v1 cross-ref v3.4+ → v3.5+. Связано: Tooling v2.5 / PSR_v1 v3.5 / CLAUDE.md v2.5; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`.
|
||||
|
||||
**Что изменилось в v1.18 относительно v1.17:** §13.2 +абзац «Off-phase audit-security» — формализованы 2 инструмента раздела D3 карты «Аудит и управление рисками» (#39 Trail of Bits Skills, #40 Security Guidance) как шестая off-phase категория; §13.2 PSR_v1 cross-ref v3.3+ → v3.4+. Связано: Tooling v2.4 / PSR_v1 v3.4 / CLAUDE.md v2.4; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`.
|
||||
|
||||
**Что изменилось в v1.17 относительно v1.16:** §13.2 +абзац «Off-phase architecture-tooling» — формализованы 3 инструмента раздела A6 карты «Архитектура систем» (#36 adr-kit, #37 mermaid-skill, #38 architecture-patterns) как пятая off-phase категория; §13.2 PSR_v1 cross-ref v3.2+ → v3.3+. Связано: Tooling v2.3 / PSR_v1 v3.3 / CLAUDE.md v2.3; план `docs/superpowers/plans/2026-05-17-a6-architecture-tooling-integration.md`.
|
||||
@@ -560,6 +564,9 @@ P0 = блокер старта спринта или регуляторного
|
||||
| **v1.15** | **15.05.2026** | Новый §14 «Ruflo Queen routing — hard rule»: триггер queen/королева → безусловный route через ruflo Queen (`hive-mind spawn --claude`), enforcement-хук `tools/ruflo-queen-hook.mjs`. §13.6 tier-таблица +строка §14 (explicit hard-rule). §0 priority chain +§14 +note. §14.3 — проактивное предложение ruflo-spawn на нетривиальных задачах. Связано: spec/plan 2026-05-15-ruflo-queen-trigger-and-delegation, CLAUDE.md v2.1, PSR_v1 v3.1, Tooling v2.1. Через `superpowers:brainstorming` → `writing-plans` → `subagent-driven-development`. |
|
||||
| **v1.16** | **16.05.2026** | Реколлаж ruflo — приведение декларации к фактическому рантайму: §12 Superpowers переведён из sub-policy обратно в explicit hard-rule; §0 priority note и §14.6 cross-ref — убраны упоминания ruflo как «уровня −1»; §11.5/§13.2/§13.9/§13.10 cross-refs на PSR_v1 v3.2. Связано: CLAUDE.md v2.2 / PSR_v1 v3.2 / Tooling v2.2; spec `docs/superpowers/specs/2026-05-16-ruflo-hierarchy-factual-recollage-design.md`. |
|
||||
| **v1.17** | **17.05.2026** | A6 architecture-tooling: §13.2 +абзац «Off-phase architecture-tooling» — формализованы 3 инструмента раздела A6 карты «Архитектура систем» (#36 adr-kit, #37 mermaid-skill, #38 architecture-patterns) как пятая off-phase категория, отдельная от UI-пула / infrastructure / debug-runtime / orchestration; не UI → вне R6.0/R6.1/R14. §13.2 PSR_v1 cross-ref v3.2+ → v3.3+. Связано: Tooling v2.2→v2.3 (§4.11-4.13 + §0 счётчик 35→38), PSR_v1 v3.2→v3.3 (R10.1 Блок 1 +2 строки + note), CLAUDE.md v2.2→v2.3 (§3.3 +#36-38). Через manual Edit (Pravila/PSR_v1/Tooling) + `/claude-md-management:claude-md-improver` (CLAUDE.md per §5 п.10). План `docs/superpowers/plans/2026-05-17-a6-architecture-tooling-integration.md`. Архитектурных изменений в §§1–12 + §§13.1, 13.3–14: 0. |
|
||||
| **v1.18** | **17.05.2026** | D3 audit-security: §13.2 +абзац «Off-phase audit-security» — формализованы 2 инструмента раздела D3 карты «Аудит и управление рисками» (#39 Trail of Bits Skills, #40 Security Guidance) как шестая off-phase категория; §13.2 PSR_v1 cross-ref v3.3+ → v3.4+. Связано: Tooling v2.4 / PSR_v1 v3.4 / CLAUDE.md v2.4. План `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`. |
|
||||
| **v1.19** | **17.05.2026** | Фактическая правка §13.2 абзаца «Off-phase audit-security»: #40 Security Guidance — **блокирующий** PreToolUse-хук (`sys.exit 2`, одноразовый speed-bump per «файл+правило» за сессию), не warn-only; §13.2 PSR_v1 cross-ref v3.4+ → v3.5+. Связано: Tooling v2.5 / PSR_v1 v3.5 / CLAUDE.md v2.5. План `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`. |
|
||||
| **v1.20** | **17.05.2026** | C9 project-management: §13.2 +абзац «Off-phase project-management» — формализованы 2 инструмента раздела C9 карты «Управление проектами» (#41 CCPM, #42 product-management) как седьмая off-phase категория, отдельная от UI-пула / infrastructure / debug-runtime / orchestration / architecture-tooling / audit-security; не UI → вне R6.0/R6.1/R14. §13.2 PSR_v1 cross-ref v3.5+ → v3.6+. Связано: Tooling v2.6 (§4.16-4.17 + §0 счётчик 40→42), PSR_v1 v3.6 (R10.1 Блок 1 +2 строки + note), CLAUDE.md v2.6 (§3.3 +#41-42). Через manual Edit (Pravila/PSR_v1/Tooling) + `/claude-md-management:claude-md-improver` (CLAUDE.md per §5 п.10). План `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`. Архитектурных изменений в §§1–12 + §§13.1, 13.3–14: 0. |
|
||||
|
||||
---
|
||||
|
||||
@@ -692,11 +699,13 @@ Frontend Design и `obra/superpowers` (v5.1.0, 14 skills) — **парный sta
|
||||
|
||||
**Инфраструктурные плагины (вне расширенного UI-пула, v1.9+):** `claude-md-management` (skills `claude-md-improver` + `revise-claude-md`, marketplace `anthropics/claude-plugins-official`) — единственный интерфейс правок CLAUDE.md (CLAUDE.md §5 п.10). Категория **инфраструктурная**, не UI — поэтому не попадает под §13 (расширенный UI-пул) и не проходит R6.0/R6.1 фильтр / R14 pipeline. Регулируется PSR_v1 R10.1 блок 1 (`enabledPlugins`-плагины) как off-pool tool. Аналогичные инфраструктурные категории — built-in skills Claude Code (`review`, `security-review`, `init`, `simplify`, `update-config`, `keybindings-help`, `fewer-permission-prompts`, `loop`, `schedule`, `claude-api`) — активируются по явному `/имя` от пользователя; PSR_v1 R10.1 блок 2.
|
||||
|
||||
**Off-phase MCP debug-runtime (отдельная категория, введена v1.13 Pravila, 13.05.2026 day +1):** `@sentry/mcp-server@0.33.0+` (Tooling #34, server `sentry` в `.mcp.json`) — отладка production errors в self-hosted Sentry (Yandex Cloud per CLAUDE.md §2; pending Б-1 ООО registration); `@modelcontextprotocol/server-redis@2025.4.25` (Tooling #35, server `redis` в `.mcp.json`; deprecated Anthropic source; Memurai PONG verified Task 4) — отладка Redis/Memurai runtime (очереди, кэш, Pest --parallel races per quirk 72/77). **Категория отдельная** от UI-пула (§13.2 paired-stack + UPM + 21st) и от infrastructure (claude-md-management §13.2 paragraph выше) — **не trigger'ит R6.0/R6.1 stack-фильтры** (READ-ONLY, не модифицируют code/UI/CLAUDE.md) и **не входит в R14 pipeline** UI-генераторов. Регулируется PSR_v1 R10.1 Блок 3 (`.mcp.json`-серверы) как debug-runtime off-phase tool. READ-ONLY usage обязателен — никаких mutation операций (DEL/FLUSHDB/SET/LPUSH для Redis; write actions для Sentry). Установлены retrospective на feat/claude-automation `6f7e7d7` (sentry) + `bd4ec48` (redis), merged через PR #3 (`cc5f63b`). PSR_v1 cross-ref: **v3.4+**, R10.1 Блок 3.
|
||||
**Off-phase MCP debug-runtime (отдельная категория, введена v1.13 Pravila, 13.05.2026 day +1):** `@sentry/mcp-server@0.33.0+` (Tooling #34, server `sentry` в `.mcp.json`) — отладка production errors в self-hosted Sentry (Yandex Cloud per CLAUDE.md §2; pending Б-1 ООО registration); `@modelcontextprotocol/server-redis@2025.4.25` (Tooling #35, server `redis` в `.mcp.json`; deprecated Anthropic source; Memurai PONG verified Task 4) — отладка Redis/Memurai runtime (очереди, кэш, Pest --parallel races per quirk 72/77). **Категория отдельная** от UI-пула (§13.2 paired-stack + UPM + 21st) и от infrastructure (claude-md-management §13.2 paragraph выше) — **не trigger'ит R6.0/R6.1 stack-фильтры** (READ-ONLY, не модифицируют code/UI/CLAUDE.md) и **не входит в R14 pipeline** UI-генераторов. Регулируется PSR_v1 R10.1 Блок 3 (`.mcp.json`-серверы) как debug-runtime off-phase tool. READ-ONLY usage обязателен — никаких mutation операций (DEL/FLUSHDB/SET/LPUSH для Redis; write actions для Sentry). Установлены retrospective на feat/claude-automation `6f7e7d7` (sentry) + `bd4ec48` (redis), merged через PR #3 (`cc5f63b`). PSR_v1 cross-ref: **v3.6+**, R10.1 Блок 3.
|
||||
|
||||
**Off-phase architecture-tooling (отдельная категория, v1.17, 17.05.2026):** три инструмента раздела A6 карты «Архитектура систем» — `adr-kit` (Tooling #36, marketplace `rvdbreemen/adr-kit`; ADR-решения в `docs/adr/`, `adr-judge` врезан в lefthook pre-commit job 9 декларативно, без `--llm`), `mermaid-skill` (Tooling #37, вендоренный сторонний скил `.claude/skills/mermaid/`; C4/architecture-диаграммы), `architecture-patterns` (Tooling #38, marketplace `secondsky/claude-skills`; knowledge-only справочник паттернов). **Категория отдельная** от UI-пула (UPM/21st), infrastructure (claude-md-management) и debug-runtime (Sentry/Redis) — не UI, **не trigger'ит R6.0/R6.1 stack-фильтры и не входит в R14 pipeline**. Регулируется PSR_v1 R10.1 Блок 1 (adr-kit, architecture-patterns) + Блок 1 note (mermaid-skill — вендоренный скил вне типологии трёх блоков). Установлены 17.05.2026 на ветке `feat/a6-architecture-tooling`; план `docs/superpowers/plans/2026-05-17-a6-architecture-tooling-integration.md`.
|
||||
|
||||
**Off-phase audit-security (отдельная категория, v1.18, 17.05.2026):** инструменты раздела D3 карты «Аудит и управление рисками» — `Trail of Bits Skills` (Tooling #39, marketplace `trailofbits/skills`; курированный субсет 8 audit-плагинов — security-аудит diff, supply-chain риск зависимостей; CC-BY-SA-4.0, marketplace-плагин не вендорен), `Security Guidance` (Tooling #40, marketplace `anthropics/claude-plugins-official`; один PreToolUse warn-only хук — inline-предупреждения уязвимостей, не блокирует). Дополнительно `/security-review` (Anthropic built-in, customized в `.claude/commands/security-review.md` с проектным FP-фильтром RLS/ПДн/economy-хуки). **Категория отдельная** от UI-пула, infrastructure, debug-runtime, orchestration и architecture-tooling — не UI, **не trigger'ит R6.0/R6.1 stack-фильтры и не входит в R14 pipeline**. Регулируется PSR_v1 R10.1 Блок 1. Установлены 17.05.2026 на ветке `feat/d3-audit-risk-tooling`; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`.
|
||||
**Off-phase audit-security (отдельная категория, v1.18, 17.05.2026):** инструменты раздела D3 карты «Аудит и управление рисками» — `Trail of Bits Skills` (Tooling #39, marketplace `trailofbits/skills`; курированный субсет 8 audit-плагинов — security-аудит diff, supply-chain риск зависимостей; CC-BY-SA-4.0, marketplace-плагин не вендорен), `Security Guidance` (Tooling #40, marketplace `anthropics/claude-plugins-official`; один **блокирующий** PreToolUse-хук — inline-предупреждения уязвимостей, `sys.exit 2`, одноразовый speed-bump per «файл+правило» за сессию). Дополнительно `/security-review` (Anthropic built-in, customized в `.claude/commands/security-review.md` с проектным FP-фильтром RLS/ПДн/economy-хуки). **Категория отдельная** от UI-пула, infrastructure, debug-runtime, orchestration и architecture-tooling — не UI, **не trigger'ит R6.0/R6.1 stack-фильтры и не входит в R14 pipeline**. Регулируется PSR_v1 R10.1 Блок 1. Установлены 17.05.2026 на ветке `feat/d3-audit-risk-tooling`; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`.
|
||||
|
||||
**Off-phase project-management (отдельная категория, v1.20, 17.05.2026):** инструменты раздела C9 карты «Управление проектами» — `CCPM` (Tooling #41, вендоренный standalone-скил в `.claude/skills/ccpm/`, `automazeio/ccpm` MIT; PRD→эпик→GitHub-issue→код с трассируемостью через `/pm` flow; GitHub-issue-backed модель ADR-004; bus-factor — community-проект, mitigation — вендоринг), `product-management` (Tooling #42, marketplace `anthropics/knowledge-work-plugins`, Anthropic Verified; product-strategy церемонии: `/write-spec`, `/roadmap-update`, `/stakeholder-update`, `/synthesize-research`, `/competitive-brief`, `/metrics-review`). GitHub MCP (Tooling #3) reuse с `projects` toolset для GitHub Projects v2 (не новый слот). **Категория отдельная** от UI-пула, infrastructure, debug-runtime, orchestration, architecture-tooling и audit-security — не UI, **не trigger'ит R6.0/R6.1 stack-фильтры и не входит в R14 pipeline**. Регулируется PSR_v1 R10.1 Блок 1. Установлены 17.05.2026 на ветке `feat/c9-project-management-tooling`; план `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`.
|
||||
|
||||
### 13.3. Скоуп
|
||||
|
||||
|
||||
+31
-8
@@ -1,10 +1,10 @@
|
||||
# Приложение Н — Tooling, скиллы и плагины Claude (v8.3)
|
||||
|
||||
**Дата:** 17.05.2026
|
||||
**Версия:** 2.4 (D3 audit-security — формализованы #39 Trail of Bits Skills (субсет 8 audit-плагинов, marketplace `trailofbits`, CC-BY-SA-4.0) + #40 Security Guidance (Anthropic warn-only PreToolUse-хук) как новая 6-я off-phase подкатегория «audit-security» — §4.14/§4.15; §0 счётчик 38→40 (58→60 total); off-phase row +8→+10. Связано: PSR_v1 v3.4, Pravila v1.18, CLAUDE.md v2.4; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`. **v2.3 наследие:** A6 architecture-tooling — формализованы 3 инструмента раздела A6 карты «Архитектура систем»: **#36 adr-kit** (ADR-решения + `adr-judge` gate), **#37 mermaid-skill** (C4-диаграммы), **#38 architecture-patterns** (паттерны) — новые §4.11–4.13, новая пятая off-phase подкатегория «architecture-tooling»; §0 счётчик 35→38 формализованных позиций (55→58 total), §0 table row off-phase +5→+8. Связано: PSR_v1 v3.3, Pravila v1.17, CLAUDE.md v2.3; план `docs/superpowers/plans/2026-05-17-a6-architecture-tooling-integration.md`. **v2.2 наследие:** §4.10 реколлаж — ruflo переописан из «entry-point иерархии» в «advisory/automation-подсистему» (декларация приведена к рантайму: рой idle, 0 задач); заголовок §4.10 + «Архитектурная роль» переписаны; §0 table row + «Категории off-phase tools» + «Назначение» обновлены; §13 +v2.2 entry. Связано: Pravila v1.16, PSR_v1 v3.2, CLAUDE.md v2.2; spec `docs/superpowers/specs/2026-05-16-ruflo-hierarchy-factual-recollage-design.md`. **v2.1 наследие:** §4.10 +абзац «Queen trigger»: триггер queen/королева → безусловный route через ruflo Queen (`hive-mind spawn --claude`), explicit hard-rule Pravila §14, enforcement-хук `tools/ruflo-queen-hook.mjs`. Связано: spec/plan `docs/superpowers/{specs,plans}/2026-05-15-ruflo-queen-trigger-and-delegation*`, Pravila v1.15, CLAUDE.md v2.1, PSR_v1 v3.1. **v2.0 наследие:** Ruflo big-bang — major bump: добавлен **orchestration layer (ruflo)** как четвёртая off-phase подкатегория. §0 +ruflo orchestration row: 35 формализованных позиций + 20 ruflo plugins = 55 total; новая §4.10 «Orchestration layer (ruflo)». Связано: spec/plan 2026-05-15, Pravila v1.14, PSR_v1 v3.0, CLAUDE.md v2.0.)
|
||||
**Версия:** 2.6 (C9 project-management — формализованы #41 CCPM (vendored standalone skill) + #42 product-management (Anthropic-verified marketplace plugin) как новая 7-я off-phase подкатегория «project-management» — §4.16/§4.17; §0 счётчик 40→42 (60→62 total); off-phase row +10→+12. Связано: PSR_v1 v3.6, Pravila v1.20, CLAUDE.md v2.6; план `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`. **v2.5 наследие:** фактическая правка #40 Security Guidance — это **блокирующий** PreToolUse-хук (`sys.exit(2)`), не warn-only: при первом за сессию срабатывании уязвимого паттерна блокирует правку (одноразовый speed-bump, retry проходит). §4.15 переписан, SG1 уточнён, +SG2 — Windows-починка python3-резолва (`python3.exe`-шим). Счётчики не меняются — 40 позиций. Связано: PSR_v1 v3.5, Pravila v1.19, CLAUDE.md v2.5; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`. **v2.4 наследие:** D3 audit-security — формализованы #39 Trail of Bits Skills (субсет 8 audit-плагинов, marketplace `trailofbits`, CC-BY-SA-4.0) + #40 Security Guidance (Anthropic PreToolUse-хук) как новая 6-я off-phase подкатегория «audit-security» — §4.14/§4.15; §0 счётчик 38→40 (58→60 total); off-phase row +8→+10. Связано: PSR_v1 v3.4, Pravila v1.18, CLAUDE.md v2.4; план `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`. **v2.3 наследие:** A6 architecture-tooling — формализованы 3 инструмента раздела A6 карты «Архитектура систем»: **#36 adr-kit** (ADR-решения + `adr-judge` gate), **#37 mermaid-skill** (C4-диаграммы), **#38 architecture-patterns** (паттерны) — новые §4.11–4.13, новая пятая off-phase подкатегория «architecture-tooling»; §0 счётчик 35→38 формализованных позиций (55→58 total), §0 table row off-phase +5→+8. Связано: PSR_v1 v3.3, Pravila v1.17, CLAUDE.md v2.3; план `docs/superpowers/plans/2026-05-17-a6-architecture-tooling-integration.md`. **v2.2 наследие:** §4.10 реколлаж — ruflo переописан из «entry-point иерархии» в «advisory/automation-подсистему» (декларация приведена к рантайму: рой idle, 0 задач); заголовок §4.10 + «Архитектурная роль» переписаны; §0 table row + «Категории off-phase tools» + «Назначение» обновлены; §13 +v2.2 entry. Связано: Pravila v1.16, PSR_v1 v3.2, CLAUDE.md v2.2; spec `docs/superpowers/specs/2026-05-16-ruflo-hierarchy-factual-recollage-design.md`. **v2.1 наследие:** §4.10 +абзац «Queen trigger»: триггер queen/королева → безусловный route через ruflo Queen (`hive-mind spawn --claude`), explicit hard-rule Pravila §14, enforcement-хук `tools/ruflo-queen-hook.mjs`. Связано: spec/plan `docs/superpowers/{specs,plans}/2026-05-15-ruflo-queen-trigger-and-delegation*`, Pravila v1.15, CLAUDE.md v2.1, PSR_v1 v3.1. **v2.0 наследие:** Ruflo big-bang — major bump: добавлен **orchestration layer (ruflo)** как четвёртая off-phase подкатегория. §0 +ruflo orchestration row: 35 формализованных позиций + 20 ruflo plugins = 55 total; новая §4.10 «Orchestration layer (ruflo)». Связано: spec/plan 2026-05-15, Pravila v1.14, PSR_v1 v3.0, CLAUDE.md v2.0.)
|
||||
**Предыдущая версия:** 1.17 (13.05.2026 day +1 — формализация retrospective двух off-phase MCP debug-инструментов установленных на feat/claude-automation `6f7e7d7` + `bd4ec48` после merge PR #3 в main `cc5f63b`: §0 счётчик off-phase 3 → 5, итого 33 → 35; §4.8 новый — #34 Sentry MCP; §4.9 новый — #35 Redis MCP. Категория debug-runtime, отдельная от UI-пула.)
|
||||
**Адресат:** Claude + разработчики проекта Лидерра
|
||||
**Назначение:** единый источник истины по 40 формализованным позициям тулчейна + 20 ruflo orchestration plugins = 60 total (29 «активных» номеров фаз + 10 off-phase инструментов-резерв в категориях UI-пул, инфраструктура, debug-runtime, architecture-tooling, audit-security — UPM, 21st, claude-md-management, Sentry MCP, Redis MCP, adr-kit, mermaid-skill, architecture-patterns, Trail of Bits Skills, Security Guidance; +1 заменённый PG MCP исторически; +ruflo advisory/automation-подсистема — 20 plugins, см. §4.10), скиллам Claude Code, MCP-серверам и плагинам, используемым в проекте. Зафиксирован выбор, объяснено, что заменяет что, и в какой фазе вводится каждый инструмент.
|
||||
**Назначение:** единый источник истины по 42 формализованным позициям тулчейна + 20 ruflo orchestration plugins = 62 total (29 «активных» номеров фаз + 12 off-phase инструментов-резерв в категориях UI-пул, инфраструктура, debug-runtime, architecture-tooling, audit-security, project-management — UPM, 21st, claude-md-management, Sentry MCP, Redis MCP, adr-kit, mermaid-skill, architecture-patterns, Trail of Bits Skills, Security Guidance, CCPM, product-management; +1 заменённый PG MCP исторически; +ruflo advisory/automation-подсистема — 20 plugins, см. §4.10), скиллам Claude Code, MCP-серверам и плагинам, используемым в проекте. Зафиксирован выбор, объяснено, что заменяет что, и в какой фазе вводится каждый инструмент.
|
||||
|
||||
> **Связано:**
|
||||
>
|
||||
@@ -81,10 +81,10 @@
|
||||
| **1 — старт Laravel** | `composer create-project laravel/laravel` | **17** | +9 новых, −1 заменённый (PostgreSQL MCP → Laravel Boost) |
|
||||
| **2 — старт frontend** | первый коммит в `resources/js/` (Vue 3 + Vuetify 3) | **24** | +7 (включая #30 Frontend Design plugin, добавлен post-MVP в v1.10) |
|
||||
| **3 — pre-production** | ~спринт 12, перед публичным релизом | **29** | +5 |
|
||||
| **off-phase tools** | по факту включения в `~/.claude/settings.json` / `~/.claude.json` / `.mcp.json` / `.claude/skills/` | **+10** | #31 UPM (UI-резерв), #32 21st Magic MCP (UI-генератор), #33 claude-md-management (инфраструктура CLAUDE.md edits), #34 Sentry MCP (debug self-hosted Sentry в Yandex Cloud), #35 Redis MCP (debug Memurai/Redis runtime), #36 adr-kit (ADR-решения, architecture-tooling), #37 mermaid-skill (C4-диаграммы), #38 architecture-patterns (паттерны), #39 Trail of Bits Skills (8 audit-плагинов, audit-security), #40 Security Guidance (inline security warn-hook) |
|
||||
| **off-phase tools** | по факту включения в `~/.claude/settings.json` / `~/.claude.json` / `.mcp.json` / `.claude/skills/` | **+12** | #31 UPM (UI-резерв), #32 21st Magic MCP (UI-генератор), #33 claude-md-management (инфраструктура CLAUDE.md edits), #34 Sentry MCP (debug self-hosted Sentry в Yandex Cloud), #35 Redis MCP (debug Memurai/Redis runtime), #36 adr-kit (ADR-решения, architecture-tooling), #37 mermaid-skill (C4-диаграммы), #38 architecture-patterns (паттерны), #39 Trail of Bits Skills (8 audit-плагинов, audit-security), #40 Security Guidance (inline security warn-hook), #41 CCPM (PRD→эпик→issue→код трассируемость, project-management), #42 product-management (product-strategy церемонии, project-management) |
|
||||
| **ruflo advisory/automation-подсистема** (off-phase, post-MVP 2026-05-15) | `npx ruflo@latest init` + `.mcp.json` ruflo entry | **+20 plugins** | `ruflo` v3.7.0-alpha.38+ + 20 plugins (`@claude-flow/*`, IPFS-registry) — advisory/automation-подсистема; orchestration подкатегория off-phase (см. §4.10) |
|
||||
|
||||
**Итого формализованных позиций:** 40 (29 активных по фазам + 10 off-phase + 1 заменённый PG MCP исторически) + 20 ruflo orchestration plugins = **60 total**. Полный перечень — §2–§5 (по фазам) + §4.5/§4.6/§4.7/§4.8/§4.9/§4.11/§4.12/§4.13/§4.14/§4.15 (off-phase) + §4.10 (ruflo orchestration). Карта «когда что использовать» — §7. Что НЕ ставим и почему — §9.
|
||||
**Итого формализованных позиций:** 42 (29 активных по фазам + 12 off-phase + 1 заменённый PG MCP исторически) + 20 ruflo orchestration plugins = **62 total**. Полный перечень — §2–§5 (по фазам) + §4.5/§4.6/§4.7/§4.8/§4.9/§4.11/§4.12/§4.13/§4.14/§4.15/§4.16/§4.17 (off-phase) + §4.10 (ruflo orchestration). Карта «когда что использовать» — §7. Что НЕ ставим и почему — §9.
|
||||
|
||||
**Ключевой принцип фазирования:** не активируем фазу N+1, пока не закрыт триггер фазы N. Без `composer create-project` Boost не работает; без Vuetify-приложения Histoire бесполезен.
|
||||
|
||||
@@ -428,15 +428,35 @@
|
||||
|
||||
### 4.15. Security Guidance — inline-предупреждения уязвимостей (off-phase, audit-security)
|
||||
|
||||
**Security Guidance** (Claude Code plugin, marketplace `anthropics/claude-plugins-official`, plugin `security-guidance@claude-plugins-official`, Anthropic Verified). Один PreToolUse `Write|Edit|MultiEdit`-хук — **warn-only**: печатает session-scoped предупреждение об уязвимом паттерне (8 категорий — command/shell injection, `eval`, XSS, pickle-десериализация и т.д.) перед применением правки, **не блокирует**.
|
||||
**Security Guidance** (Claude Code plugin, marketplace `anthropics/claude-plugins-official`, plugin `security-guidance@claude-plugins-official`, Anthropic Verified). Один PreToolUse `Write|Edit|MultiEdit`-хук — **блокирующий** (не warn-only): при **первом** за сессию срабатывании уязвимого паттерна в данном файле печатает предупреждение в stderr и завершается `sys.exit(2)` → **блокирует правку**. Пара «файл+правило» пишется в session state-файл `~/.claude/security_warnings_state_<id>.json` — повторная попытка той же правки проходит; это **одноразовый speed-bump**, не безусловный блок. 9 правил: 8 контентных (command/shell injection `child_process.exec`/`os.system`, `eval(`, `new Function`, XSS через `innerHTML`/`document.write`/`dangerouslySetInnerHTML`, `pickle`-десериализация) + 1 path-правило на `.github/workflows/*.yml`. Отключается env `ENABLE_SECURITY_REMINDER=0`.
|
||||
|
||||
**Роль:** инструмент **#40**, раздел D3 — real-time inline-напоминание об уязвимостях во время редактирования (дополняет on-demand аудит ToB/Semgrep).
|
||||
|
||||
**Категория:** off-phase, audit-security. Регулируется PSR_v1 R10.1 Блок 1.
|
||||
|
||||
**Конфликт-аудит интеграции:** SG1 — добавляет 5-й PreToolUse-хук поверх 4 существующих (skill-marker / skill-check / economy-state-guard в `~/.claude/settings.json` + CLAUDE.md-warn в проектном `.claude/settings.json`); warn-only (не `decision:block`), economy/ruflo-цепочка хуков не нарушается, +~34 мс/правку latency принято. `/security-review` (Anthropic built-in, customized в `.claude/commands/security-review.md` с проектным FP-фильтром — RLS/ПДн/economy-хуки) — D3 #2, не отдельный нумерованный слот (built-in, не installed tool).
|
||||
**Конфликт-аудит интеграции:** SG1 — добавляет 5-й PreToolUse-хук поверх 4 существующих (skill-marker / skill-check / economy-state-guard в `~/.claude/settings.json` + CLAUDE.md-warn в проектном `.claude/settings.json`); хук **блокирующий** (`sys.exit(2)`), но одноразовый per «файл+правило» за сессию — economy/ruflo-цепочка не нарушается (PreToolUse-хуки независимы, SG блокирует только на свой уязвимый паттерн), +~34 мс/правку latency. **SG2 (Windows-починка, 17.05.2026):** bundled `hooks.json` жёстко зовёт интерпретатор `python3`, которого в PATH этой машины нет (есть `python` 3.14.4) → без починки хук не спаунился, SG был инертен. Решено: `python3.exe` (копия `python.exe`) добавлен в каталог установки Python в PATH — кэш плагина не трогается, починка переживает обновления плагина. Verified end-to-end 17.05.2026 (manual smoke → `sys.exit 2` + in-session Write-блокировка). `/security-review` (Anthropic built-in, customized в `.claude/commands/security-review.md` с проектным FP-фильтром — RLS/ПДн/economy-хуки) — D3 #2, не отдельный нумерованный слот (built-in, не installed tool).
|
||||
|
||||
**Категории off-phase tools (v2.4):** шесть подкатегорий — UI-пул (#31 UPM + #32 21st), infrastructure (#33 claude-md-management), debug-runtime (#34 Sentry + #35 Redis), orchestration (ruflo §4.10), **architecture-tooling (#36 adr-kit + #37 mermaid-skill + #38 architecture-patterns)**, **audit-security (#39 Trail of Bits Skills + #40 Security Guidance)**.
|
||||
**Категории off-phase tools (v2.6):** семь подкатегорий — UI-пул (#31 UPM + #32 21st), infrastructure (#33 claude-md-management), debug-runtime (#34 Sentry + #35 Redis), orchestration (ruflo §4.10), **architecture-tooling (#36 adr-kit + #37 mermaid-skill + #38 architecture-patterns)**, **audit-security (#39 Trail of Bits Skills + #40 Security Guidance)**, **project-management (#41 CCPM + #42 product-management)**.
|
||||
|
||||
### 4.16. CCPM — Claude Code PM (off-phase, project-management)
|
||||
|
||||
**CCPM** (`automazeio/ccpm`, MIT) — standalone-скил, **вендорен** в `.claude/skills/ccpm/` (`SKILL.md` + `references/` с гайдами + 14 bash-скриптов). **0 Claude Code lifecycle-хуков** (статически верифицировано — нет `hooks/`-папки). Источник: GitHub `automazeio/ccpm`; вендоринг изолирует от upstream-потерь (bus-factor — community-проект — CC1).
|
||||
|
||||
**Роль:** инструмент **#41**, раздел C9 карты «Управление проектами». PRD→эпик→GitHub-issue→код с полной трассируемостью через `/pm` flow. PRD/epic хранятся в `.claude/prds/` + `.claude/epics/`. GitHub-issue-backed модель (конфликт-аудит CP3, зафиксировано в ADR-004). Раздел C9 опирается также на reuse: GitHub MCP (Tooling #3) с `projects` toolset для GitHub Projects v2, Superpowers `writing-plans` (execution plan-files), `q-item-add` (управление реестром вопросов).
|
||||
|
||||
**Категория:** off-phase, **project-management** — седьмая off-phase подкатегория (отдельная от UI-пула UPM/21st, infrastructure claude-md-management, debug-runtime Sentry/Redis, orchestration ruflo, architecture-tooling adr-kit/mermaid/architecture-patterns, audit-security Trail of Bits Skills/Security Guidance). Не UI → **не** проходит R6.0/R6.1/R14 PSR_v1. Регулируется PSR_v1 R10.1 Блок 1.
|
||||
|
||||
**Конфликт-аудит интеграции:** CP2 — граница с Superpowers `writing-plans`: CCPM = PRD/epic/issue трассируемость; `writing-plans` = execution plan-files (разные артефакты, не дублируют). CP3 — GitHub-issue-backed модель зафиксирована в ADR-004 (docs/adr/ADR-004). CP5 — PRD/epic store `.claude/prds/`/`.claude/epics/` исключён из markdownlint/cspell нормального flow (вендорные артефакты, как `.claude/skills/`). Plan `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`.
|
||||
|
||||
### 4.17. product-management — Anthropic product-strategy plugin (off-phase, project-management)
|
||||
|
||||
**product-management** (Claude Code plugin, marketplace `anthropics/knowledge-work-plugins`, plugin `product-management@knowledge-work-plugins`, **Anthropic Verified**). Команды: `/write-spec` (PRD), `/roadmap-update`, `/stakeholder-update`, `/synthesize-research`, `/competitive-brief`, `/metrics-review`. **0 Claude Code lifecycle-хуков** (только команды, не хуки).
|
||||
|
||||
**Роль:** инструмент **#42**, раздел C9 — product-strategy церемонии (problem→spec, roadmap, stakeholder updates, research synthesis, competitive analysis, metrics review). Установлен в user-scope (`claude plugin install product-management@knowledge-work-plugins`).
|
||||
|
||||
**Категория:** off-phase, project-management. Регулируется PSR_v1 R10.1 Блок 1.
|
||||
|
||||
**Конфликт-аудит интеграции:** PG3 — граница с CCPM `/write-spec` vs CCPM PRD: product-management PRD = product-strategy-уровень (problem→spec, roadmap-aligned); CCPM PRD = engineering epic→issue→code трассируемость. Разный altitude — не дублируют. Plan `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`.
|
||||
|
||||
---
|
||||
|
||||
@@ -726,10 +746,13 @@ Vuetify-тема — `liderraLight` и `liderraDark` — определена в
|
||||
| **v2.1** | **15.05.2026** | §4.10 +абзац «Queen trigger»: триггер queen/королева → безусловный route через ruflo Queen (`hive-mind spawn --claude`), explicit hard-rule Pravila §14, enforcement-хук `tools/ruflo-queen-hook.mjs`; footer-колонтитул v2.1. Связано: spec/plan `docs/superpowers/{specs,plans}/2026-05-15-ruflo-queen-trigger-and-delegation*`, Pravila v1.15 / CLAUDE.md v2.1 / PSR_v1 v3.1. |
|
||||
| **v2.2** | **16.05.2026** | **§4.10 реколлаж:** ruflo переописан из «entry-point иерархии» в «advisory/automation-подсистему» (декларация приведена к рантайму: рой idle, 0 задач / 0 раундов консенсуса; Claude-сессии работают напрямую). Заголовок §4.10 изменён («Orchestration layer (ruflo) — entry-point иерархии» → «ruflo — advisory/automation-подсистема»); «Архитектурная роль» переписана; §0 table row обновлён; «Категории off-phase tools» обновлены; «Назначение» обновлено; шапка v2.1 → v2.2, дата 16.05.2026. Связано: Pravila v1.16, PSR_v1 v3.2, CLAUDE.md v2.2; spec `docs/superpowers/specs/2026-05-16-ruflo-hierarchy-factual-recollage-design.md`. |
|
||||
| **v2.3** | **17.05.2026** | **A6 architecture-tooling:** формализованы 3 инструмента раздела A6 карты «Архитектура систем» как новая пятая off-phase подкатегория «architecture-tooling» — **§4.11 #36 adr-kit** (ADR-решения, `adr-judge` lefthook job 9), **§4.12 #37 mermaid-skill** (C4-диаграммы, вендорен в `.claude/skills/mermaid/`), **§4.13 #38 architecture-patterns** (паттерны). §0 счётчик 35→38 формализованных позиций (55→58 total); §0 table row off-phase `+5`→`+8`; «Назначение» обновлено. Конфликт-аудит интеграции — AK1 (git-хук adr-kit не ставится, `adr-judge` через lefthook), AK2 (`init` не пишет CLAUDE.md), AK6 (`adr-judge` без `--llm` → 0 стоимости), MK1 (lefthook exclude вендоренного скила). Связано: PSR_v1 v3.2→v3.3 (R10.1 +3 строки), Pravila v1.16→v1.17 (§13.2 +architecture-tooling абзац), CLAUDE.md v2.2→v2.3 (§3.3 +#36-38). Через manual Edit (Tooling/PSR_v1/Pravila) + `/claude-md-management:claude-md-improver` (CLAUDE.md per §5 п.10). План `docs/superpowers/plans/2026-05-17-a6-architecture-tooling-integration.md`. |
|
||||
| **v2.4** | 17.05.2026 | **D3 audit-security:** формализованы #39 Trail of Bits Skills (субсет 8 audit-плагинов, marketplace `trailofbits`, CC-BY-SA-4.0) + #40 Security Guidance (Anthropic warn-only PreToolUse-хук) как новая 6-я off-phase подкатегория «audit-security» — §4.14/§4.15. §0 счётчик 38→40 (58→60 total); off-phase row +8→+10. Конфликт-аудит — TB1 (граница с Semgrep MCP), TB4 (CC-BY-SA не триггерится — не вендорено), SG1 (5-й PreToolUse warn-хук). Связано: PSR_v1 v3.3→v3.4 (R10.1 Блок 1 +2 строки), Pravila v1.17→v1.18 (§13.2 +audit-security абзац), CLAUDE.md v2.3→v2.4 (§3.3 +#39-40). План `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`. |
|
||||
| **v2.4** | 17.05.2026 | **D3 audit-security:** формализованы #39 Trail of Bits Skills (субсет 8 audit-плагинов, marketplace `trailofbits`, CC-BY-SA-4.0) + #40 Security Guidance (Anthropic PreToolUse-хук) как новая 6-я off-phase подкатегория «audit-security» — §4.14/§4.15. §0 счётчик 38→40 (58→60 total); off-phase row +8→+10. Конфликт-аудит — TB1 (граница с Semgrep MCP), TB4 (CC-BY-SA не триггерится — не вендорено), SG1 (5-й PreToolUse-хук). Связано: PSR_v1 v3.3→v3.4 (R10.1 Блок 1 +2 строки), Pravila v1.17→v1.18 (§13.2 +audit-security абзац), CLAUDE.md v2.3→v2.4 (§3.3 +#39-40). План `docs/superpowers/plans/2026-05-17-d3-audit-risk-tooling-integration.md`. |
|
||||
| **v2.5** | 17.05.2026 | **Фактическая правка #40 Security Guidance:** §4.15 переписан — это **блокирующий** PreToolUse-хук (`sys.exit(2)` на первой за сессию правке с уязвимым паттерном, retry проходит — одноразовый speed-bump), не warn-only; SG1 уточнён; +SG2 — Windows-починка python3-резолва (`python3.exe`-шим, кэш плагина не трогается). Verified end-to-end (manual smoke + in-session Write-блок). Счётчики без изменений — 40 позиций. Связано: PSR_v1 v3.5, Pravila v1.19, CLAUDE.md v2.5. |
|
||||
|
||||
---
|
||||
|
||||
*Прил. Н v2.5 от 17.05.2026 — фактическая правка #40 Security Guidance: блокирующий PreToolUse-хук (`sys.exit(2)`, не warn-only) + SG2 Windows-починка python3-резолва. Связано: PSR_v1 v3.5, Pravila v1.19, CLAUDE.md v2.5.*
|
||||
|
||||
*Прил. Н v2.4 от 17.05.2026 — D3 audit-security: формализованы #39 Trail of Bits Skills + #40 Security Guidance (§4.14/§4.15), новая 6-я off-phase подкатегория. 40 формализованных позиций (29 по фазам + 10 off-phase + 1 PG MCP) + 20 ruflo = 60 total. Связано: PSR_v1 v3.4, Pravila v1.18, CLAUDE.md v2.4.*
|
||||
|
||||
*Прил. Н v2.3 от 17.05.2026 — A6 architecture-tooling: формализованы #36 adr-kit + #37 mermaid-skill + #38 architecture-patterns (§4.11–4.13), новая пятая off-phase подкатегория. 38 формализованных позиций (29 по фазам + 8 off-phase + 1 PG MCP) + 20 ruflo = 58 total. Связано: PSR_v1 v3.3, Pravila v1.17, CLAUDE.md v2.3.*
|
||||
|
||||
@@ -2,7 +2,9 @@
|
||||
|
||||
## Status
|
||||
|
||||
Accepted, 2026-05-17.
|
||||
Accepted, 2026-05-17. Amended 2026-05-17 — corrected the Security Guidance
|
||||
characterisation (a blocking `PreToolUse` hook, not warn-only) and recorded the
|
||||
`python3.exe` shim needed on the Windows dev host.
|
||||
|
||||
## Context
|
||||
|
||||
@@ -26,8 +28,10 @@ The D3 audit and risk-management toolset is:
|
||||
(`differential-review`, `audit-context-building`, `supply-chain-risk-auditor`,
|
||||
`insecure-defaults`, `sharp-edges`, `static-analysis`, `variant-analysis`,
|
||||
`agentic-actions-auditor`) for deep, on-demand audit campaigns.
|
||||
- **Security Guidance** — the Anthropic warn-only `PreToolUse` hook plugin, for
|
||||
inline vulnerability reminders while editing.
|
||||
- **Security Guidance** — the Anthropic `PreToolUse` hook plugin, for inline
|
||||
vulnerability reminders while editing. The hook is **blocking** (`sys.exit(2)`):
|
||||
the first edit per session whose content matches a vulnerable pattern in a
|
||||
given file is blocked once — a one-time speed-bump, the retry passes.
|
||||
- **adr-kit** — reused, not re-installed. The decision and risk register is the
|
||||
set of ADRs in `docs/adr/`: each ADR's `## Consequences` records the residual
|
||||
risks of a decision, and the `docs/Открытые_вопросы` registry holds the
|
||||
@@ -70,7 +74,11 @@ The D3 audit and risk-management toolset is:
|
||||
and supply-chain risk; mitigated by marketplace-cache pinning and re-checked
|
||||
on plugin upgrades.
|
||||
- Security Guidance adds one `PreToolUse` hook to a chain that already carries
|
||||
four — a small per-edit latency cost, accepted because the hook is warn-only.
|
||||
four — a small per-edit latency cost. The hook is **blocking** (`sys.exit(2)`),
|
||||
not warn-only; the block is a one-time per-file-and-rule speed-bump, so the
|
||||
cost is bounded. On this Windows host the bundled `hooks.json` hardcodes the
|
||||
`python3` interpreter, which is absent — fixed by a `python3.exe` shim in the
|
||||
Python install directory on PATH (the plugin cache is not modified).
|
||||
- The toolchain attack surface still depends on a manual procedure until a
|
||||
vetted auto-auditor exists.
|
||||
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
# ADR-004: Project-management tooling (C9)
|
||||
|
||||
- **Status:** Accepted
|
||||
- **Date:** 2026-05-17
|
||||
- **Deciders:** Дмитрий
|
||||
|
||||
## Context
|
||||
|
||||
The `C9 «Управление проектами»` map section had zero tooling. Planning was done
|
||||
ad-hoc via `docs/superpowers/plans/` files, the `Открытые_вопросы` registry, and
|
||||
sprint notes in memory. GitHub Issues were barely used (FF-push workflow).
|
||||
|
||||
## Decision
|
||||
|
||||
- Project management adopts a **GitHub-issue-backed** model: CCPM
|
||||
(vendored skill) drives PRD→epic→issue→code with traceability; epics are
|
||||
parent issues, tasks are sub-issues.
|
||||
- The **GitHub Projects v2** board (official GitHub MCP `projects` toolset) is
|
||||
the sprint/iteration board.
|
||||
- Execution plans stay as `docs/superpowers/plans/` files (Superpowers).
|
||||
- The `Открытые_вопросы` registry remains the home of *open* questions; an ADR
|
||||
records *closed* decisions; CCPM tracks *features in flight*.
|
||||
- product-management (Anthropic) is added only if Claude-Code-installable.
|
||||
|
||||
## Consequences
|
||||
|
||||
- Positive: C9 populated; planning traceable; sprints visible on a board.
|
||||
- Risk: CCPM is third-party (bus-factor) — mitigated by vendoring.
|
||||
- Risk: a workflow shift toward GitHub Issues — accepted, this is the decision.
|
||||
|
||||
## Enforcement
|
||||
|
||||
None — C9 tools are advisory; verified by use and code review.
|
||||
@@ -9,7 +9,8 @@ procedures and their artifacts.
|
||||
- `/security-review` — the customized Anthropic security-review command
|
||||
(`.claude/commands/security-review.md`).
|
||||
- Trail of Bits Skills — the `trailofbits` marketplace audit plugins.
|
||||
- Security Guidance — the Anthropic warn-only inline-vulnerability hook.
|
||||
- Security Guidance — the Anthropic inline-vulnerability hook (blocking
|
||||
`PreToolUse`, a one-time per-file-and-rule speed-bump).
|
||||
- `audit-portal` — the project skill encoding the 14-phase portal audit.
|
||||
|
||||
## Boundaries
|
||||
|
||||
@@ -249,6 +249,8 @@ const NODES = [
|
||||
// D3 audit-security (17.05.2026) — 2 плагина раздела «Аудит и управление рисками»
|
||||
{ id: 'tob_skills', label: 'Trail of Bits\nskills', group: 'plugins', size: 22, ring: 2, ...pos(2, 330) },
|
||||
{ id: 'sec_guidance', label: 'Security\nGuidance', group: 'plugins', size: 20, ring: 2, ...pos(2, 345) },
|
||||
// C9 project-management-tooling (17.05.2026) — плагин раздела «Управление проектами»
|
||||
{ id: 'product_mgmt', label: 'product-\nmanagement', group: 'plugins', size: 20, ring: 2, ...pos(2, 355) },
|
||||
|
||||
// ── СКИЛЫ SUPERPOWERS (14) — N sector (0–90) ────
|
||||
{ id: 'sk_brainstorm', label: 'brainstorming', group: 'skills_sp', size: 18, ring: 3, ...pos(3, 5) },
|
||||
@@ -275,6 +277,8 @@ const NODES = [
|
||||
// D3 audit-security (17.05.2026) — скилы раздела «Аудит и управление рисками»
|
||||
{ id: 'sk_security_review', label: 'security-review', group: 'skills_proj', size: 20, ring: 3, ...pos(3, 315) },
|
||||
{ id: 'sk_audit_portal', label: 'audit-portal', group: 'skills_proj', size: 20, ring: 3, ...pos(3, 325) },
|
||||
// C9 project-management-tooling (17.05.2026) — вендоренный скил раздела «Управление проектами»
|
||||
{ id: 'ccpm', label: 'CCPM\n(skill)', group: 'skills_proj', size: 18, ring: 3, ...pos(3, 335) },
|
||||
|
||||
// ── ХУКИ (12) — S+infra + E (economy/skill) ───
|
||||
{ id: 'hk_session', label: 'SessionStart:\ncontext-inject', group: 'hooks', size: 24, ring: 4, ...pos(4, 100) },
|
||||
@@ -721,6 +725,24 @@ const NODE_DETAILS = {
|
||||
[{ name: 'docs/architecture/', cond: 'C4-диаграммы → c4-context.md' }]
|
||||
),
|
||||
|
||||
// ── C9 PROJECT-MANAGEMENT-TOOLING (17.05.2026) ──
|
||||
ccpm: nd(
|
||||
'Vendored-скил CCPM: PRD→эпик→GitHub-issue→код с трассируемостью. Раздел C9 опирается также на reuse — GitHub MCP (issues/Projects v2) + Superpowers writing-plans + q-item-add.',
|
||||
'При создании PRD, декомпозиции на эпики/задачи, связывании с GitHub Issues — стек CCPM + GitHub MCP + writing-plans.',
|
||||
'Вендорен в .claude/skills/ccpm/ (C9 project-management-tooling, off-phase). Раздел C9. Tooling #41, CLAUDE.md §3.3 #41.',
|
||||
[{ name: 'Tooling', cond: '§4.16 #41 — реестр' }],
|
||||
[],
|
||||
[{ name: 'GitHub MCP', cond: 'CCPM использует GitHub Issues/Projects v2 как source-of-truth' }]
|
||||
),
|
||||
product_mgmt: nd(
|
||||
'Плагин Anthropic (product-management@knowledge-work-plugins): PRD/роадмап/метрики — product-strategy церемонии.',
|
||||
'При написании PRD, обновлении роадмапа, анализе метрик продукта — skills product-management плагина.',
|
||||
'Правило PSR_v1 R10.1 блок 1 (project-management-tooling, off-phase). Не UI → вне фильтров R6.0/R6.1/R14. Tooling #42, CLAUDE.md §3.3 #42.',
|
||||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: project-management-tooling' }, { name: 'Tooling', cond: '§4.17 #42 — реестр' }],
|
||||
[],
|
||||
[]
|
||||
),
|
||||
|
||||
// ── D3 AUDIT-SECURITY (17.05.2026) ───────────────
|
||||
tob_skills: nd(
|
||||
'Marketplace-плагин Trail of Bits (`trailofbits/skills`) — курированный субсет 8 audit-плагинов: `differential-review`, `audit-context-building`, `supply-chain-risk-auditor`, `insecure-defaults`, `sharp-edges`, `static-analysis`, `variant-analysis`, `agentic-actions-auditor`. Глубокие on-demand аудит-кампании. Раздел D3. Tooling #39, off-phase audit-security.',
|
||||
@@ -732,9 +754,9 @@ const NODE_DETAILS = {
|
||||
[{ name: 'MCP: semgrep', desc: 'TB1: граница разграничена регламентом — Semgrep = inline SAST в процессе работы, Trail of Bits = глубокие аудит-кампании по запросу. Параллельное использование разрешено при разных сценариях.', type: 'GREEN' }]
|
||||
),
|
||||
sec_guidance: nd(
|
||||
'Anthropic-плагин (`security-guidance@claude-plugins-official`, Anthropic Verified) — один warn-only PreToolUse-хук, inline-предупреждения уязвимостей при правке кода (8 категорий). Не блокирует, только предупреждает. Раздел D3. Tooling #40.',
|
||||
'Активен автоматически при каждом Write/Edit/MultiEdit — печатает предупреждение об уязвимом паттерне перед правкой файла.',
|
||||
'Правило PSR_v1 R10.1 блок 1 (audit-security, off-phase). SG1: 5-й PreToolUse-хук, +~34 мс/правку, economy/ruflo-цепочка не нарушается. Warn-only — не блокирует. Не UI → вне R6.0/R6.1/R14. Tooling §4.15, CLAUDE.md §3.3 #40.',
|
||||
'Anthropic-плагин (`security-guidance@claude-plugins-official`, Anthropic Verified) — один блокирующий PreToolUse-хук, inline-предупреждения уязвимостей при правке кода (8 контентных правил + 1 path-правило). При первом за сессию совпадении уязвимого паттерна в файле — sys.exit(2), блокирует правку (одноразовый speed-bump, retry проходит). Раздел D3. Tooling #40.',
|
||||
'Активен автоматически при каждом Write/Edit/MultiEdit — при уязвимом паттерне печатает предупреждение и блокирует первую такую правку файла за сессию; повторная попытка проходит.',
|
||||
'Правило PSR_v1 R10.1 блок 1 (audit-security, off-phase). SG1: 5-й PreToolUse-хук, блокирующий (sys.exit 2), одноразовый per «файл+правило» за сессию — economy/ruflo-цепочка не нарушается, +~34 мс/правку. SG2: Windows-починка — bundled hooks.json зовёт python3 (нет в PATH), решено python3.exe-шимом в каталоге Python. Не UI → вне R6.0/R6.1/R14. Tooling §4.15, CLAUDE.md §3.3 #40.',
|
||||
[{ name: 'PSR_v1', cond: 'R10.1 блок 1: audit-security' }, { name: 'Tooling', cond: '§4.15 #40 — реестр' }],
|
||||
[],
|
||||
[{ name: 'скил security-review', cond: 'оба — D3 audit-security; sec_guidance inline, sk_security_review ручной' }]
|
||||
@@ -1839,6 +1861,10 @@ const NODE_META = {
|
||||
sec_guidance: { since: '17.05.2026', changed: '—', uses: null, usesSrc: 'хук' },
|
||||
sk_security_review: { since: '17.05.2026', changed: '—', uses: null, usesSrc: 'скил' },
|
||||
sk_audit_portal: { since: '17.05.2026', changed: '—', uses: null, usesSrc: 'скил' },
|
||||
|
||||
// ── C9 PROJECT-MANAGEMENT-TOOLING 17.05.2026 ──
|
||||
ccpm: { since: '17.05.2026', changed: '—', uses: null, usesSrc: 'скил' },
|
||||
product_mgmt: { since: '17.05.2026', changed: '—', uses: null, usesSrc: 'плагин' },
|
||||
};
|
||||
|
||||
// Явные парные дубли (Фича 3) — попадают в кнопку «⧉ Дубли».
|
||||
@@ -1921,7 +1947,7 @@ const SECTIONS = [
|
||||
{ id: 'E7', bucket: 'E', label: 'Исследования' },
|
||||
{ id: 'E8', bucket: 'E', label: 'Самообучение Claude' },
|
||||
];
|
||||
// Узел -> раздел. Покрывает все 110 узлов карты.
|
||||
// Узел -> раздел. Покрывает все 112 узлов карты.
|
||||
const NODE_SECTION = {
|
||||
// правила (4)
|
||||
pravila: 'E1', claude_md: 'E1', psr_v1: 'E1', tooling: 'E1',
|
||||
@@ -1967,6 +1993,8 @@ const NODE_SECTION = {
|
||||
adr_kit: 'A6', arch_patterns: 'A6', mermaid_skill: 'A6',
|
||||
// D3 audit-security 17.05.2026 — раздел «Аудит и управление рисками» наполнен
|
||||
tob_skills: 'D3', sec_guidance: 'D3', sk_security_review: 'D3', sk_audit_portal: 'D3',
|
||||
// C9 project-management-tooling 17.05.2026 — раздел «Управление проектами» наполнен
|
||||
ccpm: 'C9', product_mgmt: 'C9',
|
||||
};
|
||||
// Производные индексы для рендера панели и Паспорта.
|
||||
const SECTION_BY_ID = new Map(SECTIONS.map(s => [s.id, s]));
|
||||
|
||||
@@ -0,0 +1,40 @@
|
||||
# docs/projects — project-management playbook (map section C9)
|
||||
|
||||
Home of the `C9 «Управление проектами»` section. Defines how the Лидерра
|
||||
development project is planned, tracked, and reported.
|
||||
|
||||
## Toolset
|
||||
|
||||
- **CCPM** (`.claude/skills/ccpm/`) — the PRD→epic→GitHub-issue→code traceability
|
||||
layer. PRDs live in `.claude/prds/`, epics/tasks in `.claude/epics/<feature>/`.
|
||||
Invoked via the `/pm` flow / the `ccpm` skill.
|
||||
- **GitHub MCP** — issues, sub-issues (epic = parent issue, task = sub-issue),
|
||||
and **Projects v2** boards used as the sprint/iteration board.
|
||||
- **Superpowers `writing-plans` / `executing-plans` / `subagent-driven-development`**
|
||||
— authoring and running execution plan-files in `docs/superpowers/plans/`.
|
||||
- **`q-item-add` skill + `docs/Открытые_вопросы_v8_3.md`** — the open-question
|
||||
registry (Б-/CTO-/Ю-/Диз-/DO-/OPEN- codes).
|
||||
- **product-management plugin** (if installed — see Task 5) — PRD/roadmap/metrics
|
||||
product-strategy ceremonies.
|
||||
|
||||
## Boundaries (which tool for which artifact)
|
||||
|
||||
- **Open product/business/legal question** → `Открытые_вопросы` registry. Not an
|
||||
epic, not an ADR — it has no resolution yet.
|
||||
- **A closed technical/architecture decision** → `docs/adr/` (adr-kit, A6).
|
||||
- **A feature to build, with engineering traceability** → a CCPM PRD → epic →
|
||||
GitHub issues.
|
||||
- **The step-by-step execution plan for that epic** → a `docs/superpowers/plans/`
|
||||
file (Superpowers `writing-plans`). CCPM tracks *what & status*; the plan
|
||||
file tracks *how, task-by-task*.
|
||||
- **Product-strategy spec / roadmap** → product-management `/write-spec` /
|
||||
`/roadmap-update` (if installed); else a registry/WISHLIST entry.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Idea → CCPM PRD (`.claude/prds/`).
|
||||
2. PRD → epic + GitHub issues (CCPM `sync`, via GitHub MCP `issue_write` /
|
||||
`sub_issue_write`).
|
||||
3. Epic → a `docs/superpowers/plans/` plan-file → execution.
|
||||
4. Status → CCPM `status.sh` / `standup.sh`; the GitHub Projects v2 board is the
|
||||
sprint view.
|
||||
@@ -0,0 +1,672 @@
|
||||
# A11 ML / AI Tooling Integration Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Populate the empty `A11 «ML / AI-разработка»` map section with a conflict-minimal ML/AI toolset — document a **reuse core** (claude-api skill + context7 MCP + Sentry MCP), install **two new light tools** (promptfoo, a vendored Data Scientist skill), and register **Jupyter MCP as a deferred reserved slot** — so A11 becomes a working playbook.
|
||||
|
||||
**Architecture:** A11 is an **empty** functional section — `NODE_SECTION` in `docs/automation-graph.html` tags zero nodes `A11`. Approach А (chosen 2026-05-17): a **reuse layer** (claude-api skill, context7 MCP, Sentry MCP — all already installed; A11 documents the coverage, never re-tags their nodes) plus **two new installs** — promptfoo as a root `package.json` devDependency, and a Data Scientist skill vendored as a standalone skill into `.claude/skills/data-scientist/` (no plugin, no marketplace, no hooks — the A6 mermaid pattern). **Jupyter MCP** (executable notebooks) is **deferred** — registered now as a reserved slot, installed later by a separate severable task gated on a Python ML environment + a concrete model to train. All A11 tools are non-UI → a new **ml-ai-tooling** off-phase category, outside the PSR_v1 UI-pool. A11 artifacts live in `docs/ml/`.
|
||||
|
||||
**Tech Stack:** promptfoo (`promptfoo/promptfoo`, npm package `promptfoo`, MIT); a Data Scientist skill (vendored standalone skill, MIT/permissive — exact repo resolved in Task 1); Jupyter MCP (`datalayer/jupyter-mcp-server` — deferred, not installed); the already-installed claude-api skill / context7 MCP / Sentry MCP (reuse); project normative docs; `docs/automation-graph.html` (vis.js).
|
||||
|
||||
**Sequencing (2026-05-17):** the A6 / D3 / C9 epics land and push **first** (they touch the same shared files: the map, 4 normative docs, the Tooling counter). A11 then rebases onto the updated `origin/main` (Task 8 Step 1). The working branch `feat/a11-ml-ai-tooling` already exists and holds the brainstorming spec commit (`ae423be`). A11's Tooling numbers are runtime-resolved (NUM1) — never hard-coded before reading the live counter. Push pattern: `git push origin feat/a11-ml-ai-tooling:main`.
|
||||
|
||||
---
|
||||
|
||||
## Tool Identity (verified 2026-05-17 via WebSearch)
|
||||
|
||||
| # | Tool | Install mode | Source / License | Hooks? |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **promptfoo** — CLI test-suite for LLM prompts/agents/RAG: declarative `promptfooconfig.yaml`, assertions (`equals`/`contains`/`llm-rubric`/cost/latency), model comparison, red-teaming. Invoked `npx promptfoo`. | npm **devDependency** in the root `package.json` (`npm i -D promptfoo`) — version-pinned via `package-lock.json` (ML9) | GitHub `promptfoo/promptfoo`, **MIT** (OpenAI-owned since 2026, remains OSS) | None — npm CLI, no Claude Code lifecycle hooks |
|
||||
| 2 | **Data Scientist skill** — knowledge-only skill: business objective → ML task, algorithm selection (Linear Regression … XGBoost), feature engineering, experiment-tracking + A/B-analysis guidance. | Standalone skill — **vendored** copy into `.claude/skills/data-scientist/` (no plugin, no marketplace) | Exact repo **resolved Task 1 Step 4** — candidates: `secondsky/claude-skills` (the A6 architecture-patterns marketplace), `alirezarezvani/claude-skills` (263+ skills), or a dedicated data-science skill repo. MIT/permissive required. | None disclosed (skills-only) — **verify on vendor** |
|
||||
| — | **Jupyter MCP** (`datalayer/jupyter-mcp-server`) — executable notebooks: insert/run cells, read outputs, plots. | **NOT installed** — deferred reserved slot (see "Deferred Task"). | GitHub `datalayer/jupyter-mcp-server` | n/a — not installed |
|
||||
| — | **claude-api skill** / **context7 MCP** / **Sentry MCP** | **Reuse** — already installed | claude-api: plugin skill; context7: MCP (`mcp__plugin_context7_context7__*`); Sentry: Tooling #34 | n/a |
|
||||
|
||||
**Verification status:** promptfoo — repo, MIT, npm package name, config-file convention confirmed via WebSearch. Data Scientist skill — the *category* (151+ data-science skills in the marketplace) and the "Data Scientist" skill *concept* confirmed; the **exact source repo is NOT pinned** → Task 1 Step 4 resolves it with concrete criteria. Jupyter MCP — `datalayer/jupyter-mcp-server` confirmed to exist; **not installed by this plan**.
|
||||
|
||||
**Deferred (with reason — no task in this plan):**
|
||||
|
||||
- **Jupyter MCP** — would be the 8th `.mcp.json` server; experimental (Notebook 6.x only); requires a Python ML environment that the native-Windows machine deliberately lacks; and there is no model to train. Registered in the Tooling registry as a **pending** slot (Task 6); installed later by the severable task described in "Deferred Task" below.
|
||||
|
||||
**Dropped (with reason — no task, no slot):**
|
||||
|
||||
- **A dedicated LLM-observability tool** (Langfuse / Helicone) — redundant with Sentry's AI/LLM monitoring on the already-installed Sentry MCP (#34); CLAUDE.md §5 п.6 (no two tools for one job).
|
||||
- **A standalone Claude-API plugin** — the claude-api skill is already available; installing a second is a §5 п.6 duplication.
|
||||
- **An `ml-developer`-style agent plugin** — the agent layer is already crowded; promptfoo + the Data Scientist skill + claude-api cover the workflow without a new agent.
|
||||
|
||||
---
|
||||
|
||||
## Design Decisions & Conflict Audit
|
||||
|
||||
Pattern follows the K1–K8 / AK1–CC1 / CP1–NUM1 audits used for claude-mem and the A6 / C9 / D3 plans. Verified against the promptfoo repo, project `.claude/settings.json`, `~/.claude/settings.json`, `.mcp.json`, `lefthook.yml`, `cspell.json`, `.markdownlintignore`, root `package.json`, and the A6 plan.
|
||||
|
||||
| # | Tool | Sev | Conflict | Resolution (locked) |
|
||||
|---|---|---|---|---|
|
||||
| ML1 | promptfoo | 🟡 | A real eval run needs an Anthropic API key and makes **paid** LLM calls. Putting it in a hook / pre-commit would cost money on every commit and could break the economy chain. | promptfoo runs **manually / CI-only** — never in a hook, never a lefthook job, never auto. No `lefthook.yml` change. The API key lives in an env var (`ANTHROPIC_API_KEY`, PowerShell User scope — the Sentry `SENTRY_AUTH_TOKEN` pattern), never committed. Documented in `docs/ml/README.md` (Task 4) + the Tooling entry (Task 6). |
|
||||
| ML2 | promptfoo | 🟢 | promptfoo's red-team module overlaps the D3 audit-security tools. | None — promptfoo red-team tests *LLM prompts* for jailbreak/injection; D3 Trail of Bits (#39) + Semgrep (#25) are SAST of *code*. Different objects. Boundary stated in `docs/ml/README.md` (Task 4) + the Tooling entry (Task 6). |
|
||||
| ML3 | Data Scientist skill | 🟡 | Vendored `.claude/skills/data-scientist/**/*.md` (third-party English files) is caught by the cspell + markdownlint pre-commit jobs. | Add `.claude/skills/data-scientist/**` to `cspell.json` `ignorePaths` and `.claude/skills/data-scientist/` to `.markdownlintignore` (Task 3 Step 4) — the A6 MK1 pattern. The project's own skills (`q-item-add`, `rls-check`, `regression`, `mermaid`) stay linted. |
|
||||
| ML4 | reuse layer | 🟢 | Re-tagging the existing `context7` (E7) / `mcp_sentry` (A7) map nodes to A11 would empty their current sections — `NODE_SECTION` is 1-node→1-section. | Reuse nodes **stay** in their sections. A11 gets its **own** new nodes (`claude_api`, `promptfoo`, `data_scientist`). The reuse coverage is documented in `docs/ml/README.md` (Task 4) and noted in the new nodes' details (Task 7). Same as A6/D3/C9 REU1. |
|
||||
| ML5 | all | 🟢 | A11 is non-UI tooling. | New off-phase category **ml-ai-tooling**, outside the PSR_v1 UI-pool → no R6.0/R6.1 stack-filter, no R14 pipeline — same treatment as `claude-md-management` (infrastructure), the A6 architecture-tooling, and the D3 audit-security categories. Registered in PSR_v1 R10.1 + Pravila §13.2 (Task 6). |
|
||||
| ML6 | promptfoo | 🟢 | 8 PreToolUse/UserPromptSubmit/Stop economy + skill-discipline + ruflo hooks — does promptfoo touch them? | None — promptfoo is an npm CLI invoked on demand; it registers zero Claude Code lifecycle hooks. Re-verified Task 2 Step 5. |
|
||||
| ML7 | all | 🟡 | Bus-factor — the Data Scientist skill is a community project; Jupyter MCP is community + experimental. | The Data Scientist skill is **vendored** → immune to upstream loss (the A6 mermaid pattern). promptfoo is MIT, OpenAI-owned, stable. Jupyter MCP is deferred and will be version-pinned at install. Noted in the Tooling entry (Task 6). No alpha-substrate spike needed for the core scope — neither promptfoo nor the vendored skill has a known-broken core (unlike ruflo K7). |
|
||||
| ML8 | reuse layer | 🟡 | claude-api skill / context7 MCP are used but may not be **formalized** Tooling-registry positions → using them unregistered is a PSR_v1 R0.2/R10 gap. | Task 1 Step 5 audits whether claude-api and context7 are already in `~/.claude/settings.json` `enabledPlugins` + the Tooling registry. Task 6 registers whatever is missing (as reuse positions). Sentry MCP is already Tooling #34. |
|
||||
| ML9 | Jupyter MCP | 🟡 | Registering a tool that is not installed could mislead a future reader into thinking it is available. | The Tooling entry + `docs/ml/README.md` + the map mark Jupyter MCP explicitly **«pending — не установлен, severable-задача»** (the Sentry #34 "pending Sentry deployment" precedent). No `jupyter_mcp` map node is added until the deferred task runs. |
|
||||
| NUM1 | normative sync | 🟡 | The A6 plan claimed Tooling #36-#38, D3 claimed #39-#40, C9 claims the next after that. A11 must not collide. | Task 1 Step 6 + Task 6 Step 1 read the **live** `docs/Tooling_v8_3.md` Прил. Н §0 counter and assign A11's numbers sequentially after whatever is current. Never hard-code a number before reading the live counter. |
|
||||
|
||||
**Severable scope.** Core A11 = Tasks 1-8 (reuse documentation + promptfoo + Data Scientist skill + normative + map + finish) — already populates and closes the section. There is **no severable task inside this plan** (unlike A6's Task 5): the only deferred piece, Jupyter MCP, is a *future* task outside this plan (see "Deferred Task"). A11 adds **no lefthook job** and **no `.mcp.json` change** — fewer conflicts by design (the C9 shape).
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| File | Created / Modified | Responsibility |
|
||||
|---|---|---|
|
||||
| `docs/ml/` | Create dir | A11 home — the ML/AI playbook |
|
||||
| `docs/ml/README.md` | Create | The ML/AI convention: tool boundaries (claude-api skill = *build* / promptfoo = *test* prompts / Data Scientist skill = classical-ML *workflow* / Jupyter MCP = *execute* — deferred); the reuse-layer map; the promptfoo API-key + manual-run note (ML1) |
|
||||
| `docs/ml/promptfoo-example/promptfooconfig.yaml` | Create | One seed eval config — a worked lead-qualification prompt example |
|
||||
| `docs/ml/promptfoo-example/README.md` | Create | How to run the example (`npx promptfoo eval`), the API-key requirement, the "never in CI/hooks" rule |
|
||||
| `.claude/skills/data-scientist/` | Create (vendored) | The Data Scientist skill — `SKILL.md` + `references/` |
|
||||
| `docs/adr/ADR-005-ml-ai-tooling.md` | Create (conditional — adr-kit/A6 landed) | Seed ADR documenting the A11 tooling decision + the Python/Jupyter defer |
|
||||
| `package.json` (repo root) | Modify | `promptfoo` devDependency |
|
||||
| `package-lock.json` (repo root) | Modify | promptfoo dependency tree (written by `npm i`) |
|
||||
| `cspell.json` | Modify | `ignorePaths` += `.claude/skills/data-scientist/**` (ML3) |
|
||||
| `.markdownlintignore` | Modify | += `.claude/skills/data-scientist/` (ML3) |
|
||||
| `cspell-words.txt` | Modify (conditional) | New ML/AI vocabulary |
|
||||
| `docs/Tooling_v8_3.md` | Modify | Прил. Н — new ml-ai-tooling subsection(s) + §0 counter bump |
|
||||
| `docs/Plugin_stack_rules_v1.md` | Modify | R10.1 — new ml-ai-tooling rows |
|
||||
| `docs/Pravila_raboty_Claude_v1_1.md` | Modify | §13.2 — ml-ai-tooling category note |
|
||||
| `CLAUDE.md` | Modify (**via claude-md-management only**) | §3 title count, §1 row 2b count, new §3.3 ml-ai-tooling row(s) |
|
||||
| `docs/CHANGELOG_claude_md.md` | Modify | CLAUDE.md version-bump entry |
|
||||
| `docs/automation-graph.html` | Modify | 3 new A11 nodes (`claude_api`, `promptfoo`, `data_scientist`) → `NODE_SECTION` A11; header metrics |
|
||||
| `.mcp.json` | **NOT modified** | Jupyter MCP deferred — `.mcp.json` is untouched by this plan |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Pre-flight — baseline, branch, snapshot, fact-check
|
||||
|
||||
**Files:** none modified (read-only)
|
||||
|
||||
- [ ] **Step 1: Confirm tree state and branch**
|
||||
|
||||
```bash
|
||||
cd "c:/моя/проекты/портал crm/Документация"
|
||||
git status --short
|
||||
git rev-parse --short HEAD
|
||||
git branch --show-current
|
||||
```
|
||||
|
||||
Expected: branch `feat/a11-ml-ai-tooling`, HEAD at the spec commit `ae423be` (or later). Record the HEAD SHA as the regression baseline. (If a different branch — `git checkout feat/a11-ml-ai-tooling`.)
|
||||
|
||||
- [ ] **Step 2: Snapshot the hook chain**
|
||||
|
||||
Read `.claude/settings.json`, `.claude/settings.local.json` (if present), and `~/.claude/settings.json`. Record every hook on `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `Stop`. This is the ML6 baseline — Task 2 compares against it.
|
||||
Expected (`~/.claude/settings.json`): SessionStart economy-self-check; PreToolUse skill-marker/skill-check/economy-state-guard/CLAUDE.md-warn/security-guidance; UserPromptSubmit economy-mode; PostCompact economy-postcompact; Stop economy-verifier. Project `.claude/settings.json`: ruflo-recall + ruflo-queen (UserPromptSubmit), markdownlint-fix + schema-CHANGELOG-reminder (PostToolUse).
|
||||
|
||||
- [ ] **Step 3: Baseline regression**
|
||||
|
||||
```
|
||||
/regression quick
|
||||
```
|
||||
|
||||
Expected: GREEN. Record the current Pest / Vitest counts from the last green run (memory `project_state.md`). A11 touches no `app/` code → the final run (Task 8) must match.
|
||||
|
||||
- [ ] **Step 4: Fact-check promptfoo + resolve the Data Scientist skill repo**
|
||||
|
||||
promptfoo — open `https://github.com/promptfoo/promptfoo` and confirm: npm package `promptfoo`, MIT license, `promptfooconfig.yaml` config convention, the Anthropic provider id form (`anthropic:messages:<model>`), no Claude Code lifecycle hooks.
|
||||
|
||||
Data Scientist skill — resolve the exact source. WebFetch the candidates and pick **one** repo that satisfies ALL of:
|
||||
|
||||
- ships a real standalone **skill** (`SKILL.md` + optional `references/`), not a plugin requiring marketplace machinery;
|
||||
- MIT or other permissive license;
|
||||
- covers classical-ML workflow (algorithm selection, feature engineering, evaluation, experiment tracking);
|
||||
- no `hooks` block / no Claude Code lifecycle hooks.
|
||||
|
||||
Candidates, in priority order: (a) `secondsky/claude-skills` (already a project marketplace from A6 — check for a `data-science`/`data-scientist` skill dir), (b) `alirezarezvani/claude-skills`, (c) a dedicated data-science skill repo found via WebSearch. Record the chosen repo URL + license + the in-repo path to the skill directory. If a candidate registers CC lifecycle hooks → reject it, try the next.
|
||||
|
||||
If **no** candidate qualifies → **stop**, report to the user; A11 falls back to a project-authored minimal `data-scientist` skill (out of this plan's scope).
|
||||
|
||||
- [ ] **Step 5: Audit reuse-tool registration (ML8)**
|
||||
|
||||
Check whether the reuse tools are already formalized:
|
||||
|
||||
- `~/.claude/settings.json` `enabledPlugins` — is the claude-api skill's backing plugin listed? Record yes/no + the plugin id.
|
||||
- `.mcp.json` / `~/.claude/settings.json` — is context7 configured? (It is — `mcp__plugin_context7_context7__*` tools exist.) Record the server/plugin id.
|
||||
- `docs/Tooling_v8_3.md` Прил. Н — grep for `claude-api`, `context7`. Record which (if any) already have a Tooling number.
|
||||
|
||||
This drives Task 6: register whatever reuse tool is missing a Tooling position.
|
||||
|
||||
- [ ] **Step 6: Check A6 landed + read the live Tooling counter (NUM1)**
|
||||
|
||||
```bash
|
||||
git log --oneline | grep -iE "adr-kit|architecture-patterns|mermaid|ADR-00" | head
|
||||
ls docs/adr/ 2>/dev/null
|
||||
```
|
||||
|
||||
Read `docs/Tooling_v8_3.md` Прил. Н §0 — record the **live** tool counter. Record: **A6 landed?** yes/no (drives Task 4's conditional ADR-005 — `docs/adr/ADR-000-adr-process.md` exists ⇒ yes) and the counter value (drives Task 6 numbering). (Note: the Task-0 pre-commit run already showed `adr-judge` as lefthook job 9 + "1 ADR with Enforcement" — A6 has very likely landed; confirm here.)
|
||||
|
||||
No repo files changed → no commit.
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Install promptfoo (npm devDependency — ML1/ML9)
|
||||
|
||||
**Files:** Modify `package.json`, `package-lock.json` (repo root)
|
||||
|
||||
- [ ] **Step 1: Inspect the root `package.json`**
|
||||
|
||||
Read the repo-root `package.json`. Confirm it is the doc-tooling project (scripts `lint:md`, `spell`, `links`, `a11y`; devDependencies `markdownlint-cli2`, `cspell`, etc.). Record the current `devDependencies` shape.
|
||||
|
||||
- [ ] **Step 2: Install promptfoo as a devDependency**
|
||||
|
||||
```bash
|
||||
cd "c:/моя/проекты/портал crm/Документация"
|
||||
npm install --save-dev promptfoo
|
||||
```
|
||||
|
||||
Expected: `promptfoo` appears in `package.json` `devDependencies` with a pinned `^`-range; `package-lock.json` updated. If `npm install` warns about peer deps, record the warning — do NOT use `--force`/`--legacy-peer-deps` unless a hard failure requires it (record the reason if so).
|
||||
|
||||
- [ ] **Step 3: Verify the CLI runs**
|
||||
|
||||
```bash
|
||||
npx promptfoo --version
|
||||
```
|
||||
|
||||
Expected: prints a version number (a real run with no API key still reports `--version`). No paid LLM call is made here.
|
||||
|
||||
- [ ] **Step 4: Add a convenience npm script (optional but recommended)**
|
||||
|
||||
Edit `package.json` `scripts` — add:
|
||||
|
||||
```json
|
||||
"eval:llm": "promptfoo eval -c docs/ml/promptfoo-example/promptfooconfig.yaml"
|
||||
```
|
||||
|
||||
This documents the manual invocation. It is **not** wired into any other script, hook, or CI step (ML1).
|
||||
|
||||
- [ ] **Step 5: Verify NO lifecycle hooks were added (ML6)**
|
||||
|
||||
Read the `hooks` block of `~/.claude/settings.json` AND project `.claude/settings.json`. Both must be **unchanged** vs the Task 1 Step 2 snapshot — npm installs do not touch Claude Code settings, but confirm. If anything changed → stop and re-audit.
|
||||
|
||||
- [ ] **Step 6: Lint + commit**
|
||||
|
||||
```bash
|
||||
git add package.json package-lock.json
|
||||
npx lefthook run pre-commit
|
||||
```
|
||||
|
||||
Expected: all jobs green (`package.json`/`package-lock.json` are JSON — not linted by markdownlint/cspell; gitleaks scans them — promptfoo's tree has no secrets).
|
||||
|
||||
```bash
|
||||
git commit -m "feat(a11): add promptfoo as devDependency for LLM prompt eval (ML1)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Vendor the Data Scientist skill (standalone, vendored — ML3/ML7)
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.claude/skills/data-scientist/` (vendored skill tree)
|
||||
- Modify: `cspell.json`, `.markdownlintignore`
|
||||
|
||||
- [ ] **Step 1: Clone the resolved source to a temp location**
|
||||
|
||||
Using the repo URL + in-repo skill path resolved in Task 1 Step 4:
|
||||
|
||||
```bash
|
||||
git clone --depth 1 <RESOLVED_REPO_URL> /tmp/ds-skill-src
|
||||
ls -R /tmp/ds-skill-src/<RESOLVED_SKILL_PATH>/
|
||||
```
|
||||
|
||||
Expected: a `SKILL.md` + optional `references/` directory.
|
||||
|
||||
- [ ] **Step 2: Verify the skill ships no Claude Code hooks (ML6/ML7)**
|
||||
|
||||
```bash
|
||||
grep -rIl "hooks" /tmp/ds-skill-src --include="*.json" || echo "no hooks json"
|
||||
```
|
||||
|
||||
Expected: no `settings.json` with a `hooks` block. If the skill ships hooks → **stop**, re-audit (pick another candidate from Task 1 Step 4).
|
||||
|
||||
- [ ] **Step 3: Vendor the skill into the project**
|
||||
|
||||
```bash
|
||||
mkdir -p ".claude/skills/data-scientist"
|
||||
cp -r /tmp/ds-skill-src/<RESOLVED_SKILL_PATH>/. ".claude/skills/data-scientist/"
|
||||
ls -R ".claude/skills/data-scientist/"
|
||||
rm -rf /tmp/ds-skill-src
|
||||
```
|
||||
|
||||
Expected: `.claude/skills/data-scientist/SKILL.md` (+ `references/**` if present). The `SKILL.md` frontmatter `name:` should be `data-scientist` (or a clear ML name) — if the upstream `name:` clashes with an existing skill, edit it to `data-scientist`. (Vendoring — not a submodule — keeps it on Windows+Cyrillic paths and immune to upstream loss, ML7.)
|
||||
|
||||
- [ ] **Step 4: Exclude the vendored skill from the doc-lint chain (ML3)**
|
||||
|
||||
Edit `.markdownlintignore` — append:
|
||||
|
||||
```
|
||||
.claude/skills/data-scientist/
|
||||
```
|
||||
|
||||
Edit `cspell.json` — add `.claude/skills/data-scientist/**` to the `ignorePaths` array. Do **not** ignore `.claude/skills/` wholesale — `q-item-add`, `rls-check`, `regression`, `mermaid` stay linted.
|
||||
|
||||
- [ ] **Step 5: Reload and verify the skill is discoverable**
|
||||
|
||||
```
|
||||
/reload-plugins
|
||||
```
|
||||
|
||||
Confirm a `data-scientist` skill is now listed among available skills (project `.claude/skills/` is auto-discovered, like the other project skills). Confirm neither `settings.json` `hooks` block changed (ML6).
|
||||
|
||||
- [ ] **Step 6: Verify lint exclusion works, then commit**
|
||||
|
||||
```bash
|
||||
git add .claude/skills/data-scientist/ cspell.json .markdownlintignore
|
||||
npx lefthook run pre-commit
|
||||
```
|
||||
|
||||
Expected: cspell + markdownlint do NOT report errors from `.claude/skills/data-scientist/**`; all jobs green.
|
||||
|
||||
```bash
|
||||
git commit -m "feat(a11): vendor Data Scientist skill into .claude/skills + lint-ignore (ML3)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: Bootstrap the A11 home — `docs/ml/` + seed promptfoo example + ADR-005
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `docs/ml/README.md`, `docs/ml/promptfoo-example/promptfooconfig.yaml`, `docs/ml/promptfoo-example/README.md`
|
||||
- Create (conditional — A6 landed): `docs/adr/ADR-005-ml-ai-tooling.md`
|
||||
- Modify (conditional): `cspell-words.txt`
|
||||
|
||||
- [ ] **Step 1: Create the A11 home + the ML/AI convention**
|
||||
|
||||
```bash
|
||||
mkdir -p "docs/ml/promptfoo-example"
|
||||
```
|
||||
|
||||
Create `docs/ml/README.md`:
|
||||
|
||||
```markdown
|
||||
# docs/ml — ML / AI playbook (map section A11)
|
||||
|
||||
Home of the `A11 «ML / AI-разработка»` section. Defines the tooling Лидерра uses
|
||||
to build and test ML/AI capability. The portal currently ships no ML/AI code —
|
||||
this section is the toolset, ready for when AI features are scoped.
|
||||
|
||||
## Toolset
|
||||
|
||||
| Tool | Role | Status |
|
||||
|---|---|---|
|
||||
| **claude-api skill** | Build AI features on the Anthropic SDK (lead qualification, call summaries, email drafts) with prompt caching. | reuse — already available |
|
||||
| **context7 MCP** | Up-to-date docs for AI/ML libraries and SDKs. | reuse — already installed |
|
||||
| **Sentry MCP** | Debug AI features in production via Sentry AI/LLM monitoring (read-only). | reuse — Tooling #34, pending the Sentry deployment (Б-1) |
|
||||
| **promptfoo** | Test suite for LLM prompts/agents: assertions, regression, LLM-graded eval, red-team. | installed — `npx promptfoo` |
|
||||
| **Data Scientist skill** | Classical-ML workflow: business objective → ML task, algorithm selection, feature engineering, evaluation. | installed — vendored skill |
|
||||
| **Jupyter MCP** | Executable notebooks for real model training. | **deferred** — see below |
|
||||
|
||||
## Boundaries (which tool for which job)
|
||||
|
||||
- **Building an AI feature** (a prompt-backed endpoint) → the **claude-api skill**.
|
||||
- **Testing / regression-checking an LLM prompt** → **promptfoo** (`docs/ml/promptfoo-example/`).
|
||||
- **A classical-ML modelling question** (which algorithm, how to evaluate) → the
|
||||
**Data Scientist skill**.
|
||||
- **Executing a notebook / training a model** → **Jupyter MCP** — *deferred*.
|
||||
- promptfoo's **red-team** tests *prompts*; the D3 Trail of Bits / Semgrep tools do
|
||||
SAST of *code*. Different objects — not a duplication.
|
||||
|
||||
## promptfoo — running an eval
|
||||
|
||||
promptfoo makes **paid** Anthropic API calls. It runs **manually or in CI only** —
|
||||
never in a git hook, never in pre-commit, never automatically.
|
||||
|
||||
- API key: `ANTHROPIC_API_KEY` env var (PowerShell User scope — the Sentry
|
||||
`SENTRY_AUTH_TOKEN` pattern). Never commit a key.
|
||||
- Run the seed example: `npm run eval:llm` (or
|
||||
`npx promptfoo eval -c docs/ml/promptfoo-example/promptfooconfig.yaml`).
|
||||
|
||||
## Jupyter MCP — why deferred
|
||||
|
||||
Jupyter MCP executes notebooks; it needs a Python ML environment (pandas /
|
||||
scikit-learn / Jupyter). The machine is native Windows, deliberately runtime-minimal
|
||||
(no Docker), and there is no model to train yet. Jupyter MCP is a **reserved slot**:
|
||||
registered in the Tooling registry as *pending*, installed by a separate severable
|
||||
task when a concrete ML model is scoped. See the A11 plan's "Deferred Task".
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Create the seed promptfoo example config**
|
||||
|
||||
Create `docs/ml/promptfoo-example/promptfooconfig.yaml`:
|
||||
|
||||
```yaml
|
||||
# yaml-language-server: $schema=https://promptfoo.dev/config-schema.json
|
||||
# Seed example — A11. Lead-qualification prompt eval.
|
||||
# Run manually: npm run eval:llm (needs ANTHROPIC_API_KEY — never in CI/hooks)
|
||||
description: "Лидерра — lead-qualification prompt eval (example)"
|
||||
|
||||
prompts:
|
||||
- |
|
||||
Классифицируй обращение лида как HOT, WARM или COLD.
|
||||
Ответь РОВНО одним словом — HOT, WARM или COLD.
|
||||
|
||||
Обращение: {{message}}
|
||||
|
||||
providers:
|
||||
- id: anthropic:messages:claude-haiku-4-5-20251001
|
||||
|
||||
tests:
|
||||
- vars:
|
||||
message: "Нужно срочно, бюджет согласован, готовы подписать договор сегодня."
|
||||
assert:
|
||||
- type: equals
|
||||
value: HOT
|
||||
- vars:
|
||||
message: "Интересно, расскажите подробнее про условия и сроки."
|
||||
assert:
|
||||
- type: equals
|
||||
value: WARM
|
||||
- vars:
|
||||
message: "Просто смотрю что есть на рынке, ничего конкретного."
|
||||
assert:
|
||||
- type: equals
|
||||
value: COLD
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Create the example README**
|
||||
|
||||
Create `docs/ml/promptfoo-example/README.md`:
|
||||
|
||||
```markdown
|
||||
# promptfoo example — lead-qualification eval
|
||||
|
||||
A worked promptfoo eval: a HOT/WARM/COLD lead-classification prompt with three
|
||||
assertion cases. Demonstrates the A11 prompt-testing workflow.
|
||||
|
||||
## Run
|
||||
|
||||
```bash
|
||||
# from the repo root; ANTHROPIC_API_KEY must be set (PowerShell User scope)
|
||||
npm run eval:llm
|
||||
```
|
||||
|
||||
This makes **paid** Anthropic API calls. Run it manually or in CI only — never
|
||||
in a git hook or pre-commit (A11 rule ML1). See `docs/ml/README.md`.
|
||||
|
||||
## Adapt
|
||||
|
||||
Copy `promptfooconfig.yaml` next to a real prompt when an AI feature is built.
|
||||
Swap the model, add `tests`, use richer assertions (`contains`, `llm-rubric`,
|
||||
cost/latency thresholds). Full reference: <https://promptfoo.dev/docs/>.
|
||||
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Decide on the conditional ADR (uses Task 1 Step 6 result)**
|
||||
|
||||
If **A6 landed** (`docs/adr/ADR-000-adr-process.md` exists, adr-kit present) → do Step 5. If A6 has **not** landed → skip Step 5, and add a line to `docs/ml/README.md` noting "the A11 tooling decision will be recorded as an ADR once adr-kit (A6) lands". Record the branch taken.
|
||||
|
||||
- [ ] **Step 5: Write ADR-005 (conditional)**
|
||||
|
||||
Create `docs/adr/ADR-005-ml-ai-tooling.md`:
|
||||
```markdown
|
||||
# ADR-005: ML / AI tooling (A11)
|
||||
|
||||
- **Status:** Accepted
|
||||
- **Date:** 2026-05-17
|
||||
- **Deciders:** Дмитрий
|
||||
|
||||
## Context
|
||||
The `A11 «ML / AI-разработка»` map section had zero tooling. Лидерра ships no
|
||||
ML/AI code; `calc_lead_score` is a deterministic SQL function. A toolset is needed
|
||||
for the day AI features (LLM-backed) or a scoring model are scoped.
|
||||
|
||||
## Decision
|
||||
A11 adopts a six-position toolset in two subcategories:
|
||||
- **LLM integration** — the claude-api skill (build), promptfoo (test prompts),
|
||||
Sentry MCP (observe). All reuse or light.
|
||||
- **Classical ML** — a vendored Data Scientist skill (workflow knowledge). The
|
||||
executable part, **Jupyter MCP**, is **deferred**: it needs a Python ML runtime
|
||||
the deliberately-minimal native-Windows machine lacks, and there is no model to
|
||||
train. Jupyter MCP is a reserved registry slot, installed by a separate task
|
||||
when a concrete model is scoped.
|
||||
- promptfoo runs manually / CI only — never in a hook (paid LLM calls).
|
||||
- A11 tools are non-UI → the `ml-ai-tooling` off-phase category.
|
||||
|
||||
## Consequences
|
||||
- Positive: A11 populated; AI features have a build+test+observe toolchain.
|
||||
- Risk: the Data Scientist skill is third-party — mitigated by vendoring.
|
||||
- Deferred: no Python runtime until a model is scoped — accepted, this is the
|
||||
decision.
|
||||
|
||||
## Enforcement
|
||||
None — A11 tools are advisory; verified by use and code review.
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Lint + commit**
|
||||
|
||||
```bash
|
||||
npx markdownlint-cli2 "docs/ml/**/*.md"
|
||||
npx cspell --no-progress --no-summary --no-gitignore "docs/ml/**/*.md"
|
||||
```
|
||||
|
||||
If A6 landed, also lint `docs/adr/ADR-005-*.md`. Add flagged valid terms (`promptfoo`, `promptfooconfig`, `scikit`, `XGBoost`, `Jupyter`, `Лидерра`, etc.) to `cspell-words.txt`. Then:
|
||||
|
||||
```bash
|
||||
git add docs/ml/ cspell-words.txt
|
||||
git add docs/adr/ADR-005-*.md # only if Step 5 ran
|
||||
git commit -m "feat(a11): bootstrap docs/ml — README + promptfoo example + ADR-005"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: Smoke-test the A11 toolset
|
||||
|
||||
**Files:** none modified
|
||||
|
||||
- [ ] **Step 1: Smoke-test promptfoo config validity (no paid call — ML1)**
|
||||
|
||||
```bash
|
||||
npx promptfoo validate -c docs/ml/promptfoo-example/promptfooconfig.yaml
|
||||
```
|
||||
|
||||
Expected: the config parses as valid. (`validate` checks schema only — no LLM call, no cost.) If `validate` is not a subcommand in the installed promptfoo version, instead run `npx promptfoo eval -c docs/ml/promptfoo-example/promptfooconfig.yaml --no-cache` **only if** `ANTHROPIC_API_KEY` is set and the user approves the small cost; otherwise record "config syntax reviewed manually, eval not run (no key / cost)".
|
||||
|
||||
- [ ] **Step 2: Smoke-test the Data Scientist skill**
|
||||
|
||||
Invoke the `data-scientist` skill with a trivial ML question (e.g. "which algorithm and evaluation metric fit predicting lead conversion from CRM features?"). Expected: the skill loads, `SKILL.md` routes the intent, and it returns structured classical-ML guidance (algorithm choice, metrics, validation). Functional smoke — no file output required.
|
||||
|
||||
- [ ] **Step 3: Smoke-test the claude-api skill reuse**
|
||||
|
||||
Confirm the `claude-api` skill is invocable (it appears in the available-skills list). No deep test — A11 only documents it as reuse. Record availability.
|
||||
|
||||
- [ ] **Step 4: Confirm the hook chain is intact (ML6)**
|
||||
|
||||
Submit a trivial prompt; the economy marker still appears, the Stop verifier still runs, ruflo + CLAUDE.md-warn hooks fire. No plugin/skill leaked a `hooks` entry. No repo files changed in Task 5 → no commit.
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Normative registry sync (ML / NUM1)
|
||||
|
||||
**Files:** Modify `docs/Tooling_v8_3.md`, `docs/Plugin_stack_rules_v1.md`, `docs/Pravila_raboty_Claude_v1_1.md`, `CLAUDE.md`, `docs/CHANGELOG_claude_md.md`
|
||||
|
||||
- [ ] **Step 1: Read the registry homes + the live counter (NUM1)**
|
||||
|
||||
Read for exact insertion points and the **current** counter: `docs/Tooling_v8_3.md` Прил. Н §0 + the last `§4.x` subsection; `docs/Plugin_stack_rules_v1.md` R10.1; `docs/Pravila_raboty_Claude_v1_1.md` §13.2. Using the Task 1 Step 5 result, decide the A11 numbers:
|
||||
|
||||
- `#N` promptfoo, `#N+1` Data Scientist skill, `#N+2` Jupyter MCP (registered **pending**) — sequential from `counter + 1`, after any A6/D3/C9 entries.
|
||||
- If Task 1 Step 5 found claude-api / context7 **unregistered**, also assign them numbers (reuse positions). Record the full number assignment.
|
||||
|
||||
- [ ] **Step 2: Add the Tooling Прил. Н ml-ai-tooling subsection(s)**
|
||||
|
||||
Edit `docs/Tooling_v8_3.md`: add a subsection for each new number, category **ml-ai-tooling** (off-phase). Per tool:
|
||||
|
||||
- **promptfoo** — npm `promptfoo` MIT (OpenAI-owned), root `package.json` devDependency, `npx promptfoo`; runs manually/CI only — never in a hook (ML1); red-team boundary vs D3 ToB/Semgrep (ML2); no CC hooks.
|
||||
- **Data Scientist skill** — vendored standalone skill in `.claude/skills/data-scientist/` (source repo from Task 1 Step 4), knowledge-only; bus-factor mitigated by vendoring (ML7).
|
||||
- **Jupyter MCP** — `datalayer/jupyter-mcp-server`, **pending — NOT installed**; deferred severable task gated on a Python ML environment (ML9); the Sentry #34 "pending" precedent.
|
||||
- claude-api / context7 (if unregistered) — reuse positions.
|
||||
|
||||
Add the ml-ai-tooling category as the **seventh** off-phase subcategory (after UI-pool, infrastructure, debug-runtime, architecture-tooling, audit-security — confirm the exact count against the live file). Bump §0 counter; bump the Прил. Н version header.
|
||||
|
||||
- [ ] **Step 3: Add PSR_v1 R10.1 rows**
|
||||
|
||||
Edit `docs/Plugin_stack_rules_v1.md`: add a row per new tool to R10.1, category **ml-ai-tooling** (off-phase) — explicitly *outside* the UI-pool → no R6.0/R6.1 stack-filter, no R14 pipeline (same treatment as `claude-md-management`, architecture-tooling, audit-security). Bump the PSR_v1 version header.
|
||||
|
||||
- [ ] **Step 4: Add the Pravila §13.2 note**
|
||||
|
||||
Edit `docs/Pravila_raboty_Claude_v1_1.md` §13.2: add a one-line **ml-ai-tooling** category note, alongside the existing infrastructure / debug-runtime / architecture-tooling / audit-security notes. Re-read Pravila §0/§13 first to keep section numbering consistent. Bump the Pravila version header.
|
||||
|
||||
- [ ] **Step 5: Update CLAUDE.md via the governed channel**
|
||||
|
||||
Invoke `/claude-md-management:claude-md-improver`. Apply: §3 title count bump, §1 priority-chain row 2b count bump, new §3.3 ml-ai-tooling row(s). The plugin also writes the `docs/CHANGELOG_claude_md.md` entry and bumps §0 cross-ref versions (Tooling / PSR_v1 / Pravila). **Do not** edit `CLAUDE.md` directly (§5 п.10).
|
||||
|
||||
- [ ] **Step 6: Lint + commit**
|
||||
|
||||
```bash
|
||||
npx markdownlint-cli2 "docs/Tooling_v8_3.md" "docs/Plugin_stack_rules_v1.md" "docs/Pravila_raboty_Claude_v1_1.md" "docs/CHANGELOG_claude_md.md"
|
||||
npx cspell --no-progress --no-summary --no-gitignore "docs/Tooling_v8_3.md" "docs/Plugin_stack_rules_v1.md" "docs/Pravila_raboty_Claude_v1_1.md"
|
||||
git add docs/Tooling_v8_3.md docs/Plugin_stack_rules_v1.md docs/Pravila_raboty_Claude_v1_1.md CLAUDE.md docs/CHANGELOG_claude_md.md cspell-words.txt
|
||||
git commit -m "docs(a11): register ml-ai-tooling category — promptfoo/Data Scientist skill/Jupyter MCP (NUM1)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 7: Reflect A11 on the map — close the section
|
||||
|
||||
**Files:** Modify `docs/automation-graph.html`
|
||||
|
||||
- [ ] **Step 1: Read the structures to replicate**
|
||||
|
||||
In `docs/automation-graph.html` read, as templates: a vendored-skill node (`mermaid_skill`), a plugin-skill node, and an MCP node (`mcp_sentry`) across `NODES`, `NODE_DETAILS`/`nd(...)`, `NODE_SECTION`, and the "Паспорт узла" date fields. Record the current node/edge counts from the header and the group-count comments.
|
||||
|
||||
- [ ] **Step 2: Add the 3 A11 nodes**
|
||||
|
||||
Add to `NODES`, replicating the template shapes:
|
||||
|
||||
- `claude_api` — label `claude-api\n(skill)`, skills group.
|
||||
- `promptfoo` — label `promptfoo`, an appropriate tooling group (match how `bin/` CLIs / lefthook tools are grouped — e.g. the group used for gitleaks/lychee-class tools, or a plugins/skills group if no CLI group exists; record the choice).
|
||||
- `data_scientist` — label `Data Scientist\n(skill)`, skills group.
|
||||
|
||||
Add matching `nd(...)` / `NODE_DETAILS` entries (Russian, per the file's convention), Паспорт `since: '2026-05-17'`:
|
||||
|
||||
- `claude_api` — "Скил сборки AI-фич на Anthropic SDK (prompt-кэш). Reuse — раздел A11 опирается также на context7 MCP (доки) и Sentry MCP (LLM-наблюдаемость)."
|
||||
- `promptfoo` — "npm-CLI eval LLM-промптов: ассерты, регрессия, red-team. Запуск вручную/CI — не в хуках (платные вызовы)."
|
||||
- `data_scientist` — "Vendored-скил: классический ML-воркфлоу — выбор алгоритма, feature engineering, оценка модели."
|
||||
|
||||
- [ ] **Step 3: Map the 3 nodes to section A11**
|
||||
|
||||
In `NODE_SECTION` add (a new comment block, after the A6 block):
|
||||
|
||||
```js
|
||||
// A11 ml-ai-tooling 17.05.2026 — раздел «ML / AI-разработка» наполнен
|
||||
claude_api: 'A11', promptfoo: 'A11', data_scientist: 'A11',
|
||||
```
|
||||
|
||||
`A11 «ML / AI-разработка»` goes from 0 → 3 nodes — the section is no longer empty. (No `jupyter_mcp` node — Jupyter MCP is deferred, ML9.)
|
||||
|
||||
- [ ] **Step 4: Update header metrics + group-count comments**
|
||||
|
||||
Bump the node count in the map header/legend by 3. Bump the edge count if Step 2's node details add governing edges (match how the A6 nodes were wired — e.g. an edge to the governing normative node; replicate that pattern, else node-only). Update the `NODE_SECTION` group-count comments (skills, and whatever group `promptfoo` joined).
|
||||
|
||||
- [ ] **Step 5: Smoke-test the map**
|
||||
|
||||
```bash
|
||||
npx stylelint docs/automation-graph.html
|
||||
```
|
||||
|
||||
Open `docs/automation-graph.html` (Playwright MCP or a local `http.server` — quirk 90: `file://` rejected). Expected: 0 JS console errors; the 3 new nodes render; clicking section `A11` highlights all three.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/automation-graph.html
|
||||
git commit -m "feat(map): A11 nodes — closes section «ML / AI-разработка»"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 8: Final regression & branch finish
|
||||
|
||||
**Files:** none modified
|
||||
|
||||
- [ ] **Step 1: Rebase onto latest origin/main (sequencing)**
|
||||
|
||||
```bash
|
||||
git fetch origin
|
||||
git rebase origin/main
|
||||
```
|
||||
|
||||
Expected: a clean rebase (A6/D3/C9 already landed; A11 touched the same shared files — the map, 4 normative docs, the Tooling counter — so resolve any conflict by **re-reading the live file and re-applying the A11 delta**, never blindly). If conflicts are non-trivial → stop, report. Re-run the live-counter read (Task 6 Step 1) if the Tooling counter moved.
|
||||
|
||||
- [ ] **Step 2: Full pre-commit chain**
|
||||
|
||||
```bash
|
||||
npx lefthook run pre-commit
|
||||
```
|
||||
|
||||
Expected: all jobs green — A11 adds **no** lefthook job (job count unchanged vs the Task 1 baseline).
|
||||
|
||||
- [ ] **Step 3: Confirm app code untouched — run the suites**
|
||||
|
||||
A11 changes no `app/` code → suites must match the Task 1 Step 3 baseline:
|
||||
|
||||
```bash
|
||||
cd app && php artisan test --parallel
|
||||
cd .. && npm run test:vue
|
||||
```
|
||||
|
||||
Expected: Pest and Vitest counts unchanged vs the Task 1 baseline (0 regressions). Record exact counts; write out any failure with file:line.
|
||||
|
||||
- [ ] **Step 4: Confirm the economy/ruflo hook chain is intact**
|
||||
|
||||
Economy marker still appears; the Stop verifier still runs; no plugin/skill leaked a `hooks` entry into either `settings.json`. Compare to the Task 1 Step 2 snapshot.
|
||||
|
||||
- [ ] **Step 5: Pre-push checks**
|
||||
|
||||
```bash
|
||||
./bin/gitleaks.exe detect --source . --no-banner --redact
|
||||
./bin/lychee.exe --config .lychee.toml "docs/**/*.md" "*.md"
|
||||
```
|
||||
|
||||
Expected: gitleaks 0 leaks (the promptfoo example holds no key — ML1); lychee 0 broken (new `docs/ml/**/*.md` + `docs/adr/ADR-005-*.md` are scanned — fix or `.lychee.toml`-exclude any link, e.g. the `promptfoo.dev` docs link).
|
||||
|
||||
- [ ] **Step 6: Finish the branch**
|
||||
|
||||
Invoke `superpowers:finishing-a-development-branch` — present the standard options. Do **not** push without an explicit user choice. Push pattern: `git push origin feat/a11-ml-ai-tooling:main`.
|
||||
|
||||
---
|
||||
|
||||
## Deferred Task (NOT in this plan — future, severable)
|
||||
|
||||
**Jupyter MCP install — gated on a trigger.** When a concrete ML model is scoped
|
||||
(a real lead-scoring / lead-quality model with a dataset), run a separate task:
|
||||
|
||||
1. Decide the Python ML environment (native Windows venv vs a YC instance) — an
|
||||
explicit runtime weighing, like the Docker / pg_partman decisions.
|
||||
2. `alpha-substrate-spike-first` — spike Jupyter MCP (it is experimental, Notebook
|
||||
6.x only) before integrating.
|
||||
3. Install `datalayer/jupyter-mcp-server` as the 8th `.mcp.json` server, version-pinned.
|
||||
4. Flip the Tooling registry entry from **pending** to **active**; add a `jupyter_mcp`
|
||||
node to `docs/automation-graph.html` → `NODE_SECTION` A11 (now 4 nodes).
|
||||
5. Re-run the full regression + the conflict re-audit.
|
||||
|
||||
Until then, A11 is fully covered by the 5 installed/reuse positions.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
|
||||
**1. Spec coverage (the six-position toolset, Approach А).** Reuse layer — claude-api / context7 / Sentry documented in `docs/ml/README.md` (Task 4 Step 1), registration audited (Task 1 Step 5) and synced (Task 6). promptfoo — installed (Task 2), seed example (Task 4 Steps 2-3), smoked (Task 5 Step 1). Data Scientist skill — repo resolved (Task 1 Step 4), vendored (Task 3), smoked (Task 5 Step 2). Jupyter MCP — registered pending (Task 6 Step 2), deferred task documented ("Deferred Task"). Section closure: normative (Task 6), map (Task 7), regression/finish (Task 8). Conflict audit: ML1→T2.4+T4.1/3, ML2→T4.1+T6.2, ML3→T3.4, ML4→T4.1+T7.2-3, ML5→T6.2-4, ML6→T2.5+T3.5, ML7→T3.3+T6.2, ML8→T1.5+T6.1-2, ML9→T6.2+T7.3, NUM1→T1.6+T6.1+T8.1. No gaps.
|
||||
|
||||
**2. Placeholder scan.** `#N`/`#N+1`/`#N+2` (Task 6), `<RESOLVED_REPO_URL>`/`<RESOLVED_SKILL_PATH>` (Task 3), and the promptfoo node's map group (Task 7 Step 2) are **runtime-resolved by design** — the live Tooling counter, the Data Scientist skill source repo, and the live map group shapes are not knowable before Task 1 Step 4-6 / reading the 2400-line map, and each carries concrete resolution criteria (the A6/C9/D3 pattern). All file contents shown in full — `docs/ml/README.md`, both promptfoo-example files, ADR-005, the seed `promptfooconfig.yaml`. No "TBD" / "handle edge cases".
|
||||
|
||||
**3. Consistency.** Branch `feat/a11-ml-ai-tooling` consistent T1↔T8. Node ids `claude_api` / `promptfoo` / `data_scientist` consistent T7 Steps 2-3 + the `docs/ml/README.md` table. Category name **ml-ai-tooling** consistent T6 Steps 2-4 + ADR-005. Paths consistent: `.claude/skills/data-scientist/`, `docs/ml/`, `docs/ml/promptfoo-example/`. promptfoo install mode (root `package.json` devDep) consistent T2↔file-structure↔Tooling-entry. Jupyter MCP flagged **deferred/pending** uniformly (Tool Identity, ML9, Task 6 Step 2, Task 7 Step 3, "Deferred Task"). No lefthook job added — consistent with the minimal-conflict goal (ML1).
|
||||
|
||||
---
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
Plan complete and saved to `docs/superpowers/plans/2026-05-17-a11-ml-ai-tooling-integration.md`. Two execution options:
|
||||
|
||||
1. **Subagent-Driven** — fresh subagent per task, two-stage review. *Caveat:* Task 2 (`npx promptfoo`), Task 3 Step 5 + Task 5 Steps 2-3 (`/reload-plugins`, skill invocations) and Task 6 Step 5 (`/claude-md-management`) are main-session-bound — those steps stay with the controller.
|
||||
2. **Inline Execution** — `superpowers:executing-plans`, batch with checkpoints. **Recommended here** — install/config/docs-heavy with many interactive main-session steps (the A6/C9/D3 pattern).
|
||||
|
||||
**Sequencing reminder:** A11 rebases onto `origin/main` after A6 / D3 / C9 land (Task 8 Step 1). One open item before execution: execution method — **1** (Subagent-Driven) or **2** (Inline, recommended here).
|
||||
@@ -0,0 +1,588 @@
|
||||
# C9 Project-Management Tooling Integration Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Populate the empty `C9 «Управление проектами»` map section with a conflict-minimal project-management toolset — reuse the existing GitHub MCP (Projects v2) + Superpowers planning skills, vendor **CCPM** (PRD→epic→issue→code traceability), and conditionally install the Anthropic **product-management** plugin — so C9 becomes a working playbook.
|
||||
|
||||
**Architecture:** C9 is an **empty** functional section — `NODE_SECTION` in `docs/automation-graph.html` tags zero nodes `C9`. Variant А (chosen 2026-05-17): a **reuse core** (GitHub MCP `projects` toolset + `issue`/`sub_issue` tools, Superpowers `writing-plans`/`executing-plans`/`subagent-driven-development`, the `q-item-add` skill + `Открытые_вопросы` registry, ruflo task layer) plus **one verified-clean install** — CCPM, vendored as a standalone skill into `.claude/skills/ccpm/` (no plugin, no marketplace, no hooks — the A6 mermaid pattern). The Anthropic **product-management** plugin is a **conditional** add (Task 5, severable) — installed only if Task 1 confirms Claude Code installability. The three conflict-heavy candidates (`task-tracker-plugin` 🔴 hook collision, `claude-kanban` 🔴 lefthook + CLAUDE.md collision, `pm-skills` sprawl) are **dropped**. All C9 tools are non-UI → **project-management** category, outside the PSR_v1 UI-pool. C9 artifacts live in `docs/projects/`; CCPM's PRD/epic store lives under `.claude/prds/` and `.claude/epics/` (CCPM's hardcoded convention).
|
||||
|
||||
**Tech Stack:** CCPM (`automazeio/ccpm`, standalone skill, MIT); the official GitHub MCP Server (`github/github-mcp-server`, already installed — `projects` toolset enabled here); Anthropic **product-management** plugin (conditional); adr-kit v0.13.1 (reused from the A6 plan, if landed); project normative docs; `docs/automation-graph.html` (vis.js).
|
||||
|
||||
**Sequencing (locked 2026-05-17):** the A6 plan (`2026-05-17-a6-architecture-tooling-integration.md`) and the D3 plan (`2026-05-17-d3-audit-risk-tooling-integration.md`) run to completion and push **first**, in that order; C9 Task 1 then forks from the updated `origin/main`. Rationale: all three epics touch shared files (the map, 4 normative docs, the Tooling counter). C9's seed ADR (Task 4) reuses A6's adr-kit + `docs/adr/ADR-000`. Run strictly sequentially, never interleaved. C9 numbers are runtime-resolved (NUM1) — never hard-coded before reading the live counter.
|
||||
|
||||
---
|
||||
|
||||
## Tool Identity (verified 2026-05-17 via WebFetch/WebSearch)
|
||||
|
||||
| # | Tool | Install mode | Source / License | Hooks? |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **CCPM** (Claude Code PM) — `skill/ccpm/`: `SKILL.md` + `references/` (`plan.md`, `structure.md`, `sync.md`, `execute.md`, `track.md`, `conventions.md`) + `references/scripts/` (14 bash scripts: `status.sh`, `standup.sh`, `epic-list.sh`, `search.sh`, …). PRD→epic→GitHub-issue→code, 5 phases. | Standalone skill — vendored copy into `.claude/skills/ccpm/` (no plugin, no marketplace) | GitHub `automazeio/ccpm`, **MIT**; a preserved `v1` branch holds the original system | None disclosed (skills-only; "activates when the agent detects PM intent") — **verify on install** |
|
||||
| 2 | **product-management** (Anthropic) — `/write-spec`, `/roadmap-update`, `/stakeholder-update`, `/synthesize-research`, `/competitive-brief`, `/metrics-review` | Marketplace plugin (Anthropic-verified) — **conditional** (Task 5) | Anthropic; marketplace name "Product Management" | Unknown — **verify on install** (expected none — skills/commands plugin) |
|
||||
| — | **GitHub MCP `projects` toolset** (`projects_get` / `projects_list` / `projects_write`) + `issue_read`/`issue_write`/`sub_issue_write` | **Reuse** — already-installed official server; enable the `projects` toolset | `github/github-mcp-server`, official | n/a (MCP server, no CC lifecycle hooks) |
|
||||
|
||||
**Verification status:** CCPM — repo, MIT, skill structure, no-`install.sh` (manual symlink/vendor) confirmed via WebFetch. product-management — Anthropic publisher + command list confirmed; **Claude Code (vs Cowork) installability NOT confirmed** — Task 1 Step 5 resolves it. GitHub MCP `projects` toolset — confirmed to exist in the official server; **NOT currently exposed in this project** (the `mcp__github__*` tool set lacks `projects_*`) → Task 2 enables it.
|
||||
|
||||
**Dropped (with reason — no tasks):**
|
||||
|
||||
- **`task-tracker-plugin`** (`victor-software-house`) — 🔴 registers 5 lifecycle hooks incl. its own `Stop` + `SessionStart`, colliding with the economy/skill-discipline/ruflo hook stack. Compaction context-loss is already mitigated by the ruflo recall hook + memory files.
|
||||
- **`claude-kanban`** (`alessiocol`) — 🔴 registers git pre-commit hooks (collides with lefthook) and writes its own `CLAUDE.md` (violates CLAUDE.md §5 п.10); 5 commits / no releases (very high bus-factor). Sprint-board need is met by GitHub Projects v2.
|
||||
- **`pm-skills`** (`phuryn`) — 100+ skills = sprawl; a material library, not a решатель.
|
||||
- **Separate GitHub Projects v2 MCP** (Arclio / kunwarVivek) — redundant with the official server's `projects` toolset (§5 п.6).
|
||||
- **`feature-dev`** (Anthropic official) — 7-phase feature workflow + code-explorer/architect/reviewer agents overlap Superpowers (brainstorming→writing-plans→subagent-driven-development) (§5 п.6).
|
||||
|
||||
---
|
||||
|
||||
## Design Decisions & Conflict Audit
|
||||
|
||||
Pattern follows the K1–K8 / AK1–CC1 audits used for claude-mem, the A6 plan, and the D3 plan. Verified against the CCPM repo, the product-management plugin page, project `.claude/settings.json`, `~/.claude/settings.json`, `.mcp.json`, `lefthook.yml`, `cspell.json`, `.markdownlintignore`, and the A6/D3 plans.
|
||||
|
||||
| # | Tool | Sev | Conflict | Resolution (locked) |
|
||||
|---|---|---|---|---|
|
||||
| CP1 | CCPM | 🟡 | Vendored `.claude/skills/ccpm/**/*.md` (third-party English skill files) gets caught by the cspell + markdownlint pre-commit jobs. | Add `.claude/skills/ccpm/**` to `cspell.json` `ignorePaths` and `.markdownlintignore` (Task 3). The project's own skills (`q-item-add`, `rls-check`, `regression`, `mermaid`) stay linted. Same as A6 MK1. |
|
||||
| CP2 | CCPM | 🟡 | CCPM "activates automatically when the agent detects PM intent" — could collide with Superpowers `brainstorming`/`writing-plans` auto-activation and the §12.2 task-map. | Boundary in `docs/projects/README.md` (Task 4): **CCPM** = the PRD→epic→GitHub-issue→code *traceability* layer (explicit `/pm` flow); **Superpowers `writing-plans`** = authoring execution plan-files in `docs/superpowers/plans/`. CCPM's auto-intent is advisory; the §12.2 map is **unchanged** — CCPM is not added to it. |
|
||||
| CP3 | CCPM | 🟡 | CCPM uses GitHub Issues as source-of-truth; the project currently barely uses issues (FF-push pattern, `git push origin <branch>:main`). | This is the **deliberate architecture decision of Variant А** — adopt GitHub-issue-backed PM. It is an architectural choice, not a technical clash. Documented as an ADR (Task 4 Step 4, adr-kit from A6). Issues created via the reused GitHub MCP `issue_write` / `sub_issue_write`. |
|
||||
| CP4 | CCPM | 🟢 | Lifecycle-hook collision with the 6 economy + skill-discipline + 2 ruflo hooks. | Expected none — CCPM is skills-only. Re-verify Task 1 Step 4 + Task 3 Step 4. If CCPM ships a `hooks` block → **stop** and re-audit. |
|
||||
| CP5 | CCPM | 🟡 | CCPM's scripts hard-code `.claude/prds/` and `.claude/epics/` as the PRD/epic store — `.claude/` is config, not docs; the project keeps docs under `docs/`. | Accept CCPM's hard-coded store (do not patch its 14 scripts — YAGNI). `.claude/prds/` + `.claude/epics/` are committed project content and **stay linted** (NOT covered by the CP1 skill-only lint-ignore). Documented in `docs/projects/README.md`. |
|
||||
| CP6 | CCPM | 🟢 | 14 bash scripts (`status.sh`, `standup.sh`, …) on native Windows. | None — the project already runs bash (`lefthook`, `gitleaks`, `bin/*.exe`) via Git Bash / the Bash tool. Smoke-tested in Task 6 Step 2. |
|
||||
| PG1 | product-mgmt | 🟡 | The product-management plugin's page says "Available in Claude Cowork" — Claude **Code** installability is unconfirmed. Installing an uninstallable plugin wastes the task. | Task 1 Step 5 fact-checks the `/plugin marketplace add` + `/plugin install` strings / a backing GitHub marketplace repo. Task 5 installs **only if** Code-installable; otherwise **defer** with a documented fallback (reuse layer authors specs via `writing-plans`; roadmap via the registry + map WISHLIST). Same default-defer shape as D3 #5. |
|
||||
| PG2 | product-mgmt | 🟢 | Could the plugin register CC lifecycle hooks? | Verify on install (Task 5 Step 2). Skills/commands plugins register none; if it does → stop and re-audit. |
|
||||
| PG3 | product-mgmt | 🟡 | `/write-spec` (PRD) overlaps the CCPM PRD phase (§5 п.6). | Boundary (Task 7 Tooling entry): CCPM PRD = the *engineering* epic→issue→code traceability artifact; product-management `/write-spec` = the *product-strategy* PRD (problem→spec, roadmap-aligned). Different altitude. Moot if PG1 defers product-management. |
|
||||
| GH1 | GitHub MCP | 🟢 | Enabling the `projects` toolset = a config + permissions change on an already-installed official server. | Task 2: enable `projects` in the github server's toolset config in `.mcp.json`; add `mcp__github__projects_get/list/write` to `~/.claude/settings.json` `permissions.allow`. No new install. |
|
||||
| GH2 | GitHub MCP | 🟡 | A separate GitHub Projects v2 MCP (Arclio etc.) would duplicate the official `projects` toolset (§5 п.6). | **Dropped** — not installed. Documented here, no task. |
|
||||
| REU1 | reuse layer | 🟢 | Re-tagging existing nodes (`sk_wplans`, `mcp_gh`, `sk_qitem`) to C9 would *empty* their current sections — `NODE_SECTION` is 1-node→1-section. | Reuse nodes **stay** in their sections; C9 gets its **own** new nodes (CCPM, product-management). The reuse coverage is documented in `docs/projects/README.md` and noted in the new nodes' `NODE_DETAILS` (Task 8). Same as A6/D3 (they added new nodes, did not re-tag). |
|
||||
| CC1 | all | 🟡 | Bus-factor — CCPM is a community project (`automazeio`, pre-`v1`-tagged); product-management is Anthropic (low risk). | CCPM is **vendored** → immune to upstream loss (like A6's mermaid). product-management stays a marketplace plugin (cache-pinned). Noted in the Tooling entry. No alpha-substrate spike needed — neither has a known-broken core (unlike ruflo K7). |
|
||||
| NUM1 | normative sync | 🟡 | The A6 plan claims Tooling slots #36-#38; the D3 plan claims the next ≥2 after A6. C9 must not collide. | Task 1 Step 6 + Task 7 Step 1 read the **live** `docs/Tooling_v8_3.md` Прил. Н §0 counter and assign C9's number(s) sequentially after whatever is current. Never hard-code a number before reading. |
|
||||
|
||||
**Severable scope.** Core C9 = Tasks 1-4 + 6-9 (reuse enablement + CCPM vendored + normative + map + finish) — already populates the section. **Task 5** (product-management) is severable + conditional (PG1). Unlike A6, C9 adds **no lefthook job** (no commit-pipeline gate) — fewer conflicts by design. **Selected 2026-05-17 (Variant А): core + conditional Task 5.**
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| File | Created / Modified | Responsibility |
|
||||
|---|---|---|
|
||||
| `.claude/skills/ccpm/` | Create (vendored) | The CCPM skill — `SKILL.md` + `references/` + `references/scripts/` |
|
||||
| `.claude/prds/.gitkeep` | Create | CCPM PRD store (CCPM's hard-coded convention — CP5) |
|
||||
| `.claude/epics/.gitkeep` | Create | CCPM epic/task store (CCPM's hard-coded convention — CP5) |
|
||||
| `docs/projects/` | Create dir | C9 home — the project-management playbook & convention |
|
||||
| `docs/projects/README.md` | Create | The PM convention: GitHub-Projects-v2-as-sprint-board; CCPM vs `writing-plans` vs registry vs ADR boundaries; reuse-layer map |
|
||||
| `docs/adr/ADR-004-project-management-tooling.md` | Create (conditional — adr-kit present, A6 landed) | Seed ADR documenting the C9 tooling + GitHub-issue-backed-PM decision (CP3) |
|
||||
| `.mcp.json` | Modify | Enable the `projects` toolset on the `github` server (GH1) |
|
||||
| `~/.claude/settings.json` | Modify | `permissions.allow` += `mcp__github__projects_*`; `enabledPlugins` += product-management (conditional); `extraKnownMarketplaces` += 1 (conditional) |
|
||||
| `cspell.json` | Modify | `ignorePaths` += `.claude/skills/ccpm/**` (CP1) |
|
||||
| `.markdownlintignore` | Modify | += `.claude/skills/ccpm/` (CP1) |
|
||||
| `cspell-words.txt` | Modify (conditional) | New PM vocabulary |
|
||||
| `docs/Tooling_v8_3.md` | Modify | Прил. Н — new project-management subsection(s) + §0 counter bump |
|
||||
| `docs/Plugin_stack_rules_v1.md` | Modify | R10.1 — new project-management rows |
|
||||
| `docs/Pravila_raboty_Claude_v1_1.md` | Modify | §13.2 — project-management category note |
|
||||
| `CLAUDE.md` | Modify (**via claude-md-management only**) | §3 title count, §1 row 2b count, new §3.3 project-management rows |
|
||||
| `docs/CHANGELOG_claude_md.md` | Modify | CLAUDE.md version-bump entry |
|
||||
| `docs/automation-graph.html` | Modify | New C9 nodes → `NODE_SECTION` C9; header metrics |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: Pre-flight — baseline, branch, snapshot, fact-check
|
||||
|
||||
**Files:** none modified (read-only) except a new branch
|
||||
|
||||
- [ ] **Step 1: Confirm tree state and create the working branch**
|
||||
|
||||
```bash
|
||||
cd "c:/моя/проекты/портал crm/Документация"
|
||||
git status --short
|
||||
git rev-parse --short HEAD
|
||||
git fetch origin && git checkout -b feat/c9-project-management-tooling origin/main
|
||||
```
|
||||
|
||||
Expected: record `origin/main` HEAD SHA as the regression baseline; new branch `feat/c9-project-management-tooling` created off it. (Push pattern at the end: `git push origin feat/c9-project-management-tooling:main`.)
|
||||
|
||||
- [ ] **Step 2: Snapshot the hook chain**
|
||||
|
||||
Read `.claude/settings.json`, `.claude/settings.local.json` (if present), and `~/.claude/settings.json`. Record every hook on `SessionStart`, `UserPromptSubmit`, `PreToolUse`, `PostToolUse`, `PreCompact`, `PostCompact`, `Stop`. This is the CP4/PG2 baseline — Tasks 3 and 5 compare against it.
|
||||
Expected (`~/.claude/settings.json`): SessionStart economy-self-check; PreToolUse skill-marker/skill-check/economy-state-guard; UserPromptSubmit economy-mode; PostCompact economy-postcompact; Stop economy-verifier (Sonnet). Project `.claude/settings.json`: ruflo-recall + ruflo-queen (UserPromptSubmit), CLAUDE.md-warn (PreToolUse), markdownlint-fix + schema-CHANGELOG-reminder (PostToolUse).
|
||||
|
||||
- [ ] **Step 3: Baseline regression**
|
||||
|
||||
```
|
||||
/regression quick
|
||||
```
|
||||
|
||||
Expected: GREEN. Record the current Pest / Vitest counts from the last green run (memory `project_state.md`). C9 touches no `app/` code → the final run (Task 9) must match.
|
||||
|
||||
- [ ] **Step 4: Fact-check CCPM**
|
||||
|
||||
Open `https://github.com/automazeio/ccpm` and confirm assumptions still hold:
|
||||
|
||||
- Skill structure: `skill/ccpm/SKILL.md` + `skill/ccpm/references/` + `skill/ccpm/references/scripts/` (~14 bash scripts).
|
||||
- MIT license.
|
||||
- No `settings.json` `hooks` block / no Claude Code lifecycle hook registration.
|
||||
- Integration is manual (symlink / copy) — no `install.sh` required.
|
||||
|
||||
If CCPM now registers CC lifecycle hooks → **stop**, re-audit CP4 before continuing.
|
||||
|
||||
- [ ] **Step 5: Fact-check product-management Claude Code installability (PG1)**
|
||||
|
||||
Determine whether the Anthropic product-management plugin is installable in Claude **Code** (not only Claude Cowork):
|
||||
|
||||
- WebFetch `https://claude.com/plugins/product-management` for an explicit `/plugin marketplace add …` + `/plugin install …` instruction.
|
||||
- WebSearch for a backing GitHub marketplace repo (e.g. in `anthropics/claude-plugins-official` `marketplace.json`, or a dedicated repo).
|
||||
|
||||
Record the verdict: **product-management Code-installable? yes/no** + the exact marketplace + install strings if yes. This drives Task 5 (conditional) and Task 8 (whether a `product_mgmt` node is added).
|
||||
|
||||
- [ ] **Step 6: Check A6/D3 landed + read the live Tooling counter (NUM1)**
|
||||
|
||||
```bash
|
||||
git log --oneline origin/main | grep -iE "adr-kit|architecture-patterns|mermaid|trail of bits|security guidance" | head
|
||||
ls ~/.claude/plugins/cache/ | grep -iE "adr-kit|architecture"
|
||||
```
|
||||
|
||||
Read `docs/Tooling_v8_3.md` Прил. Н §0 — record the **live** tool counter. Record: **A6 landed?** yes/no (drives Task 4's conditional ADR-004) and the counter value (drives Task 7 numbering).
|
||||
|
||||
No repo files changed → no commit.
|
||||
|
||||
---
|
||||
|
||||
## Task 2: Enable the GitHub MCP `projects` toolset (reuse — GH1)
|
||||
|
||||
**Files:** Modify `.mcp.json`; Modify `~/.claude/settings.json` (the `Edit` triggers the `ask` permission — expected)
|
||||
|
||||
- [ ] **Step 1: Inspect the github server config**
|
||||
|
||||
Read `.mcp.json` — locate the `github` server block. Identify how toolsets are configured (the official server gates toolsets via a `--toolsets` arg or a `GITHUB_TOOLSETS` env var; the hosted server may use a query param). Record the current toolset value.
|
||||
|
||||
- [ ] **Step 2: Enable the `projects` toolset**
|
||||
|
||||
Edit `.mcp.json` — add `projects` to the github server's enabled toolsets (alongside `issues`, `pull_requests`, `repos`, etc.). If toolsets were previously unset (server default), set an explicit list that **includes the previously-working toolsets plus `projects`** — do not narrow the surface. Example (adjust to the actual config shape):
|
||||
|
||||
```json
|
||||
"github": {
|
||||
"...": "...",
|
||||
"env": { "GITHUB_TOOLSETS": "repos,issues,pull_requests,projects" }
|
||||
}
|
||||
```
|
||||
|
||||
- [ ] **Step 3: Add the `projects` tool permissions**
|
||||
|
||||
Edit `~/.claude/settings.json` — append to `permissions.allow`:
|
||||
|
||||
```
|
||||
"mcp__github__projects_get",
|
||||
"mcp__github__projects_list",
|
||||
"mcp__github__projects_write"
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Reload and verify**
|
||||
|
||||
```
|
||||
/reload-plugins
|
||||
```
|
||||
|
||||
Confirm `mcp__github__projects_get`, `mcp__github__projects_list`, `mcp__github__projects_write` are now available MCP tools. If they are still absent → the toolset value or the server version is wrong; re-inspect Step 1-2. Confirm no `settings.json` `hooks` block changed.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add .mcp.json
|
||||
git commit -m "feat(c9): enable GitHub MCP projects toolset for Projects v2 (GH1)"
|
||||
```
|
||||
|
||||
(`~/.claude/settings.json` is outside the repo — not committed.)
|
||||
|
||||
---
|
||||
|
||||
## Task 3: Vendor the CCPM skill (standalone, vendored — CP1/CP4)
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.claude/skills/ccpm/` (vendored skill tree)
|
||||
- Modify: `cspell.json`, `.markdownlintignore`
|
||||
|
||||
- [ ] **Step 1: Clone the source to a temp location**
|
||||
|
||||
```bash
|
||||
git clone --depth 1 https://github.com/automazeio/ccpm.git /tmp/ccpm-src
|
||||
ls -R /tmp/ccpm-src/skill/ccpm/
|
||||
```
|
||||
|
||||
Expected: `SKILL.md` + `references/` (`plan.md`, `structure.md`, `sync.md`, `execute.md`, `track.md`, `conventions.md`) + `references/scripts/` (~14 `.sh` files).
|
||||
|
||||
- [ ] **Step 2: Verify CCPM ships no Claude Code hooks (CP4)**
|
||||
|
||||
```bash
|
||||
grep -rIl "hooks" /tmp/ccpm-src --include="*.json" || echo "no hooks json"
|
||||
ls /tmp/ccpm-src/.claude/ 2>/dev/null || echo "no .claude config dir"
|
||||
```
|
||||
|
||||
Expected: no `settings.json` with a `hooks` block. If CCPM ships hooks → **stop**, re-audit CP4.
|
||||
|
||||
- [ ] **Step 3: Vendor the skill into the project**
|
||||
|
||||
```bash
|
||||
mkdir -p ".claude/skills/ccpm"
|
||||
cp -r /tmp/ccpm-src/skill/ccpm/. ".claude/skills/ccpm/"
|
||||
ls -R ".claude/skills/ccpm/"
|
||||
rm -rf /tmp/ccpm-src
|
||||
```
|
||||
|
||||
Expected: `.claude/skills/ccpm/SKILL.md` + `references/**` present. (Vendoring — not a submodule — keeps it on Windows+Cyrillic paths and immune to upstream loss, CC1.)
|
||||
|
||||
- [ ] **Step 4: Exclude the vendored skill from the doc-lint chain (CP1)**
|
||||
|
||||
Edit `.markdownlintignore` — append:
|
||||
|
||||
```
|
||||
.claude/skills/ccpm/
|
||||
```
|
||||
|
||||
Edit `cspell.json` — add `.claude/skills/ccpm/**` to the `ignorePaths` array. Do **not** ignore `.claude/skills/` wholesale — `q-item-add`, `rls-check`, `regression`, `mermaid` stay linted.
|
||||
|
||||
- [ ] **Step 5: Reload and verify the skill is discoverable**
|
||||
|
||||
```
|
||||
/reload-plugins
|
||||
```
|
||||
|
||||
Confirm a `ccpm` skill is now listed among available skills (project `.claude/skills/` is auto-discovered, like the other project skills). Confirm neither `settings.json` `hooks` block changed (CP4).
|
||||
|
||||
- [ ] **Step 6: Verify lint exclusion works, then commit**
|
||||
|
||||
```bash
|
||||
git add .claude/skills/ccpm/ cspell.json .markdownlintignore
|
||||
npx lefthook run pre-commit
|
||||
```
|
||||
|
||||
Expected: cspell + markdownlint jobs do NOT report errors from `.claude/skills/ccpm/**`; all 8 jobs green.
|
||||
|
||||
```bash
|
||||
git commit -m "feat(c9): vendor CCPM skill into .claude/skills + lint-ignore (CP1)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: CCPM bootstrap + the C9 home (CP3 / CP5)
|
||||
|
||||
**Files:**
|
||||
|
||||
- Create: `.claude/prds/.gitkeep`, `.claude/epics/.gitkeep`
|
||||
- Create: `docs/projects/README.md`
|
||||
- Create (conditional — A6 landed): `docs/adr/ADR-004-project-management-tooling.md`
|
||||
- Modify (conditional): `cspell-words.txt`
|
||||
|
||||
- [ ] **Step 1: Create the CCPM store directories**
|
||||
|
||||
```bash
|
||||
mkdir -p ".claude/prds" ".claude/epics"
|
||||
echo "# CCPM PRD store — see docs/projects/README.md" > ".claude/prds/.gitkeep"
|
||||
echo "# CCPM epic/task store — see docs/projects/README.md" > ".claude/epics/.gitkeep"
|
||||
```
|
||||
|
||||
(CCPM hard-codes these paths — CP5. `.gitkeep` keeps the empty dirs tracked.)
|
||||
|
||||
- [ ] **Step 2: Create the C9 home + the PM convention**
|
||||
|
||||
```bash
|
||||
mkdir -p "docs/projects"
|
||||
```
|
||||
|
||||
Create `docs/projects/README.md`:
|
||||
|
||||
```markdown
|
||||
# docs/projects — project-management playbook (map section C9)
|
||||
|
||||
Home of the `C9 «Управление проектами»` section. Defines how the Лидерра
|
||||
development project is planned, tracked, and reported.
|
||||
|
||||
## Toolset
|
||||
|
||||
- **CCPM** (`.claude/skills/ccpm/`) — the PRD→epic→GitHub-issue→code traceability
|
||||
layer. PRDs live in `.claude/prds/`, epics/tasks in `.claude/epics/<feature>/`.
|
||||
Invoked via the `/pm` flow / the `ccpm` skill.
|
||||
- **GitHub MCP** — issues, sub-issues (epic = parent issue, task = sub-issue),
|
||||
and **Projects v2** boards used as the sprint/iteration board.
|
||||
- **Superpowers `writing-plans` / `executing-plans` / `subagent-driven-development`**
|
||||
— authoring and running execution plan-files in `docs/superpowers/plans/`.
|
||||
- **`q-item-add` skill + `docs/Открытые_вопросы_v8_3.md`** — the open-question
|
||||
registry (Б-/CTO-/Ю-/Диз-/DO-/OPEN- codes).
|
||||
- **product-management plugin** (if installed — see Task 5) — PRD/roadmap/metrics
|
||||
product-strategy ceremonies.
|
||||
|
||||
## Boundaries (which tool for which artifact)
|
||||
|
||||
- **Open product/business/legal question** → `Открытые_вопросы` registry. Not an
|
||||
epic, not an ADR — it has no resolution yet.
|
||||
- **A closed technical/architecture decision** → `docs/adr/` (adr-kit, A6).
|
||||
- **A feature to build, with engineering traceability** → a CCPM PRD → epic →
|
||||
GitHub issues.
|
||||
- **The step-by-step execution plan for that epic** → a `docs/superpowers/plans/`
|
||||
file (Superpowers `writing-plans`). CCPM tracks *what & status*; the plan
|
||||
file tracks *how, task-by-task*.
|
||||
- **Product-strategy spec / roadmap** → product-management `/write-spec` /
|
||||
`/roadmap-update` (if installed); else a registry/WISHLIST entry.
|
||||
|
||||
## Workflow
|
||||
|
||||
1. Idea → CCPM PRD (`.claude/prds/`).
|
||||
2. PRD → epic + GitHub issues (CCPM `sync`, via GitHub MCP `issue_write` /
|
||||
`sub_issue_write`).
|
||||
3. Epic → a `docs/superpowers/plans/` plan-file → execution.
|
||||
4. Status → CCPM `status.sh` / `standup.sh`; the GitHub Projects v2 board is the
|
||||
sprint view.
|
||||
```
|
||||
|
||||
Adjust the bullet list to whatever Task 5 resolves for product-management.
|
||||
|
||||
- [ ] **Step 3: Decide on the conditional ADR (uses Task 1 Step 6 result)**
|
||||
|
||||
If **A6 landed** (`docs/adr/ADR-000-adr-process.md` exists, adr-kit present) → do Step 4. If A6 has **not** landed → skip Step 4, and add a line to `docs/projects/README.md` noting "the C9 tooling decision will be recorded as an ADR once adr-kit (A6) lands". Record the branch taken.
|
||||
|
||||
- [ ] **Step 4: Write ADR-004 (conditional)**
|
||||
|
||||
Create `docs/adr/ADR-004-project-management-tooling.md`:
|
||||
|
||||
```markdown
|
||||
# ADR-004: Project-management tooling (C9)
|
||||
|
||||
- **Status:** Accepted
|
||||
- **Date:** 2026-05-17
|
||||
- **Deciders:** Дмитрий
|
||||
|
||||
## Context
|
||||
The `C9 «Управление проектами»` map section had zero tooling. Planning was done
|
||||
ad-hoc via `docs/superpowers/plans/` files, the `Открытые_вопросы` registry, and
|
||||
sprint notes in memory. GitHub Issues were barely used (FF-push workflow).
|
||||
|
||||
## Decision
|
||||
- Project management adopts a **GitHub-issue-backed** model: CCPM
|
||||
(vendored skill) drives PRD→epic→issue→code with traceability; epics are
|
||||
parent issues, tasks are sub-issues.
|
||||
- The **GitHub Projects v2** board (official GitHub MCP `projects` toolset) is
|
||||
the sprint/iteration board.
|
||||
- Execution plans stay as `docs/superpowers/plans/` files (Superpowers).
|
||||
- The `Открытые_вопросы` registry remains the home of *open* questions; an ADR
|
||||
records *closed* decisions; CCPM tracks *features in flight*.
|
||||
- product-management (Anthropic) is added only if Claude-Code-installable.
|
||||
|
||||
## Consequences
|
||||
- Positive: C9 populated; planning traceable; sprints visible on a board.
|
||||
- Risk: CCPM is third-party (bus-factor) — mitigated by vendoring.
|
||||
- Risk: a workflow shift toward GitHub Issues — accepted, this is the decision.
|
||||
|
||||
## Enforcement
|
||||
None — C9 tools are advisory; verified by use and code review.
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Lint + commit**
|
||||
|
||||
```bash
|
||||
npx markdownlint-cli2 "docs/projects/*.md" "docs/adr/ADR-004-*.md"
|
||||
npx cspell --no-progress --no-summary --no-gitignore "docs/projects/*.md" "docs/adr/ADR-004-*.md"
|
||||
```
|
||||
|
||||
Add flagged valid terms (`CCPM`, `Лидерра`, `WISHLIST`, etc.) to `cspell-words.txt`. Then:
|
||||
|
||||
```bash
|
||||
git add docs/projects/ .claude/prds/ .claude/epics/ cspell-words.txt
|
||||
git add docs/adr/ADR-004-*.md # only if Step 4 ran
|
||||
git commit -m "feat(c9): bootstrap docs/projects + CCPM store + ADR-004"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: product-management plugin — conditional install (PG1 / PG2) — *severable*
|
||||
|
||||
**Files:** Modify `~/.claude/settings.json`. No repo file changed.
|
||||
|
||||
> Run this task **only if Task 1 Step 5 confirmed Claude Code installability**. Otherwise skip — append to `docs/projects/README.md` a line: "product-management deferred — not Claude-Code-installable as of 2026-05-17; PRD/roadmap covered by `writing-plans` + the registry/WISHLIST" — and treat Task 5 as deferred for Tasks 7-8.
|
||||
|
||||
- [ ] **Step 1: Install the plugin**
|
||||
|
||||
Run the exact strings confirmed in Task 1 Step 5, e.g.:
|
||||
|
||||
```
|
||||
/plugin marketplace add <anthropic-marketplace>
|
||||
/plugin install product-management@<anthropic-marketplace>
|
||||
/reload-plugins
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Verify the plugin + NO lifecycle hooks (PG2)**
|
||||
|
||||
Read `~/.claude/settings.json` — `enabledPlugins` contains `product-management…: true`. Read the `hooks` block of `~/.claude/settings.json` AND project `.claude/settings.json` — both **unchanged** vs the Task 1 Step 2 snapshot. If product-management injected a `hooks` entry → stop and re-audit PG2.
|
||||
|
||||
- [ ] **Step 3: Smoke-test a command**
|
||||
|
||||
Invoke `/write-spec` (or `/roadmap-update`) on a trivial sample. Expected: it runs and produces a structured PRD/roadmap artifact. Functional smoke — no file output required.
|
||||
|
||||
- [ ] **Step 4: Confirm the economy/ruflo chain intact**
|
||||
|
||||
Submit a trivial prompt; the economy marker still appears, no hook errors. No repo files changed in Task 5 → no commit.
|
||||
|
||||
---
|
||||
|
||||
## Task 6: Smoke-test CCPM + close out
|
||||
|
||||
**Files:** none modified
|
||||
|
||||
- [ ] **Step 1: Smoke-test the CCPM skill**
|
||||
|
||||
Invoke the `ccpm` skill with a trivial PM intent (e.g. "draft a PRD for a sample feature"). Expected: the skill loads, `SKILL.md` routes intent, a PRD-shaped artifact is produced under `.claude/prds/` (or proposed). Do **not** sync to real GitHub issues — functional smoke only.
|
||||
|
||||
- [ ] **Step 2: Smoke-test a CCPM bash script on Windows (CP6)**
|
||||
|
||||
```bash
|
||||
bash .claude/skills/ccpm/references/scripts/status.sh
|
||||
```
|
||||
|
||||
Expected: the script runs under Git Bash / the Bash tool and prints a status summary (empty store is fine). If it fails on a Windows path / CRLF issue → record it; the script set is advisory, not commit-critical — note in `docs/projects/README.md` and continue.
|
||||
|
||||
- [ ] **Step 3: Confirm the hook chain is intact**
|
||||
|
||||
Economy marker still appears; the Stop verifier still runs; ruflo + CLAUDE.md-warn hooks fire. No plugin/skill leaked a `hooks` entry. No commit (no files changed).
|
||||
|
||||
---
|
||||
|
||||
## Task 7: Normative registry sync (CP / PG / CC / NUM1)
|
||||
|
||||
**Files:** Modify `docs/Tooling_v8_3.md`, `docs/Plugin_stack_rules_v1.md`, `docs/Pravila_raboty_Claude_v1_1.md`, `CLAUDE.md`, `docs/CHANGELOG_claude_md.md`
|
||||
|
||||
- [ ] **Step 1: Read the registry homes + the live counter (NUM1)**
|
||||
|
||||
Read for exact insertion points and the **current** counter: `docs/Tooling_v8_3.md` Прил. Н §0 + the last `§4.x` subsection; `docs/Plugin_stack_rules_v1.md` R10.1; `docs/Pravila_raboty_Claude_v1_1.md` §13.2. Assign C9's number(s) sequentially from `counter + 1` — **after** any A6/D3 entries already present. Record `#N` (CCPM) and, if Task 5 ran, `#N+1` (product-management).
|
||||
|
||||
- [ ] **Step 2: Add the Tooling Прил. Н project-management subsection(s)**
|
||||
|
||||
Edit `docs/Tooling_v8_3.md`: add a subsection for `#N CCPM` (and `#N+1 product-management` if installed), category **project-management** (off-phase). Per tool record: CCPM (GitHub `automazeio/ccpm` MIT, **vendored** standalone skill in `.claude/skills/ccpm/`, no hooks; GitHub-issue-backed traceability — CP3; PRD/epic store in `.claude/prds`/`.claude/epics` — CP5; boundary vs `writing-plans` — CP2); product-management (Anthropic-verified marketplace plugin; boundary vs CCPM PRD — PG3) — or, if deferred, a one-line "deferred — not Claude-Code-installable" note instead. Also note the GitHub MCP `projects` toolset reuse (no new slot — GitHub MCP is already #3). Add the bus-factor note (CC1). Bump §0 counter and the Прил. Н version header.
|
||||
|
||||
- [ ] **Step 3: Add PSR_v1 R10.1 rows**
|
||||
|
||||
Edit `docs/Plugin_stack_rules_v1.md`: add a CCPM row (and product-management row if installed) to R10.1, category **project-management** (off-phase) — explicitly *outside* the UI-pool → no R6.0/R6.1 stack-filter, no R14 pipeline (same treatment as `claude-md-management`, the A6 architecture-tooling, and the D3 audit-security categories). Bump the PSR_v1 version header.
|
||||
|
||||
- [ ] **Step 4: Add the Pravila §13.2 note**
|
||||
|
||||
Edit `docs/Pravila_raboty_Claude_v1_1.md` §13.2: add a one-line **project-management** category note covering CCPM (+ product-management if installed), alongside the existing infrastructure / debug-runtime / architecture-tooling / audit-security notes. Re-read Pravila §0/§13 first to keep section numbering consistent. Bump the Pravila version header.
|
||||
|
||||
- [ ] **Step 5: Update CLAUDE.md via the governed channel**
|
||||
|
||||
Invoke `/claude-md-management:claude-md-improver`. Apply: §3 title count bump, §1 priority-chain row 2b count bump, new §3.3 project-management row(s) for `#N` (+`#N+1`). The plugin also writes the `docs/CHANGELOG_claude_md.md` entry and bumps §0 cross-ref versions (Tooling / PSR_v1 / Pravila). **Do not** edit `CLAUDE.md` directly (§5 п.10).
|
||||
|
||||
- [ ] **Step 6: Lint + commit**
|
||||
|
||||
```bash
|
||||
npx markdownlint-cli2 "docs/Tooling_v8_3.md" "docs/Plugin_stack_rules_v1.md" "docs/Pravila_raboty_Claude_v1_1.md" "docs/CHANGELOG_claude_md.md"
|
||||
npx cspell --no-progress --no-summary --no-gitignore "docs/Tooling_v8_3.md" "docs/Plugin_stack_rules_v1.md" "docs/Pravila_raboty_Claude_v1_1.md"
|
||||
git add docs/Tooling_v8_3.md docs/Plugin_stack_rules_v1.md docs/Pravila_raboty_Claude_v1_1.md CLAUDE.md docs/CHANGELOG_claude_md.md cspell-words.txt
|
||||
git commit -m "docs(c9): register CCPM (+product-management) project-management category (NUM1)"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 8: Reflect C9 on the map — close the section
|
||||
|
||||
**Files:** Modify `docs/automation-graph.html`
|
||||
|
||||
- [ ] **Step 1: Read the structures to replicate**
|
||||
|
||||
In `docs/automation-graph.html` read, as templates: an existing vendored-skill node (`mermaid_skill` if A6 landed, else a project-skill node `sk_rls`) and a plugin node (`claude_md_mgmt`) across `NODES`, `NODE_DETAILS`/`nd(...)`, `NODE_SECTION`, and the "Паспорт узла" date fields. Record the current node/edge counts from the header.
|
||||
|
||||
- [ ] **Step 2: Add the C9 nodes**
|
||||
|
||||
Add to `NODES`, replicating the template shapes:
|
||||
|
||||
- `ccpm` — label `CCPM\n(skill)`, skills group.
|
||||
- `product_mgmt` — label `product-\nmanagement`, plugins group. *(omit if Task 5 was deferred)*
|
||||
|
||||
Add matching `nd(...)` / `NODE_DETAILS` entries (Russian, per the file's convention), Паспорт `since: '2026-05-17'`:
|
||||
|
||||
- `ccpm` — "Vendored-скил: PRD→эпик→GitHub-issue→код с трассируемостью. Раздел C9 опирается также на reuse — GitHub MCP (issues/Projects v2) + Superpowers writing-plans + q-item-add."
|
||||
- `product_mgmt` — "Плагин Anthropic: PRD/роадмап/метрики (product-strategy церемонии)."
|
||||
|
||||
- [ ] **Step 3: Map the new nodes to section C9**
|
||||
|
||||
In `NODE_SECTION` add (omit `product_mgmt` if Task 5 deferred):
|
||||
|
||||
```js
|
||||
ccpm: 'C9', product_mgmt: 'C9',
|
||||
```
|
||||
|
||||
`C9 «Управление проектами»` goes from 0 → 1-2 nodes — the section is no longer empty.
|
||||
|
||||
- [ ] **Step 4: Update header metrics + group-count comments**
|
||||
|
||||
Bump the node count in the map header/legend by 1-2. Update the `NODE_SECTION` group-count comments (plugins, skills).
|
||||
|
||||
- [ ] **Step 5: Smoke-test the map**
|
||||
|
||||
```bash
|
||||
npx stylelint docs/automation-graph.html
|
||||
```
|
||||
|
||||
Open `docs/automation-graph.html` (Playwright MCP or a local `http.server` — quirk 90: `file://` rejected). Expected: 0 JS console errors; the new node(s) render; clicking section `C9` highlights them.
|
||||
|
||||
- [ ] **Step 6: Commit**
|
||||
|
||||
```bash
|
||||
git add docs/automation-graph.html
|
||||
git commit -m "feat(map): C9 nodes — closes section «Управление проектами»"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 9: Final regression & branch finish
|
||||
|
||||
**Files:** none modified
|
||||
|
||||
- [ ] **Step 1: Full pre-commit chain**
|
||||
|
||||
```bash
|
||||
npx lefthook run pre-commit
|
||||
```
|
||||
|
||||
Expected: all jobs green — C9 adds **no** lefthook job (job count unchanged: 8, or 9 if A6's adr-judge landed).
|
||||
|
||||
- [ ] **Step 2: Confirm app code untouched — run the suites**
|
||||
|
||||
C9 changes no `app/` code → suites must match the Task 1 Step 3 baseline:
|
||||
|
||||
```bash
|
||||
cd app && php artisan test --parallel
|
||||
npm run test:vue
|
||||
```
|
||||
|
||||
Expected: Pest and Vitest counts unchanged vs the Task 1 baseline (0 regressions). Record exact counts; write out any failure with file:line.
|
||||
|
||||
- [ ] **Step 3: Confirm the economy/ruflo hook chain is intact**
|
||||
|
||||
Economy marker still appears; the Stop verifier still runs; no plugin/skill leaked a `hooks` entry into either `settings.json`. Compare to the Task 1 Step 2 snapshot.
|
||||
|
||||
- [ ] **Step 4: Pre-push checks**
|
||||
|
||||
```bash
|
||||
./bin/gitleaks.exe detect --source . --no-banner --redact
|
||||
./bin/lychee.exe --config .lychee.toml "docs/**/*.md" "*.md"
|
||||
```
|
||||
|
||||
Expected: gitleaks 0 leaks; lychee 0 broken (new `docs/projects/*.md` + `docs/adr/ADR-004-*.md` are scanned — fix or `.lychee.toml`-exclude any link).
|
||||
|
||||
- [ ] **Step 5: Finish the branch**
|
||||
|
||||
Invoke `superpowers:finishing-a-development-branch` — present the standard options. Do **not** push without an explicit user choice. Push pattern: `git push origin feat/c9-project-management-tooling:main`.
|
||||
|
||||
---
|
||||
|
||||
## Self-Review
|
||||
|
||||
**1. Spec coverage (Variant А — reuse core + CCPM + conditional product-management).** Reuse — GitHub MCP `projects` toolset enabled (Task 2), Superpowers/`q-item-add`/ruflo documented in the convention (Task 4 Step 2). CCPM — vendored (Task 3), bootstrapped (Task 4), smoked (Task 6). product-management — conditional install (Task 5). Section closure: normative (Task 7), map (Task 8), regression/finish (Task 9). Conflict audit: CP1→T3.4, CP2→T4.2, CP3→T4.4 (ADR-004), CP4→T1.4+T3.2, CP5→T4.1+T7.2, CP6→T6.2, PG1→T1.5+T5(header), PG2→T5.2, PG3→T7.2, GH1→T2, GH2→no task (dropped), REU1→T8.2, CC1→T7.2, NUM1→T1.6+T7.1. No gaps.
|
||||
|
||||
**2. Placeholder scan.** `#N`/`#N+1` (Task 7), the exact `/plugin install` strings (Task 5), and the `.mcp.json` toolset config shape (Task 2) are **runtime-resolved by design** — the live Tooling counter, the product-management marketplace, and the actual `.mcp.json` shape are not knowable before Task 1 Step 5-6 / Task 2 Step 1, which carry concrete resolution criteria (same pattern as the A6/D3 plans). All file contents (`docs/projects/README.md`, ADR-004, the `.gitkeep` seeds) are shown in full. No "TBD" / "handle edge cases".
|
||||
|
||||
**3. Consistency.** Branch `feat/c9-project-management-tooling` consistent T1↔T9. Node ids `ccpm` / `product_mgmt` consistent T8 Steps 2-3. Category name **project-management** consistent T7 Steps 2-4. Paths consistent: `.claude/skills/ccpm/`, `.claude/prds/`, `.claude/epics/`, `docs/projects/`. The conditional `product_mgmt` is flagged uniformly (Task 5 header, Task 7 Step 2, Task 8 Steps 2-3). No lefthook job added — consistent with the "minimal-conflict" goal.
|
||||
|
||||
---
|
||||
|
||||
## Execution Handoff
|
||||
|
||||
Plan complete and saved to `docs/superpowers/plans/2026-05-17-c9-project-management-tooling-integration.md`. Two execution options:
|
||||
|
||||
1. **Subagent-Driven (recommended for the doc-heavy tasks)** — fresh subagent per task, two-stage review. *Caveat:* Tasks 2, 5 (`/plugin …`, `/reload-plugins`), Task 3 Step 5 + Task 6 Step 1 (skill invocations) and Task 7 Step 5 (`claude-md-management`) are main-session-bound — those steps stay with the controller.
|
||||
2. **Inline Execution** — `superpowers:executing-plans`, batch with checkpoints. **Recommended here** — install/config/docs-heavy with many interactive main-session steps (same as the A6/D3 plans).
|
||||
|
||||
**Sequencing reminder:** C9 cannot start until A6 **and** D3 are complete and pushed (locked — see "Sequencing" in the header). One open item before execution: execution method — **1** (Subagent-Driven) or **2** (Inline, recommended here).
|
||||
@@ -12,6 +12,8 @@
|
||||
|
||||
---
|
||||
|
||||
> **NB (исправлено 17.05.2026, нормативка v2.5):** #4 Security Guidance в этом плане описан как «warn-only / does not block» (строки ~21, ~251, ~542) — **фактически неверно**: хук делает `sys.exit(2)` → это **блокирующий** PreToolUse-хук (одноразовый speed-bump per «файл+правило» за сессию, retry проходит). Актуальная характеристика — Tooling §4.15 / ADR-003 / CLAUDE.md §3.3 #40. План оставлен как исторический снимок, тело не переписано.
|
||||
|
||||
## Tool Identity (verified 2026-05-17 via WebFetch/WebSearch)
|
||||
|
||||
| # | Tool | Install mode | Source / License | Hooks? |
|
||||
|
||||
@@ -0,0 +1,378 @@
|
||||
# Sprint 6 — P3 Polish + Cleanup Tail Implementation Plan
|
||||
|
||||
> **For agentic workers:** REQUIRED SUB-SKILL: Use superpowers:subagent-driven-development (recommended) or superpowers:executing-plans to implement this plan task-by-task. Steps use checkbox (`- [ ]`) syntax for tracking.
|
||||
|
||||
**Goal:** Закрыть P3-эпики финального спринта portal-audit (`docs/superpowers/specs/2026-05-15-portal-audit-design.md` §3 Sprint 6) — a11y-доводка, гигиена констант, снятие устаревшего dev-workaround'а.
|
||||
|
||||
**Architecture:** 5 независимых XS-эпиков, все — frontend-only (Vue 3.5 SFC + TypeScript), 0 backend / 0 schema / 0 миграций. Каждый эпик правит обособленную группу файлов — пересечений между задачами нет, порядок T1→T5 произвольный, конфликты исключены.
|
||||
|
||||
**Tech Stack:** Vue 3.5 + Vuetify 3.12 + TypeScript, Vitest 4 (тесты), `import.meta.env.DEV` (DEV-гейт, статически вырезается Vite в prod-сборке).
|
||||
|
||||
**Scope-решение по 3 эпикам Sprint 6, НЕ входящим в этот план:**
|
||||
|
||||
- **F5** (`new_device_login` через session-fingerprint) — XL, требует инфраструктуры сессий-фингерпринтов; вне MVP, остаётся в реестре.
|
||||
- **G8** (ImpersonationDialog two-person approval, CTO-15) — требует Б-1 (Yandex 360 SSO); блокирован внешним блокером.
|
||||
- **I2** (dev-indices.json — gitignore-решение) — **отложен вместе с I1**. I1 (снос DevIndexBadge/DevIndexOverlay) заказчик отложил в Sprint 5D до заморозки UI; `dev-indices.json` — генерируемый манифест этой же временной фичи. Решать его git-судьбу до сноса фичи — churn на артефакте, который всё равно удалится. Отложен синхронно с I1.
|
||||
|
||||
**Эпики в этом плане (5):** A9, B6, F4, G9, I5.
|
||||
|
||||
---
|
||||
|
||||
## File Structure
|
||||
|
||||
| Файл | Задача | Ответственность |
|
||||
|---|---|---|
|
||||
| `app/resources/js/views/auth/LoginView.vue` | T1 (A9) | eye-toggle через `#append-inner` slot с accessible-name |
|
||||
| `app/resources/js/views/auth/RegisterView.vue` | T1 (A9) | то же |
|
||||
| `app/resources/js/views/auth/ResetPasswordView.vue` | T1 (A9) | то же (только первое поле пароля; поле «Повторите» eye-иконки не имеет) |
|
||||
| `app/resources/js/layouts/AdminLayout.vue` | T2 (B6) | DEV-only баннер о застабленном auth-gate |
|
||||
| `app/resources/js/constants/polling.ts` | T3 (F4) | **создаётся** — именованные интервалы polling |
|
||||
| `app/resources/js/composables/usePolling.ts` | T3 (F4) | дефолт интервала из константы |
|
||||
| `app/resources/js/layouts/AppLayout.vue` | T3 (F4) | call-site → константы |
|
||||
| `app/resources/js/components/admin/ImpersonationBanner.vue` | T3 (F4) | call-site → константа |
|
||||
| `app/resources/js/views/ReportsView.vue` | T3 (F4) | call-site → константа |
|
||||
| `app/resources/js/views/admin/AdminSystemView.vue` | T4 (G9) | aria-label на edit-кнопки |
|
||||
| `app/resources/js/views/ProjectsView.vue` | T5 (I5) | удаление устаревшего clearable-workaround'а из `<style>` |
|
||||
| spec-файлы в `app/tests/Frontend/` | T1/T2/T4 | failing-тесты + сверка существующих |
|
||||
|
||||
---
|
||||
|
||||
## Task 1: A9 — accessible-name на eye-icon переключателях пароля
|
||||
|
||||
**Контекст:** В `LoginView`/`RegisterView`/`ResetPasswordView` поле пароля переключает видимость через Vuetify-проп `:append-inner-icon` + `@click:append-inner`. Иконка-переключатель кликабельна, но не имеет accessible-name и не доступна с клавиатуры → screen-reader пользователь не знает, что это кнопка. Фикс — заменить проп на слот `#append-inner` с `<v-icon>` в роли кнопки: `role="button"` + `tabindex` + `:aria-label` + keyboard-обработчики.
|
||||
|
||||
**Files:**
|
||||
- Modify: `app/resources/js/views/auth/LoginView.vue:81-93`
|
||||
- Modify: `app/resources/js/views/auth/RegisterView.vue:97-109`
|
||||
- Modify: `app/resources/js/views/auth/ResetPasswordView.vue:107-119`
|
||||
- Test: `app/tests/Frontend/LoginView.spec.ts`, `RegisterView.spec.ts`, `ResetPasswordView.spec.ts`
|
||||
|
||||
- [ ] **Step 1: Сверить существующие spec-файлы**
|
||||
|
||||
Прочитать 3 spec-файла. Найти тесты, взаимодействующие с переключателем (grep `append-inner`, `showPassword`, `eye`). Если тест триггерит `click:append-inner` — после рефактора это событие не возникнет (теперь клик по `<v-icon>` в слоте), такие тесты переписать на клик по иконке с aria-label. Запомнить mount-setup (плагины Vuetify/Pinia/router-стабы) для нового теста.
|
||||
|
||||
- [ ] **Step 2: Написать failing-тест (для каждой из 3 вью)**
|
||||
|
||||
В каждый spec добавить тест (mount-setup взять из существующих тестов файла):
|
||||
|
||||
```ts
|
||||
it('переключатель видимости пароля имеет accessible-name и работает', async () => {
|
||||
const wrapper = mount(LoginView, { /* global: из существующего setup файла */ });
|
||||
const toggle = wrapper.find('[aria-label="Показать пароль"]');
|
||||
expect(toggle.exists()).toBe(true);
|
||||
expect(toggle.attributes('role')).toBe('button');
|
||||
await toggle.trigger('click');
|
||||
expect(wrapper.find('[aria-label="Скрыть пароль"]').exists()).toBe(true);
|
||||
});
|
||||
```
|
||||
|
||||
Для `RegisterView`/`ResetPasswordView` — аналогично, заменив компонент.
|
||||
|
||||
- [ ] **Step 3: Прогнать тесты — убедиться, что падают**
|
||||
|
||||
Run: `cd app && npm run test:vue -- LoginView RegisterView ResetPasswordView`
|
||||
Expected: 3 новых теста FAIL (`aria-label="Показать пароль"` не найден — сейчас проп `append-inner-icon`).
|
||||
|
||||
- [ ] **Step 4: Реализовать слот в LoginView.vue**
|
||||
|
||||
Заменить блок `app/resources/js/views/auth/LoginView.vue:81-93` (поле пароля):
|
||||
|
||||
```vue
|
||||
<v-text-field
|
||||
v-model="password"
|
||||
label="Пароль"
|
||||
:type="showPassword ? 'text' : 'password'"
|
||||
autocomplete="current-password"
|
||||
placeholder="Минимум 8 символов"
|
||||
variant="outlined"
|
||||
density="comfortable"
|
||||
required
|
||||
:error-messages="errors.password"
|
||||
>
|
||||
<template #append-inner>
|
||||
<v-icon
|
||||
:icon="showPassword ? 'mdi-eye-off' : 'mdi-eye'"
|
||||
:aria-label="showPassword ? 'Скрыть пароль' : 'Показать пароль'"
|
||||
role="button"
|
||||
tabindex="0"
|
||||
@click="showPassword = !showPassword"
|
||||
@keydown.enter.prevent="showPassword = !showPassword"
|
||||
@keydown.space.prevent="showPassword = !showPassword"
|
||||
/>
|
||||
</template>
|
||||
</v-text-field>
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Реализовать слот в RegisterView.vue**
|
||||
|
||||
Заменить блок `app/resources/js/views/auth/RegisterView.vue:97-109` тем же паттерном (поле пароля, `autocomplete="new-password"` — сохранить, `placeholder="Минимум 8 символов"` — сохранить). Снять строки `:append-inner-icon="..."` и `@click:append-inner="..."`, добавить `#append-inner`-слот как в Step 4.
|
||||
|
||||
- [ ] **Step 6: Реализовать слот в ResetPasswordView.vue**
|
||||
|
||||
Заменить блок `app/resources/js/views/auth/ResetPasswordView.vue:107-119` (первое поле — «Новый пароль») тем же паттерном. **Поле «Повторите пароль» (`:122-130`) не трогать** — у него нет eye-иконки, оно наследует `showPassword`.
|
||||
|
||||
- [ ] **Step 7: Прогнать тесты — убедиться, что зелёные**
|
||||
|
||||
Run: `cd app && npm run test:vue -- LoginView RegisterView ResetPasswordView`
|
||||
Expected: PASS — новые 3 теста + все ранее существовавшие в этих файлах.
|
||||
|
||||
- [ ] **Step 8: Commit**
|
||||
|
||||
```bash
|
||||
git add app/resources/js/views/auth/LoginView.vue app/resources/js/views/auth/RegisterView.vue app/resources/js/views/auth/ResetPasswordView.vue app/tests/Frontend/LoginView.spec.ts app/tests/Frontend/RegisterView.spec.ts app/tests/Frontend/ResetPasswordView.spec.ts
|
||||
git commit -m "fix(a11y): accessible eye-toggle на полях пароля — Sprint 6 A9"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 2: B6 — DEV-only баннер о застабленном auth-gate админки
|
||||
|
||||
**Контекст:** Sprint 3F (J2) поставил middleware `EnsureSaasAdmin` на `/api/admin/*` как стаб: в dev пропускает все запросы, в prod отдаёт 503. Комментарий в шапке `AdminLayout.vue:9-12` фиксирует, что полноценный auth-guard (`super_admin` role + 2FA через Yandex 360 SSO) ждёт Б-1. B6 — сделать этот auth-gap видимым в dev-UI баннером. Гейт — `import.meta.env.DEV` (Vite статически вырежет баннер в prod-сборке, паттерн I4 из Sprint 5D).
|
||||
|
||||
**Files:**
|
||||
- Modify: `app/resources/js/layouts/AdminLayout.vue` (script + template)
|
||||
- Test: `app/tests/Frontend/AdminLayout.spec.ts`
|
||||
|
||||
- [ ] **Step 1: Сверить AdminLayout.spec.ts**
|
||||
|
||||
Прочитать spec — запомнить mount-setup. Проверить наличие `vi.unstubAllEnvs()` в `afterEach` (если нет — добавить в Step 2, иначе stub `DEV` протечёт в другие тесты).
|
||||
|
||||
- [ ] **Step 2: Написать failing-тест**
|
||||
|
||||
В `AdminLayout.spec.ts` добавить (mount-setup — из существующих тестов):
|
||||
|
||||
```ts
|
||||
it('B6: показывает DEV-баннер auth-gap в dev-режиме', () => {
|
||||
const wrapper = mount(AdminLayout, { /* global: из существующего setup */ });
|
||||
expect(wrapper.find('[data-testid="dev-auth-gap-banner"]').exists()).toBe(true);
|
||||
});
|
||||
|
||||
it('B6: скрывает DEV-баннер в production-режиме', () => {
|
||||
vi.stubEnv('DEV', false);
|
||||
const wrapper = mount(AdminLayout, { /* global: из существующего setup */ });
|
||||
expect(wrapper.find('[data-testid="dev-auth-gap-banner"]').exists()).toBe(false);
|
||||
});
|
||||
```
|
||||
|
||||
Убедиться, что в файле есть `afterEach(() => { vi.unstubAllEnvs(); });` (добавить, если отсутствует).
|
||||
|
||||
- [ ] **Step 3: Прогнать тест — убедиться, что падает**
|
||||
|
||||
Run: `cd app && npm run test:vue -- AdminLayout`
|
||||
Expected: тест `показывает DEV-баннер` FAIL (`data-testid="dev-auth-gap-banner"` не найден).
|
||||
|
||||
- [ ] **Step 4: Добавить DEV-флаг в script**
|
||||
|
||||
В `app/resources/js/layouts/AdminLayout.vue` после `const auth = useAuthStore();` (`:39`) добавить:
|
||||
|
||||
```ts
|
||||
|
||||
/** DEV-режим: показываем баннер о застабленном auth-gate админки (B6). */
|
||||
const isDevEnv = import.meta.env.DEV;
|
||||
```
|
||||
|
||||
- [ ] **Step 5: Добавить баннер в template**
|
||||
|
||||
В `<v-main class="admin-main">` (`:133`) — перед `<ImpersonationBanner />` вставить:
|
||||
|
||||
```vue
|
||||
<v-alert
|
||||
v-if="isDevEnv"
|
||||
type="warning"
|
||||
variant="tonal"
|
||||
density="compact"
|
||||
class="ma-4"
|
||||
data-testid="dev-auth-gap-banner"
|
||||
>
|
||||
DEV-режим: доступ к админке открыт без SSO-проверки — middleware
|
||||
<code>EnsureSaasAdmin</code> в dev пропускает все запросы. В production
|
||||
требуется вход через Yandex 360 + роль <code>super_admin</code> (Б-1);
|
||||
неавторизованные запросы получают 503.
|
||||
</v-alert>
|
||||
```
|
||||
|
||||
- [ ] **Step 6: Прогнать тест — убедиться, что зелёные**
|
||||
|
||||
Run: `cd app && npm run test:vue -- AdminLayout`
|
||||
Expected: PASS — оба новых теста + ранее существовавшие.
|
||||
|
||||
- [ ] **Step 7: Commit**
|
||||
|
||||
```bash
|
||||
git add app/resources/js/layouts/AdminLayout.vue app/tests/Frontend/AdminLayout.spec.ts
|
||||
git commit -m "feat(admin): DEV-only баннер о застабленном auth-gate — Sprint 6 B6"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 3: F4 — вынести polling-интервалы в `constants/polling.ts`
|
||||
|
||||
**Контекст:** Дефолтный интервал `30_000` зашит в `usePolling.ts`, а call-site'ы `AppLayout`/`ImpersonationBanner`/`ReportsView` дублируют литералы `30_000`/`60_000`. F4 — собрать «магические» числа в один модуль. Чистый рефактор: поведение не меняется, защитная сетка — существующие тесты.
|
||||
|
||||
**Files:**
|
||||
- Create: `app/resources/js/constants/polling.ts`
|
||||
- Modify: `app/resources/js/composables/usePolling.ts:18,25`
|
||||
- Modify: `app/resources/js/layouts/AppLayout.vue:17,60,61`
|
||||
- Modify: `app/resources/js/components/admin/ImpersonationBanner.vue:16,40`
|
||||
- Modify: `app/resources/js/views/ReportsView.vue:14,62`
|
||||
|
||||
- [ ] **Step 1: Создать `constants/polling.ts`**
|
||||
|
||||
```ts
|
||||
/**
|
||||
* Интервалы polling-обновления view-данных — единый источник «магических»
|
||||
* чисел для usePolling. До приезда SSE/WebSocket в production это покрывает
|
||||
* «real-time»-паттерн (см. composables/usePolling.ts).
|
||||
*/
|
||||
|
||||
/** Базовый интервал авто-обновления (сделки, биллинг, инциденты, тенанты, отчёты). */
|
||||
export const POLLING_INTERVAL_MS = 30_000;
|
||||
|
||||
/** Интервал для менее срочных счётчиков (напоминания в сайдбаре). */
|
||||
export const POLLING_REMINDERS_INTERVAL_MS = 60_000;
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Подключить константу в usePolling.ts**
|
||||
|
||||
В `app/resources/js/composables/usePolling.ts`:
|
||||
- Первой строкой добавить импорт: `import { POLLING_INTERVAL_MS } from '../constants/polling';` (после `import { onBeforeUnmount, onMounted } from 'vue';`).
|
||||
- Строка `:18` doc-комментарий: `/** Период polling в миллисекундах. По умолчанию 30_000. */` → `/** Период polling в миллисекундах. По умолчанию POLLING_INTERVAL_MS (30 с). */`
|
||||
- Строка `:25`: `const intervalMs = options.intervalMs ?? 30_000;` → `const intervalMs = options.intervalMs ?? POLLING_INTERVAL_MS;`
|
||||
|
||||
- [ ] **Step 3: Обновить call-site'ы**
|
||||
|
||||
`AppLayout.vue` — добавить к импортам (`:17`): `import { POLLING_INTERVAL_MS, POLLING_REMINDERS_INTERVAL_MS } from '../constants/polling';`
|
||||
- `:60` `usePolling(loadNotifications, { intervalMs: 30_000, enabled: true });` → `{ intervalMs: POLLING_INTERVAL_MS, enabled: true }`
|
||||
- `:61` `usePolling(loadReminderCounts, { intervalMs: 60_000, enabled: true });` → `{ intervalMs: POLLING_REMINDERS_INTERVAL_MS, enabled: true }`
|
||||
|
||||
`ImpersonationBanner.vue` — добавить импорт `import { POLLING_INTERVAL_MS } from '../../constants/polling';`
|
||||
- `:40` `usePolling(load, { intervalMs: 30_000 });` → `{ intervalMs: POLLING_INTERVAL_MS }`
|
||||
|
||||
`ReportsView.vue` — добавить импорт `import { POLLING_INTERVAL_MS } from '../constants/polling';`
|
||||
- `:62` `usePolling(loadJobs, { intervalMs: 30_000 });` → `{ intervalMs: POLLING_INTERVAL_MS }`
|
||||
|
||||
Call-site'ы на дефолте (`DealsView`/`KanbanView`/`AdminBillingView`/`AdminIncidentsView`/`AdminTenantsView`) — **не трогать**, они уже получают значение через дефолт `usePolling`.
|
||||
|
||||
- [ ] **Step 4: Type-check + тесты (рефактор — поведение без изменений)**
|
||||
|
||||
Run: `cd app && npm run type-check && npm run test:vue -- usePolling AppLayout ImpersonationBanner ReportsView`
|
||||
Expected: vue-tsc 0 ошибок; все тесты PASS без изменений (интервалы численно те же — `30_000`/`60_000`).
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add app/resources/js/constants/polling.ts app/resources/js/composables/usePolling.ts app/resources/js/layouts/AppLayout.vue app/resources/js/components/admin/ImpersonationBanner.vue app/resources/js/views/ReportsView.vue
|
||||
git commit -m "refactor(polling): вынести интервалы в constants/polling.ts — Sprint 6 F4"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 4: G9 — aria-label на edit-кнопки AdminSystemView
|
||||
|
||||
**Контекст:** В списке `system_settings` каждая строка имеет кнопку «Изменить» (`AdminSystemView.vue:166-175`). У всех кнопок одинаковый видимый текст «Изменить» — screen-reader пользователь, проходя список, слышит «Изменить, Изменить, Изменить» без контекста, какая настройка. Фикс — `:aria-label` с ключом настройки.
|
||||
|
||||
**Files:**
|
||||
- Modify: `app/resources/js/views/admin/AdminSystemView.vue:166-175`
|
||||
- Test: `app/tests/Frontend/AdminSystemView.spec.ts`
|
||||
|
||||
- [ ] **Step 1: Написать failing-тест**
|
||||
|
||||
В `AdminSystemView.spec.ts` добавить (mount-setup — из существующих тестов файла; компонент стартует с mock-данными до `onMounted`-загрузки, либо использовать `defineExpose`d `settingsState`):
|
||||
|
||||
```ts
|
||||
it('G9: edit-кнопки имеют aria-label с ключом настройки', () => {
|
||||
const wrapper = mount(AdminSystemView, { /* global: из существующего setup */ });
|
||||
const editBtns = wrapper.findAll('[data-testid^="edit-"]');
|
||||
expect(editBtns.length).toBeGreaterThan(0);
|
||||
for (const btn of editBtns) {
|
||||
const label = btn.attributes('aria-label') ?? '';
|
||||
expect(label).toMatch(/^Изменить настройку .+/);
|
||||
}
|
||||
});
|
||||
```
|
||||
|
||||
- [ ] **Step 2: Прогнать тест — убедиться, что падает**
|
||||
|
||||
Run: `cd app && npm run test:vue -- AdminSystemView`
|
||||
Expected: FAIL — `aria-label` отсутствует на кнопках.
|
||||
|
||||
- [ ] **Step 3: Добавить aria-label**
|
||||
|
||||
В `app/resources/js/views/admin/AdminSystemView.vue` в `<v-btn>` (`:166-175`) добавить строку `:aria-label` между `prepend-icon` и `:data-testid`:
|
||||
|
||||
```vue
|
||||
<v-btn
|
||||
variant="text"
|
||||
size="small"
|
||||
density="comfortable"
|
||||
prepend-icon="mdi-pencil"
|
||||
:aria-label="`Изменить настройку ${setting.key}`"
|
||||
:data-testid="`edit-${setting.key}-btn`"
|
||||
@click="openEdit(setting)"
|
||||
>
|
||||
Изменить
|
||||
</v-btn>
|
||||
```
|
||||
|
||||
- [ ] **Step 4: Прогнать тест — убедиться, что зелёный**
|
||||
|
||||
Run: `cd app && npm run test:vue -- AdminSystemView`
|
||||
Expected: PASS — новый тест + ранее существовавшие.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add app/resources/js/views/admin/AdminSystemView.vue app/tests/Frontend/AdminSystemView.spec.ts
|
||||
git commit -m "fix(a11y): aria-label с ключом на edit-кнопках AdminSystem — Sprint 6 G9"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Task 5: I5 — снять устаревший clearable-workaround из ProjectsView
|
||||
|
||||
**Контекст:** `ProjectsView.vue:170-196` содержит CSS-workaround: у `clearable` `v-text-field` иконка `mdi-close-circle` делалась прозрачной, а вместо неё `::after`-псевдоэлементом рисовался Unicode-глиф `✕` — потому что MDI-шрифт не был подключён (Диз-4). CTO-19 (миграция на Lucide) закрыта: `app/resources/js/plugins/vuetify.ts:164` маппит `'mdi-close-circle': XCircle` — clearable-иконка теперь рендерится нативным Lucide-SVG. Workaround мёртв → удалить.
|
||||
|
||||
**Files:**
|
||||
- Modify: `app/resources/js/views/ProjectsView.vue` (удаление CSS-блока `:170-196`)
|
||||
|
||||
- [ ] **Step 1: Проверить премису (фальсифицировать перед удалением)**
|
||||
|
||||
Подтвердить, что `app/resources/js/plugins/vuetify.ts` содержит `'mdi-close-circle': XCircle` в Lucide IconSet-маппинге и `XCircle` импортирован из `lucide-vue-next`. Если маппинга нет — задача **BLOCKED**, эскалировать (workaround снимать нельзя без замены).
|
||||
|
||||
- [ ] **Step 2: Удалить CSS-блок workaround'а**
|
||||
|
||||
В `app/resources/js/views/ProjectsView.vue` удалить строки `:170-196` целиком — комментарий-заголовок `/* Workaround: MDI-шрифт... */` и 4 CSS-правила: `.projects-view :deep(.v-field__clearable)`, `.projects-view :deep(.v-field__clearable .v-icon)`, `.projects-view :deep(.v-field--dirty .v-field__clearable)::after`, `.projects-view :deep(.v-field--dirty .v-field__clearable:hover)::after`. Соседние блоки (`.projects-grid` выше, `.toolbar-check` ниже) не трогать.
|
||||
|
||||
- [ ] **Step 3: Type-check + сборка + существующие тесты**
|
||||
|
||||
Run: `cd app && npm run type-check && npm run test:vue -- ProjectsView`
|
||||
Expected: vue-tsc 0; `ProjectsView.spec.ts` PASS без изменений (правка чисто CSS, JS-поведение не затронуто).
|
||||
|
||||
- [ ] **Step 4: Визуальный smoke (Playwright)**
|
||||
|
||||
Запустить dev-сервер, открыть `/projects`, ввести текст в поле поиска проектов (`clearable`). Подтвердить: иконка очистки (Lucide `XCircle`) **видима** справа в поле и клик по ней очищает значение. Сделать скриншот. Если иконка не рендерится — premise опровергнута, `git revert` Step 2 и эскалировать.
|
||||
|
||||
- [ ] **Step 5: Commit**
|
||||
|
||||
```bash
|
||||
git add app/resources/js/views/ProjectsView.vue
|
||||
git commit -m "chore(cleanup): снять устаревший MDI clearable-workaround (CTO-19 tail) — Sprint 6 I5"
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Финальная верификация (после всех 5 задач)
|
||||
|
||||
- [ ] **Полная регрессия Vitest** — `cd app && npm run test:vue -- --maxWorkers=2` (full-suite без `--maxWorkers=2` OOM'ит в worktree — квирк 98). Ожидаемо: 0 fail; число passed ≥ baseline + новые тесты (T1 ×3, T2 ×2, T4 ×1).
|
||||
- [ ] **vue-tsc** — `cd app && npm run type-check` → 0 ошибок.
|
||||
- [ ] **ESLint** — `cd app && npm run lint:vue` → известная pre-existing ошибка `tests/Frontend/ImportView.spec.ts:4` (Sprint 4 долг, вне scope Sprint 6); 0 новых.
|
||||
- [ ] **Vite build** — `cd app && npm run build` → OK (подтверждает, что DEV-гейт B6 валиден для prod-сборки).
|
||||
- [ ] **Pest** опционально — Sprint 6 не трогает PHP-файлы (0 backend-изменений), backend-регрессия структурно невозможна; полный прогон Pest — belt, не обязателен.
|
||||
- [ ] **Финальный holistic code-review** всего диффа Sprint 6.
|
||||
- [ ] **Pre-push:** gitleaks-full-history + lychee (lefthook не в PATH worktree — прогонять вручную).
|
||||
|
||||
## Self-Review (выполнено при написании плана)
|
||||
|
||||
- **Spec coverage:** Sprint 6 §3 спека = 8 эпиков. A9/B6/F4/G9/I5 — в плане (5 задач). F5/G8 — внешне блокированы (инфра/Б-1). I2 — отложен с I1 (решение заказчика Sprint 5D). Покрытие полное и обоснованное.
|
||||
- **Placeholder-скан:** весь production-код приведён дословно (file:line); тест-код — с конкретными ассертами, mount-setup берётся из существующих spec-файлов (они прочитаны на Step 1 каждой задачи).
|
||||
- **Type consistency:** `POLLING_INTERVAL_MS` / `POLLING_REMINDERS_INTERVAL_MS` — единые имена в T3 (создание + 4 call-site). `data-testid="dev-auth-gap-banner"` — единое имя в T2 (template + 2 теста). `isDevEnv` — единое имя в T2.
|
||||
@@ -0,0 +1,167 @@
|
||||
# A11 ML / AI Tooling Integration — Design
|
||||
|
||||
**Date:** 2026-05-17
|
||||
**Topic:** Populate the empty `A11 «ML / AI-разработка»` map section.
|
||||
**Deciders:** Дмитрий
|
||||
**Method:** `superpowers:brainstorming` (economy 5%). Approach А approved 2026-05-17.
|
||||
|
||||
---
|
||||
|
||||
## Goal
|
||||
|
||||
Populate the empty `A11 «ML / AI-разработка»` section of `docs/automation-graph.html`
|
||||
with a conflict-minimal ML/AI toolset — so A11 becomes a working playbook, the same
|
||||
way A6 «Архитектура систем» was closed with adr-kit/mermaid/architecture-patterns and
|
||||
C9 «Управление проектами» with the CCPM stack.
|
||||
|
||||
## Context
|
||||
|
||||
- **A11 is empty.** `SECTIONS` in `docs/automation-graph.html:1836` defines
|
||||
`A11 = «ML / AI-разработка»` (bucket A «Технические и продуктовые»); `NODE_SECTION`
|
||||
tags **zero** nodes to A11.
|
||||
- **The map is a tooling map** — «карта dev-автоматики» (plugins / skills / MCP /
|
||||
hooks Claude uses). A11 must therefore be populated with **ML/AI *development
|
||||
tools*** — not with product features.
|
||||
- **The project has no ML/AI code.** Лидерра is a Laravel 13 + Vue 3 multi-tenant
|
||||
CRM. The only scoring artifact, `calc_lead_score` (`db/schema.sql`), is a
|
||||
deterministic SQL function — not a model. No dataset, no feature store, no ML/AI
|
||||
item in `Открытые_вопросы` or the plan backlog.
|
||||
- **The machine is runtime-minimal by policy.** Native Windows, no Docker (no
|
||||
nested virt on the OpenStack VPS), pg_partman replaced with a cron command. Every
|
||||
new runtime passes an explicit weighing. Python is **not** in the stack (PHP +
|
||||
Node only).
|
||||
|
||||
## Scope decision
|
||||
|
||||
A11 covers **both** subcategories — classical ML **and** LLM integration (user
|
||||
choice 2026-05-17). The **Python runtime is deferred**: the executable classical-ML
|
||||
part (Jupyter MCP) is a severable/conditional task, not a now-install. Rationale:
|
||||
no ML model to train, no dataset, a new runtime on a deliberately-minimal machine,
|
||||
and the Jupyter MCP is experimental (Notebook 6.x only). The classical-ML
|
||||
*knowledge* layer (Data Scientist skill, zero runtime) **is** installed now, so the
|
||||
subcategory is not empty — only its executor is gated.
|
||||
|
||||
This mirrors the project idiom: C9 made product-management a conditional task; A6
|
||||
made the lefthook-enforcement task severable.
|
||||
|
||||
---
|
||||
|
||||
## Architecture — the 6-position toolset (Approach А)
|
||||
|
||||
Two subcategories. Three positions are **reuse** (already installed — A11 documents
|
||||
the coverage, REU1), two are **new + light**, one is **new + deferred**.
|
||||
|
||||
| # | Tool | Subcategory | Install mode | Status |
|
||||
|---|---|---|---|---|
|
||||
| 1 | **claude-api skill** | LLM integration | already available (plugin skill) | reuse |
|
||||
| 2 | **context7 MCP** | both (library docs) | already installed (MCP, map node `context7` in E7) | reuse |
|
||||
| 3 | **Sentry MCP** (Tooling #34) | LLM observability | already installed (MCP, map node `mcp_sentry` in A7) | reuse — AI/LLM monitoring activates on the Sentry deployment (blocked on Б-1) |
|
||||
| 4 | **promptfoo** | LLM integration | new — Node CLI, project `package.json` devDependency, invoked `npx promptfoo`; MIT (OpenAI-owned, OSS) | new, light |
|
||||
| 5 | **Data Scientist skill** | classical ML | new — vendored standalone skill into `.claude/skills/data-scientist/` (no plugin, no marketplace, no hooks — the A6 mermaid pattern) | new, light |
|
||||
| 6 | **Jupyter MCP** (`datalayer/jupyter-mcp-server`) | classical ML | new — MCP server, Python-gated | **severable / conditional** — installed only when a concrete ML model is scoped |
|
||||
|
||||
**Reuse layer (positions 1-3).** claude-api skill = building AI features on the
|
||||
Anthropic SDK (lead qualification, call-summary, email drafts) with prompt caching.
|
||||
context7 MCP = up-to-date docs for AI/ML libraries and SDKs. Sentry MCP = debugging
|
||||
AI features in production via Sentry's AI/LLM monitoring (read-only, pending the
|
||||
Sentry instance — Б-1).
|
||||
|
||||
**New layer (positions 4-5).** promptfoo = a test suite for LLM prompts/agents:
|
||||
assertions, regression catching, LLM-graded eval, red-teaming. Node-based — **needs
|
||||
no new runtime**. Data Scientist skill = a knowledge-only skill: business
|
||||
objective → ML task, algorithm selection (Linear Regression … XGBoost), feature
|
||||
engineering, experiment-tracking guidance, A/B analysis.
|
||||
|
||||
**Deferred (position 6).** Jupyter MCP = executable notebooks for real model
|
||||
training. Gated on a Python ML environment + a concrete ML model to train.
|
||||
|
||||
A11 is **fully covered** by positions 1-5 from day one; position 6 is a reserved,
|
||||
registered-but-not-installed slot.
|
||||
|
||||
---
|
||||
|
||||
## Conflict audit
|
||||
|
||||
Pattern follows the K1–K8 / AK1–CC1 / CP1–NUM1 audits used for claude-mem and the
|
||||
A6 / C9 / D3 plans. Full audit with locked resolutions is produced in the
|
||||
implementation plan; the known conflicts:
|
||||
|
||||
| # | Tool | Sev | Conflict | Resolution direction |
|
||||
|---|---|---|---|---|
|
||||
| ML1 | promptfoo | 🟡 | A real eval run needs an Anthropic API key + costs money (paid LLM calls). | Key via env (PowerShell User scope, like Sentry) — never committed (gitleaks). promptfoo runs **manually / CI-only** — never in a hook, never in pre-commit, never auto. No economy-chain impact. |
|
||||
| ML2 | promptfoo | 🟢 | promptfoo's red-team module overlaps the D3 audit-security tools. | None — promptfoo red-team tests *LLM prompts* for jailbreak/injection; Trail of Bits / Semgrep (D3 #39, #25) are SAST of *code*. Different objects. Boundary documented. |
|
||||
| ML3 | Data Scientist skill | 🟡 | Vendored `.claude/skills/data-scientist/**/*.md` (third-party English files) is caught by the cspell + markdownlint pre-commit jobs. | Add `.claude/skills/data-scientist/**` to `cspell.json` `ignorePaths` and `.markdownlintignore` (the A6 MK1 pattern). The project's own skills stay linted. |
|
||||
| ML4 | reuse layer | 🟢 | Re-tagging the existing `context7` (E7) / `mcp_sentry` (A7) nodes to A11 would empty their current sections — `NODE_SECTION` is 1-node→1-section. | Reuse nodes **stay** in their sections; A11 gets its **own** new nodes. The reuse coverage is documented in `docs/ml/README.md`. Same as A6/D3/C9 REU1. |
|
||||
| ML5 | all | 🟢 | A11 is non-UI tooling. | New off-phase category **ml-ai-tooling**, outside the PSR_v1 UI-pool (no R6.0/R6.1 stack-filter, no R14 pipeline) — same treatment as architecture-tooling (A6) and audit-security (D3). |
|
||||
| ML6 | Jupyter MCP | 🟡 | Experimental (Notebook 6.x only), would be the 8th `.mcp.json` server, on a Python-less machine. | **Deferred** — severable/conditional task. When triggered: `alpha-substrate-spike-first` — a spike before integration. Registered in the registry/map as a reserved slot now; `.mcp.json` is untouched in the core scope. |
|
||||
| ML7 | all | 🟡 | Bus-factor — Data Scientist skill is community; Jupyter MCP is community + experimental. | Data Scientist skill is **vendored** → immune to upstream loss (the A6 mermaid pattern). promptfoo is MIT, OpenAI-owned, stable. Jupyter MCP — version-pinned at install time (deferred). Noted in the Tooling entry. |
|
||||
| ML8 | claude-api skill | 🟡 | claude-api is an available skill but may not be a formalized Tooling-registry position → using it unregistered is a PSR_v1 R0.2/R10 gap. | The plan's pre-flight checks whether claude-api (and its backing plugin) is already in `~/.claude/settings.json` `enabledPlugins` + the Tooling registry; if absent, register it as part of the A11 sync. |
|
||||
| ML9 | promptfoo | 🟢 | promptfoo install mode — global npm vs project devDep vs vendored binary. | Project `package.json` **devDependency** — version-pinned via `package-lock.json`, no global state, invoked `npx promptfoo`. (Not a `bin/*.exe` — promptfoo is an npm package, not a single binary.) |
|
||||
|
||||
---
|
||||
|
||||
## File structure
|
||||
|
||||
| File | Created / Modified | Responsibility |
|
||||
|---|---|---|
|
||||
| `docs/ml/` | Create dir | A11 home — the ML/AI playbook |
|
||||
| `docs/ml/README.md` | Create | The ML/AI convention: tool boundaries (claude-api skill = *build* AI features / promptfoo = *test* prompts / Data Scientist skill = classical-ML *workflow* / Jupyter MCP = *execute* — when scoped); the reuse-layer map |
|
||||
| `docs/ml/promptfoo-example/promptfooconfig.yaml` | Create | One seed eval config — a worked example (e.g. a lead-qualification prompt with assertions) |
|
||||
| `.claude/skills/data-scientist/` | Create (vendored) | The Data Scientist skill — `SKILL.md` + `references/` |
|
||||
| `docs/adr/ADR-005-ml-ai-tooling.md` | Create (conditional — adr-kit/A6 landed) | Seed ADR documenting the A11 tooling decision + the Python-defer |
|
||||
| `package.json` | Modify | `promptfoo` devDependency |
|
||||
| `cspell.json` | Modify | `ignorePaths` += `.claude/skills/data-scientist/**` (ML3) |
|
||||
| `.markdownlintignore` | Modify | += `.claude/skills/data-scientist/` (ML3) |
|
||||
| `cspell-words.txt` | Modify (conditional) | New ML/AI vocabulary |
|
||||
| `docs/Tooling_v8_3.md` | Modify | Прил. Н — new ml-ai-tooling subsection(s) + §0 counter bump |
|
||||
| `docs/Plugin_stack_rules_v1.md` | Modify | R10.1 — new ml-ai-tooling rows |
|
||||
| `docs/Pravila_raboty_Claude_v1_1.md` | Modify | §13.2 — ml-ai-tooling category note |
|
||||
| `CLAUDE.md` | Modify (**via claude-md-management only**) | §3 title count, §1 row 2b count, new §3.3 ml-ai-tooling rows |
|
||||
| `docs/CHANGELOG_claude_md.md` | Modify | CLAUDE.md version-bump entry |
|
||||
| `docs/automation-graph.html` | Modify | 3 new A11 nodes (`claude_api`, `promptfoo`, `data_scientist`) → `NODE_SECTION` A11; header metrics |
|
||||
| `.mcp.json` | **NOT modified in core scope** | Jupyter MCP deferred — `.mcp.json` touched only by the conditional task |
|
||||
|
||||
**Map nodes.** A11 gets **3 new nodes** — `claude_api`, `promptfoo`, `data_scientist`.
|
||||
The reuse nodes `context7` (E7) and `mcp_sentry` (A7) stay put (ML4). A `jupyter_mcp`
|
||||
node is added only when the conditional task runs (same as C9's conditional
|
||||
`product_mgmt` node).
|
||||
|
||||
---
|
||||
|
||||
## Severable scope
|
||||
|
||||
**Core A11** = the reuse layer + promptfoo + Data Scientist skill + normative sync +
|
||||
map closure. This already populates and closes the section.
|
||||
|
||||
**Conditional / severable** = the Jupyter MCP install (position 6) — a separate task,
|
||||
gated on (a) a Python ML environment decision and (b) a concrete ML model to build.
|
||||
Registered now as a reserved slot; installed later.
|
||||
|
||||
A11 adds **no lefthook job** and **no `.mcp.json` change** in the core scope — fewer
|
||||
conflicts by design (the C9 shape).
|
||||
|
||||
---
|
||||
|
||||
## Out of scope
|
||||
|
||||
- Building actual AI features into the CRM product (AI lead qualification, call
|
||||
summaries) — that is product work, tracked separately; A11 only provides the
|
||||
*tooling*.
|
||||
- Training an actual ML model / standing up a Python environment — the Jupyter MCP
|
||||
conditional task, triggered later.
|
||||
- Any LLM-eval gate in the commit pipeline (ML1 — promptfoo stays manual/CI-only).
|
||||
|
||||
## Open items resolved by the implementation plan
|
||||
|
||||
- **NUM** — A11's Tooling-registry numbers are runtime-resolved: the plan reads the
|
||||
**live** `docs/Tooling_v8_3.md` Прил. Н §0 counter (after A6 #36-38, D3 #39-40, and
|
||||
whatever C9 added) and assigns A11's numbers sequentially.
|
||||
- **claude-api registration** (ML8) — the plan's pre-flight checks whether claude-api
|
||||
is already a formalized Tooling position; registers it if not.
|
||||
- **ADR-005 conditional** — written only if adr-kit (A6) has landed in `origin/main`.
|
||||
- **Sequencing** — A11 forks off `origin/main` after the A6 / D3 / C9 epics land
|
||||
(they touch the same shared files: the map, 4 normative docs, the Tooling counter).
|
||||
The branch created for this spec is a scratch branch; execution re-forks.
|
||||
- **Exact tool identity** (promptfoo repo/version, Data Scientist skill source repo,
|
||||
Jupyter MCP repo) — verified via WebFetch/WebSearch in the plan's Tool Identity
|
||||
section (the A6/C9/D3 pattern).
|
||||
+4
-2
@@ -31,10 +31,11 @@ pre-commit:
|
||||
# 2. markdownlint — стиль Markdown с авто-fix
|
||||
- name: markdownlint
|
||||
glob: "*.md"
|
||||
# Вендоренный сторонний скил .claude/skills/mermaid/ — не линтуем (его .md
|
||||
# Вендоренные сторонние скилы .claude/skills/{mermaid,ccpm}/ — не линтуем (их .md
|
||||
# не наши; markdownlint-cli2 игнорирует .markdownlintignore при явных путях).
|
||||
exclude:
|
||||
- ".claude/skills/mermaid/**"
|
||||
- ".claude/skills/ccpm/**"
|
||||
run: npx markdownlint-cli2 --fix {staged_files}
|
||||
stage_fixed: true
|
||||
fail_text: |
|
||||
@@ -46,9 +47,10 @@ pre-commit:
|
||||
# (useGitignore:true) игнорирует worktree-коммиты под gitignored .claude/worktrees/.
|
||||
- name: cspell
|
||||
glob: "*.md"
|
||||
# Вендоренный сторонний скил .claude/skills/mermaid/ — не проверяем орфографию.
|
||||
# Вендоренные сторонние скилы .claude/skills/{mermaid,ccpm}/ — не проверяем орфографию.
|
||||
exclude:
|
||||
- ".claude/skills/mermaid/**"
|
||||
- ".claude/skills/ccpm/**"
|
||||
run: npx cspell --no-progress --no-summary --no-gitignore {staged_files}
|
||||
fail_text: |
|
||||
cspell нашёл слова, отсутствующие в словаре.
|
||||
|
||||
Reference in New Issue
Block a user