initial setup: planning documents updated
This commit is contained in:
226
CLAUDE.md
226
CLAUDE.md
@@ -7,9 +7,11 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
|
|||||||
This repository contains development of two Claude Code plugins for project management:
|
This repository contains development of two Claude Code plugins for project management:
|
||||||
|
|
||||||
1. **`projman`** - Single-repository project management plugin (build first)
|
1. **`projman`** - Single-repository project management plugin (build first)
|
||||||
2. **`pmo`** - Multi-project PMO coordination plugin (build second)
|
2. **`projman-pmo`** - Multi-project PMO coordination plugin (build second)
|
||||||
|
|
||||||
These plugins transform a proven 15-sprint workflow into reusable, distributable tools for managing software development with Claude Code, Gitea, and agile methodologies.
|
These plugins transform a proven 15-sprint workflow into reusable, distributable tools for managing software development with Claude Code, Gitea, Wiki.js, and agile methodologies.
|
||||||
|
|
||||||
|
**Status:** Planning phase complete, ready for implementation (Phase 1)
|
||||||
|
|
||||||
## Core Architecture
|
## Core Architecture
|
||||||
|
|
||||||
@@ -41,9 +43,9 @@ The plugins implement a three-agent architecture that mirrors the proven workflo
|
|||||||
|
|
||||||
### MCP Server Integration
|
### MCP Server Integration
|
||||||
|
|
||||||
Both plugins use a Gitea MCP server (`mcp-server/`) to expose Gitea API as tools:
|
Both plugins use **two shared MCP servers** at repository root level (`mcp-servers/`):
|
||||||
|
|
||||||
**Core Tools:**
|
**1. Gitea MCP Server** (Python)
|
||||||
- `list_issues` - Query issues with filters
|
- `list_issues` - Query issues with filters
|
||||||
- `get_issue` - Fetch single issue details
|
- `get_issue` - Fetch single issue details
|
||||||
- `create_issue` - Create new issue with labels
|
- `create_issue` - Create new issue with labels
|
||||||
@@ -52,7 +54,21 @@ Both plugins use a Gitea MCP server (`mcp-server/`) to expose Gitea API as tools
|
|||||||
- `get_labels` - Fetch org + repo label taxonomy
|
- `get_labels` - Fetch org + repo label taxonomy
|
||||||
- `suggest_labels` - Analyze context and suggest appropriate labels
|
- `suggest_labels` - Analyze context and suggest appropriate labels
|
||||||
|
|
||||||
Configuration lives in `.mcp.json` and uses environment variables for Gitea credentials.
|
**2. Wiki.js MCP Server** (Python, GraphQL)
|
||||||
|
- `search_pages` - Search Wiki.js pages by keywords/tags
|
||||||
|
- `get_page` - Fetch specific page content
|
||||||
|
- `create_page` - Create new Wiki page
|
||||||
|
- `update_page` - Modify existing page
|
||||||
|
- `list_pages` - List pages in a path
|
||||||
|
- `create_lesson` - Create lessons learned document
|
||||||
|
- `search_lessons` - Search past lessons by tags
|
||||||
|
- `tag_lesson` - Add tags to lessons learned
|
||||||
|
|
||||||
|
**Key Architecture Points:**
|
||||||
|
- MCP servers are **shared** by both plugins at `mcp-servers/gitea` and `mcp-servers/wikijs`
|
||||||
|
- Each MCP server detects its mode (project-scoped vs company-wide) based on environment variables
|
||||||
|
- Configuration uses hybrid approach (system-level + project-level)
|
||||||
|
- Both plugins reference `../mcp-servers/` in their `.mcp.json` files
|
||||||
|
|
||||||
## Branch-Aware Security Model
|
## Branch-Aware Security Model
|
||||||
|
|
||||||
@@ -100,20 +116,37 @@ The label system includes:
|
|||||||
|
|
||||||
**Critical Feature:** After 15 sprints without lesson capture, repeated mistakes occurred (e.g., Claude Code infinite loops on similar issues 2-3 times).
|
**Critical Feature:** After 15 sprints without lesson capture, repeated mistakes occurred (e.g., Claude Code infinite loops on similar issues 2-3 times).
|
||||||
|
|
||||||
**Structure:**
|
**Wiki.js Structure:**
|
||||||
```
|
```
|
||||||
docs/lessons-learned/
|
Wiki.js: https://wiki.hyperhivelabs.com
|
||||||
├── INDEX.md # Master index with searchable tags
|
└── /hyper-hive-labs/
|
||||||
├── sprints/ # Per-sprint lessons
|
├── projects/ # Project-specific documentation
|
||||||
├── patterns/ # Recurring patterns (deployment, architecture, Claude issues)
|
│ ├── cuisineflow/
|
||||||
└── templates/ # Lesson template
|
│ │ ├── lessons-learned/
|
||||||
|
│ │ │ ├── sprints/
|
||||||
|
│ │ │ ├── patterns/
|
||||||
|
│ │ │ └── INDEX.md
|
||||||
|
│ │ └── documentation/
|
||||||
|
│ ├── cuisineflow-site/
|
||||||
|
│ ├── intuit-engine/
|
||||||
|
│ └── hhl-site/
|
||||||
|
├── company/ # Company-wide documentation
|
||||||
|
│ ├── processes/
|
||||||
|
│ ├── standards/
|
||||||
|
│ └── tools/
|
||||||
|
└── shared/ # Cross-project resources
|
||||||
|
├── architecture-patterns/
|
||||||
|
├── best-practices/
|
||||||
|
└── tech-stack/
|
||||||
```
|
```
|
||||||
|
|
||||||
**Workflow:**
|
**Workflow:**
|
||||||
- Orchestrator captures lessons at sprint close
|
- Orchestrator captures lessons at sprint close via Wiki.js MCP
|
||||||
- Planner searches relevant lessons at sprint start
|
- Planner searches relevant lessons at sprint start using GraphQL search
|
||||||
- INDEX.md maintained automatically
|
- INDEX.md maintained automatically via Wiki.js API
|
||||||
|
- Tags enable cross-project lesson discovery
|
||||||
- Focus on preventable repetitions, not every detail
|
- Focus on preventable repetitions, not every detail
|
||||||
|
- Web interface for team review and editing
|
||||||
|
|
||||||
## Development Workflow
|
## Development Workflow
|
||||||
|
|
||||||
@@ -125,48 +158,93 @@ docs/lessons-learned/
|
|||||||
|
|
||||||
See [docs/reference-material/projman-implementation-plan.md](docs/reference-material/projman-implementation-plan.md) for the complete 12-phase implementation plan.
|
See [docs/reference-material/projman-implementation-plan.md](docs/reference-material/projman-implementation-plan.md) for the complete 12-phase implementation plan.
|
||||||
|
|
||||||
### Plugin Structure
|
### Repository Structure (DEFINITIVE)
|
||||||
|
|
||||||
|
⚠️ **See `docs/CORRECT-ARCHITECTURE.md` for the authoritative structure reference**
|
||||||
|
|
||||||
```
|
```
|
||||||
projman/
|
hyperhivelabs/claude-plugins/
|
||||||
├── .claude-plugin/
|
├── .claude-plugin/
|
||||||
│ └── plugin.json # Plugin manifest
|
│ └── marketplace.json
|
||||||
├── commands/ # Slash commands (user entry points)
|
├── mcp-servers/ # ← SHARED BY BOTH PLUGINS
|
||||||
│ ├── sprint-plan.md
|
│ ├── gitea/
|
||||||
│ ├── sprint-start.md
|
│ │ ├── .venv/
|
||||||
│ ├── sprint-status.md
|
│ │ ├── requirements.txt # Python dependencies
|
||||||
│ ├── sprint-close.md
|
│ │ ├── mcp_server/
|
||||||
│ ├── issue-create.md
|
│ │ │ ├── __init__.py
|
||||||
│ ├── issue-list.md
|
│ │ │ ├── server.py
|
||||||
│ ├── labels-sync.md
|
│ │ │ ├── config.py # Mode detection (project/company)
|
||||||
│ └── deploy-check.md
|
│ │ │ ├── gitea_client.py
|
||||||
├── agents/ # Agent personalities and workflows
|
│ │ │ └── tools/
|
||||||
│ ├── planner.md
|
│ │ │ ├── issues.py
|
||||||
│ ├── orchestrator.md
|
│ │ │ └── labels.py
|
||||||
│ └── executor.md
|
│ │ └── tests/
|
||||||
├── skills/ # Supporting knowledge (not orchestrators)
|
│ └── wikijs/
|
||||||
│ ├── gitea-api/
|
│ ├── .venv/
|
||||||
│ ├── label-taxonomy/
|
│ ├── requirements.txt # Python + GraphQL dependencies
|
||||||
│ ├── lessons-learned/
|
│ ├── mcp_server/
|
||||||
│ ├── agile-pm/
|
│ │ ├── __init__.py
|
||||||
│ └── branch-strategy/
|
│ │ ├── server.py
|
||||||
├── hooks/ # Automation (post-task sync, staging guards)
|
│ │ ├── config.py # Mode detection (project/company)
|
||||||
│ └── hooks.json
|
│ │ ├── wikijs_client.py # GraphQL client
|
||||||
├── .mcp.json # MCP server configuration
|
│ │ └── tools/
|
||||||
├── mcp-server/ # Gitea API integration
|
│ │ ├── pages.py
|
||||||
│ ├── package.json
|
│ │ ├── lessons_learned.py
|
||||||
│ ├── tsconfig.json
|
│ │ └── documentation.py
|
||||||
│ └── src/
|
│ └── tests/
|
||||||
└── README.md
|
├── projman/ # ← PROJECT PLUGIN
|
||||||
|
│ ├── .claude-plugin/
|
||||||
|
│ │ └── plugin.json
|
||||||
|
│ ├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
│ ├── commands/
|
||||||
|
│ │ ├── sprint-plan.md
|
||||||
|
│ │ ├── sprint-start.md
|
||||||
|
│ │ ├── sprint-status.md
|
||||||
|
│ │ ├── sprint-close.md
|
||||||
|
│ │ └── labels-sync.md
|
||||||
|
│ ├── agents/
|
||||||
|
│ │ ├── planner.md
|
||||||
|
│ │ ├── orchestrator.md
|
||||||
|
│ │ └── executor.md
|
||||||
|
│ ├── skills/
|
||||||
|
│ │ └── label-taxonomy/
|
||||||
|
│ │ └── labels-reference.md
|
||||||
|
│ ├── README.md
|
||||||
|
│ └── CONFIGURATION.md
|
||||||
|
└── projman-pmo/ # ← PMO PLUGIN
|
||||||
|
├── .claude-plugin/
|
||||||
|
│ └── plugin.json
|
||||||
|
├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
├── commands/
|
||||||
|
│ ├── pmo-status.md
|
||||||
|
│ ├── pmo-priorities.md
|
||||||
|
│ ├── pmo-dependencies.md
|
||||||
|
│ └── pmo-schedule.md
|
||||||
|
├── agents/
|
||||||
|
│ └── pmo-coordinator.md
|
||||||
|
└── README.md
|
||||||
```
|
```
|
||||||
|
|
||||||
### Key Design Decisions
|
### Key Design Decisions
|
||||||
|
|
||||||
**MCP vs Direct API:**
|
**Two MCP Servers (Shared Architecture):**
|
||||||
- Use MCP Server for Gitea integration
|
- **Gitea MCP**: Issues, labels, repository management
|
||||||
- Allows agents to use tools naturally in conversation
|
- **Wiki.js MCP**: Documentation, lessons learned, knowledge base
|
||||||
- Easier to test independently
|
- Servers are **shared** between both plugins at repository root
|
||||||
- Future-proof for additional integrations
|
- Mode detection based on environment variables (project vs company-wide)
|
||||||
|
- Benefits: Single source of truth, fix bugs once, professional architecture
|
||||||
|
|
||||||
|
**Python Implementation:**
|
||||||
|
- Python chosen over Node.js for MCP servers
|
||||||
|
- Better suited for configuration management and modular code
|
||||||
|
- Easier to maintain and extend
|
||||||
|
- Virtual environment (.venv) per MCP server
|
||||||
|
|
||||||
|
**Hybrid Configuration:**
|
||||||
|
- **System-level**: `~/.config/claude/gitea.env` and `wikijs.env` (credentials)
|
||||||
|
- **Project-level**: `project-root/.env` (repository and path specification)
|
||||||
|
- Merge strategy: project overrides system
|
||||||
|
- Benefits: Single token per service, easy multi-project setup
|
||||||
|
|
||||||
**Skills as Knowledge, Not Orchestrators:**
|
**Skills as Knowledge, Not Orchestrators:**
|
||||||
- Skills provide supporting knowledge loaded when relevant
|
- Skills provide supporting knowledge loaded when relevant
|
||||||
@@ -188,18 +266,24 @@ projman/
|
|||||||
|
|
||||||
## Multi-Project Context (PMO Plugin)
|
## Multi-Project Context (PMO Plugin)
|
||||||
|
|
||||||
The `pmo` plugin will coordinate interdependent projects:
|
The `projman-pmo` plugin will coordinate interdependent projects:
|
||||||
- **CuisineFlow** - Main product
|
- **CuisineFlow** - Main product
|
||||||
- **CuisineFlow-Site** - Demo sync + customer gateway
|
- **CuisineFlow-Site** - Demo sync + customer gateway
|
||||||
- **Intuit Engine Service** - API aggregator extraction (imminent)
|
- **Intuit Engine Service** - API aggregator extraction (imminent)
|
||||||
- **HHL-Site** - Company presence
|
- **HHL-Site** - Company presence
|
||||||
|
|
||||||
PMO plugin adds:
|
PMO plugin adds:
|
||||||
- Cross-project issue aggregation
|
- Cross-project issue aggregation (all repos in organization)
|
||||||
- Dependency tracking and visualization
|
- Dependency tracking and visualization
|
||||||
- Resource allocation across projects
|
- Resource allocation across projects
|
||||||
- Deployment coordination
|
- Deployment coordination
|
||||||
- Multi-project prioritization
|
- Multi-project prioritization
|
||||||
|
- Company-wide lessons learned search
|
||||||
|
|
||||||
|
**Configuration Difference:**
|
||||||
|
- PMO operates at company level (no `GITEA_REPO` or `WIKIJS_PROJECT`)
|
||||||
|
- Accesses entire `/hyper-hive-labs` Wiki.js namespace
|
||||||
|
- Queries all repositories in organization
|
||||||
|
|
||||||
Build PMO plugin AFTER projman is working and validated.
|
Build PMO plugin AFTER projman is working and validated.
|
||||||
|
|
||||||
@@ -231,3 +315,43 @@ Test in real CuisineFlow repository with actual Gitea instance before distributi
|
|||||||
- **Lessons learned is critical** - Prevents repeated mistakes (e.g., Claude infinite loops)
|
- **Lessons learned is critical** - Prevents repeated mistakes (e.g., Claude infinite loops)
|
||||||
- **Type/Refactor label** - Newly implemented at org level for architectural work
|
- **Type/Refactor label** - Newly implemented at org level for architectural work
|
||||||
- **Branch detection must be 100% reliable** - Prevents production accidents
|
- **Branch detection must be 100% reliable** - Prevents production accidents
|
||||||
|
- **Python for MCP servers** - Use Python 3.8+ with virtual environments
|
||||||
|
- **Wiki.js structure** - All HHL content under `/hyper-hive-labs` namespace
|
||||||
|
|
||||||
|
## Documentation Index
|
||||||
|
|
||||||
|
This repository contains comprehensive planning documentation:
|
||||||
|
|
||||||
|
- **`docs/CORRECT-ARCHITECTURE.md`** - ⚠️ DEFINITIVE repository structure reference
|
||||||
|
- **`docs/DOCUMENT-INDEX.md`** - Complete guide to all planning documents
|
||||||
|
- **`docs/projman-implementation-plan-updated.md`** - Full 12-phase implementation plan
|
||||||
|
- **`docs/projman-python-quickstart.md`** - Python-specific implementation guide
|
||||||
|
- **`docs/two-mcp-architecture-guide.md`** - Deep dive into two-MCP architecture
|
||||||
|
|
||||||
|
**Start with:** `docs/DOCUMENT-INDEX.md` for navigation guidance
|
||||||
|
|
||||||
|
## Recent Updates (Updated: 2025-06-11)
|
||||||
|
|
||||||
|
### Planning Phase Complete
|
||||||
|
- Comprehensive 12-phase implementation plan finalized
|
||||||
|
- Architecture decisions documented and validated
|
||||||
|
- Two-MCP-server approach confirmed (Gitea + Wiki.js)
|
||||||
|
- Python selected for MCP server implementation
|
||||||
|
- Hybrid configuration strategy defined (system + project level)
|
||||||
|
- Wiki.js structure planned at `/hyper-hive-labs`
|
||||||
|
- Repository structure designed with shared MCP servers
|
||||||
|
- `claude-plugin-developer` skill added to project
|
||||||
|
|
||||||
|
### Key Architectural Decisions Made
|
||||||
|
1. **Shared MCP Servers**: Both plugins use the same MCP codebase at `mcp-servers/`
|
||||||
|
2. **Mode Detection**: MCP servers detect project vs company-wide mode via environment variables
|
||||||
|
3. **Python Implementation**: MCP servers written in Python (not Node.js) for better configuration handling
|
||||||
|
4. **Wiki.js Integration**: Lessons learned and documentation moved to Wiki.js for better collaboration
|
||||||
|
5. **Hybrid Config**: System-level credentials + project-level paths for flexibility
|
||||||
|
|
||||||
|
### Next Steps
|
||||||
|
- Begin Phase 1.1a: Gitea MCP Server implementation
|
||||||
|
- Set up Python virtual environments
|
||||||
|
- Create configuration loaders
|
||||||
|
- Implement core Gitea tools (issues, labels)
|
||||||
|
- Write integration tests
|
||||||
|
|||||||
File diff suppressed because it is too large
Load Diff
@@ -1,636 +0,0 @@
|
|||||||
# ProjMan Plugin: Analysis & Design
|
|
||||||
|
|
||||||
## Executive Summary
|
|
||||||
|
|
||||||
Leo has built a sophisticated, working project management system over 15 sprints using:
|
|
||||||
- **Skills** for behavioral guidance
|
|
||||||
- **Python scripts** for Gitea API interaction
|
|
||||||
- **CLAUDE.md** for branch-aware permission control
|
|
||||||
|
|
||||||
**Goal:** Transform this proven system into a reusable, distributable plugin called `projman`.
|
|
||||||
|
|
||||||
## Current System Analysis
|
|
||||||
|
|
||||||
### What's Working Well
|
|
||||||
|
|
||||||
**1. Three-Chat Architecture**
|
|
||||||
- **Chat 0** (Claude Web): Planning & architecture → generates sprint documents
|
|
||||||
- **Chat 1** (Claude Code): Orchestration → manages branches, generates prompts, tracks progress
|
|
||||||
- **Chat 2+** (Claude Code): Execution → implements features according to prompts
|
|
||||||
|
|
||||||
**2. Branch-Aware Security**
|
|
||||||
```
|
|
||||||
development → Full access
|
|
||||||
feat/* → Full access
|
|
||||||
staging → Read-only code, can modify .env, creates issues
|
|
||||||
main → Read-only code, emergency .env only, creates issues
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Gitea Integration**
|
|
||||||
- Two Python scripts: `create_gitea_issue.py` and `list_gitea_issues.py`
|
|
||||||
- Proper API authentication via environment variables
|
|
||||||
- Structured issue creation with labels, priority, affected files
|
|
||||||
|
|
||||||
**4. Skills System**
|
|
||||||
- `sprint-workflow.md` - Planning phase (Chat 0)
|
|
||||||
- `sprint-orchestrator.md` - Coordination phase (Chat 1)
|
|
||||||
- `sprint-executor.md` - Implementation phase (Chat 2+)
|
|
||||||
- `post-task-doc-sync.md` - Documentation updates
|
|
||||||
- `incident-reporter.md` - Issue creation from staging/prod
|
|
||||||
|
|
||||||
### What Feels Messy
|
|
||||||
|
|
||||||
Leo identified these friction points:
|
|
||||||
|
|
||||||
**1. Skills vs Agents Confusion**
|
|
||||||
> "I don't think skill would be the best way of handling an Agent"
|
|
||||||
|
|
||||||
Current state: Using skills to guide behavior that should be agent personalities
|
|
||||||
|
|
||||||
**2. Manual Script Invocation**
|
|
||||||
Scripts exist but require manual execution:
|
|
||||||
```bash
|
|
||||||
python ops/scripts/create_gitea_issue.py --title "..." --problem "..." ...
|
|
||||||
python ops/scripts/list_gitea_issues.py
|
|
||||||
```
|
|
||||||
|
|
||||||
**3. Mode Detection Redundancy**
|
|
||||||
Branch detection logic is duplicated across:
|
|
||||||
- CLAUDE.md
|
|
||||||
- Each skill file
|
|
||||||
- Manual checks in workflows
|
|
||||||
|
|
||||||
**4. Context Switching Overhead**
|
|
||||||
User must manually:
|
|
||||||
- Switch between chats
|
|
||||||
- Remember which skill to load where
|
|
||||||
- Copy/paste completion reports between chats
|
|
||||||
|
|
||||||
## Plugin Architecture Design
|
|
||||||
|
|
||||||
### Core Insight: The 3-Agent Model
|
|
||||||
|
|
||||||
Transform the three chats into three distinct agents:
|
|
||||||
|
|
||||||
```
|
|
||||||
projman/
|
|
||||||
├── agents/
|
|
||||||
│ ├── planner.md # Chat 0 → Planning Agent
|
|
||||||
│ ├── orchestrator.md # Chat 1 → PM Agent
|
|
||||||
│ └── executor.md # Chat 2+ → Implementation Agent
|
|
||||||
```
|
|
||||||
|
|
||||||
### Component Breakdown
|
|
||||||
|
|
||||||
#### 1. MCP Server: `gitea-mcp`
|
|
||||||
|
|
||||||
**Purpose:** Provide Gitea API access as tools that agents can use
|
|
||||||
|
|
||||||
**Tools to expose:**
|
|
||||||
```typescript
|
|
||||||
{
|
|
||||||
"list_issues": {
|
|
||||||
state: "open" | "closed" | "all",
|
|
||||||
labels: string[],
|
|
||||||
assignee: string
|
|
||||||
},
|
|
||||||
"create_issue": {
|
|
||||||
title: string,
|
|
||||||
body: string,
|
|
||||||
labels: string[],
|
|
||||||
assignee: string,
|
|
||||||
priority: "critical" | "high" | "medium" | "low"
|
|
||||||
},
|
|
||||||
"update_issue": {
|
|
||||||
number: number,
|
|
||||||
state: "open" | "closed",
|
|
||||||
body: string,
|
|
||||||
labels: string[]
|
|
||||||
},
|
|
||||||
"get_issue": {
|
|
||||||
number: number
|
|
||||||
},
|
|
||||||
"add_comment": {
|
|
||||||
number: number,
|
|
||||||
body: string
|
|
||||||
},
|
|
||||||
"get_labels": {
|
|
||||||
// Fetches all org + repo labels with metadata
|
|
||||||
include_org: boolean,
|
|
||||||
include_repo: boolean
|
|
||||||
},
|
|
||||||
"suggest_labels": {
|
|
||||||
// Analyzes context and suggests appropriate labels
|
|
||||||
issue_body: string,
|
|
||||||
context: {
|
|
||||||
branch: string,
|
|
||||||
files_changed: string[],
|
|
||||||
is_bug: boolean,
|
|
||||||
components: string[]
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
**Configuration:** `.mcp.json`
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"mcpServers": {
|
|
||||||
"gitea": {
|
|
||||||
"command": "node",
|
|
||||||
"args": ["mcp-server/gitea-server.js"],
|
|
||||||
"env": {
|
|
||||||
"GITEA_URL": "${GITEA_URL}",
|
|
||||||
"GITEA_OWNER": "${GITEA_OWNER}",
|
|
||||||
"GITEA_REPO": "${GITEA_REPO}",
|
|
||||||
"GITEA_API_TOKEN": "${GITEA_API_TOKEN}"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 2. Slash Commands
|
|
||||||
|
|
||||||
**Primary commands for user interaction:**
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
commands/
|
|
||||||
├── sprint-plan.md # /sprint-plan - Start planning a new sprint
|
|
||||||
├── sprint-start.md # /sprint-start - Begin sprint execution
|
|
||||||
├── sprint-status.md # /sprint-status - Check current sprint progress
|
|
||||||
├── sprint-close.md # /sprint-close - Complete sprint, capture lessons learned
|
|
||||||
├── issue-create.md # /issue-create - Quick issue creation
|
|
||||||
├── issue-list.md # /issue-list - List issues with filters
|
|
||||||
├── labels-sync.md # /labels-sync - Sync label taxonomy from Gitea
|
|
||||||
└── deploy-check.md # /deploy-check - Staging/prod environment validation
|
|
||||||
```
|
|
||||||
|
|
||||||
**Example: `/labels-sync`**
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
name: labels-sync
|
|
||||||
description: Sync label taxonomy from Gitea and review changes
|
|
||||||
agent: planner
|
|
||||||
---
|
|
||||||
|
|
||||||
You are updating the plugin's label reference from Gitea.
|
|
||||||
|
|
||||||
**Workflow:**
|
|
||||||
1. Fetch current labels from Gitea (org + repo)
|
|
||||||
2. Compare with local reference (skills/label-taxonomy/labels-reference.md)
|
|
||||||
3. Show user a diff of changes:
|
|
||||||
- New labels added
|
|
||||||
- Labels removed
|
|
||||||
- Description/color changes
|
|
||||||
4. Discuss impact: "The new Type/Refactor label means we should update suggestion logic for architectural changes"
|
|
||||||
5. After approval, update local reference
|
|
||||||
6. Update label suggestion rules if needed
|
|
||||||
|
|
||||||
This ensures the plugin stays in sync with your evolving label system.
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 3. Agents
|
|
||||||
|
|
||||||
**Agent: `planner.md`**
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
name: planner
|
|
||||||
description: Architecture analysis and sprint planning expert
|
|
||||||
---
|
|
||||||
|
|
||||||
You are the Planning Agent for project management.
|
|
||||||
|
|
||||||
**Your Role:**
|
|
||||||
- Analyze business requirements
|
|
||||||
- Make architectural decisions
|
|
||||||
- Break work into implementation steps
|
|
||||||
- Generate sprint planning documents
|
|
||||||
- Create Gitea issues for approved plans
|
|
||||||
|
|
||||||
**Your Personality:**
|
|
||||||
- Ask clarifying questions upfront
|
|
||||||
- Think through edge cases
|
|
||||||
- Consider architectural fit
|
|
||||||
- Document risks explicitly
|
|
||||||
- Never rush to implementation
|
|
||||||
|
|
||||||
**Your Tools:**
|
|
||||||
- gitea.create_issue - Create issues after approval
|
|
||||||
- gitea.list_issues - Check for similar existing issues
|
|
||||||
|
|
||||||
**Branch Awareness:**
|
|
||||||
${BRANCH_DETECTION_LOGIC}
|
|
||||||
|
|
||||||
**Workflow:**
|
|
||||||
[... rest of sprint-workflow.md content ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Agent: `orchestrator.md`**
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
name: orchestrator
|
|
||||||
description: Sprint execution coordinator and progress tracker
|
|
||||||
---
|
|
||||||
|
|
||||||
You are the Orchestrator Agent for project management.
|
|
||||||
|
|
||||||
**Your Role:**
|
|
||||||
- Manage sprint execution
|
|
||||||
- Generate lean execution prompts
|
|
||||||
- Track progress and update documentation
|
|
||||||
- Handle Git operations (commit, merge, cleanup)
|
|
||||||
- Coordinate task dependencies
|
|
||||||
|
|
||||||
**Your Personality:**
|
|
||||||
- Concise and action-oriented
|
|
||||||
- Track details meticulously
|
|
||||||
- Signal next steps clearly
|
|
||||||
- Never write application code yourself
|
|
||||||
|
|
||||||
**Your Tools:**
|
|
||||||
- gitea.get_issue - Read issue details
|
|
||||||
- gitea.update_issue - Update issue status
|
|
||||||
- gitea.add_comment - Add progress notes
|
|
||||||
|
|
||||||
**Branch Awareness:**
|
|
||||||
${BRANCH_DETECTION_LOGIC}
|
|
||||||
|
|
||||||
**Workflow:**
|
|
||||||
[... rest of sprint-orchestrator.md content ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
**Agent: `executor.md`**
|
|
||||||
```markdown
|
|
||||||
---
|
|
||||||
name: executor
|
|
||||||
description: Feature implementation and code execution specialist
|
|
||||||
---
|
|
||||||
|
|
||||||
You are the Executor Agent for project management.
|
|
||||||
|
|
||||||
**Your Role:**
|
|
||||||
- Implement features according to execution prompts
|
|
||||||
- Write clean, tested code
|
|
||||||
- Follow architectural decisions from planning
|
|
||||||
- Generate completion reports for orchestrator
|
|
||||||
|
|
||||||
**Your Personality:**
|
|
||||||
- Implementation-focused
|
|
||||||
- Follow specs precisely
|
|
||||||
- Test as you build
|
|
||||||
- Report blockers immediately
|
|
||||||
|
|
||||||
**Your Tools:**
|
|
||||||
- None (uses standard code tools)
|
|
||||||
|
|
||||||
**Branch Awareness:**
|
|
||||||
${BRANCH_DETECTION_LOGIC}
|
|
||||||
|
|
||||||
**Workflow:**
|
|
||||||
[... rest of sprint-executor.md content ...]
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 4. Skills
|
|
||||||
|
|
||||||
Skills become **supporting knowledge** rather than primary orchestrators:
|
|
||||||
|
|
||||||
```markdown
|
|
||||||
skills/
|
|
||||||
├── gitea-api/
|
|
||||||
│ └── SKILL.md # How to use Gitea MCP server effectively
|
|
||||||
├── agile-pm/
|
|
||||||
│ └── SKILL.md # Agile/PMP best practices
|
|
||||||
└── branch-strategy/
|
|
||||||
└── SKILL.MD # Git branching workflow
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 5. Hooks
|
|
||||||
|
|
||||||
Automate repetitive actions:
|
|
||||||
|
|
||||||
```json
|
|
||||||
{
|
|
||||||
"hooks": [
|
|
||||||
{
|
|
||||||
"name": "post-task-sync",
|
|
||||||
"event": "task_completed",
|
|
||||||
"action": "run_command",
|
|
||||||
"command": "update-docs",
|
|
||||||
"description": "Sync documentation after task completion"
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"name": "staging-incident",
|
|
||||||
"event": "file_changed",
|
|
||||||
"filter": {
|
|
||||||
"branch": "staging",
|
|
||||||
"paths": ["src/**/*.py", "src/**/*.js"]
|
|
||||||
},
|
|
||||||
"action": "warn",
|
|
||||||
"message": "⚠️ Code changes on staging branch. Consider creating issue instead."
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### Environment-Aware Behavior
|
|
||||||
|
|
||||||
**Key Design Decision:** Plugin behavior adapts to Git branch
|
|
||||||
|
|
||||||
```typescript
|
|
||||||
// Branch detection in plugin
|
|
||||||
const CURRENT_BRANCH = getCurrentBranch();
|
|
||||||
const MODE = detectMode(CURRENT_BRANCH);
|
|
||||||
|
|
||||||
// Modify agent permissions based on mode
|
|
||||||
switch (MODE) {
|
|
||||||
case 'DEVELOPMENT':
|
|
||||||
// Full access
|
|
||||||
agents.planner.allowGiteaAPI = true;
|
|
||||||
agents.orchestrator.allowFileWrite = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'STAGING':
|
|
||||||
// Read-only code, can modify .env, can create issues
|
|
||||||
agents.planner.allowGiteaAPI = true;
|
|
||||||
agents.orchestrator.allowFileWrite = false;
|
|
||||||
agents.orchestrator.allowEnvWrite = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'PRODUCTION':
|
|
||||||
// Emergency mode only
|
|
||||||
agents.planner.allowGiteaAPI = true; // Create incidents
|
|
||||||
agents.orchestrator.allowFileWrite = false;
|
|
||||||
agents.orchestrator.allowEnvWrite = true; // Emergency only
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## Migration Strategy
|
|
||||||
|
|
||||||
### Phase 1: MCP Server (Week 1)
|
|
||||||
|
|
||||||
**Goal:** Replace Python scripts with MCP server
|
|
||||||
|
|
||||||
**Tasks:**
|
|
||||||
1. Build `gitea-mcp` server in Node.js/TypeScript
|
|
||||||
2. Implement 5 core tools (list, create, update, get, comment)
|
|
||||||
3. Test with environment variables from CuisineFlow
|
|
||||||
4. Verify equivalent functionality to existing scripts
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
- MCP server can create issues identical to `create_gitea_issue.py`
|
|
||||||
- MCP server can list issues identical to `list_gitea_issues.py`
|
|
||||||
- No regression in functionality
|
|
||||||
|
|
||||||
### Phase 2: Agents (Week 2)
|
|
||||||
|
|
||||||
**Goal:** Convert skills to agents
|
|
||||||
|
|
||||||
**Tasks:**
|
|
||||||
1. Create `agents/planner.md` from `sprint-workflow.md`
|
|
||||||
2. Create `agents/orchestrator.md` from `sprint-orchestrator.md`
|
|
||||||
3. Create `agents/executor.md` from `sprint-executor.md`
|
|
||||||
4. Add agent-specific tool permissions
|
|
||||||
5. Test agent invocation via commands
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
- `/sprint-plan` invokes planner agent correctly
|
|
||||||
- `/sprint-start` invokes orchestrator agent correctly
|
|
||||||
- Agents have distinct personalities and tool access
|
|
||||||
|
|
||||||
### Phase 3: Commands (Week 2-3)
|
|
||||||
|
|
||||||
**Goal:** Create user-facing slash commands
|
|
||||||
|
|
||||||
**Tasks:**
|
|
||||||
1. Build 6 core commands (plan, start, status, issue-create, issue-list, deploy-check)
|
|
||||||
2. Connect commands to agents
|
|
||||||
3. Add branch detection to command behavior
|
|
||||||
4. Test command flow end-to-end
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
- Commands invoke correct agents
|
|
||||||
- Branch restrictions work automatically
|
|
||||||
- User workflow feels natural
|
|
||||||
|
|
||||||
### Phase 4: Hooks (Week 3)
|
|
||||||
|
|
||||||
**Goal:** Automate repetitive tasks
|
|
||||||
|
|
||||||
**Tasks:**
|
|
||||||
1. Implement post-task documentation sync
|
|
||||||
2. Add staging/production code change warnings
|
|
||||||
3. Auto-update issue status on merge
|
|
||||||
4. Test hook reliability
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
- Hooks trigger at correct moments
|
|
||||||
- No false positives
|
|
||||||
- Improve workflow efficiency
|
|
||||||
|
|
||||||
### Phase 5: Skills Refactor (Week 4)
|
|
||||||
|
|
||||||
**Goal:** Convert orchestration skills to supporting knowledge
|
|
||||||
|
|
||||||
**Tasks:**
|
|
||||||
1. Extract Gitea API patterns → `skills/gitea-api/SKILL.md`
|
|
||||||
2. Extract PM best practices → `skills/agile-pm/SKILL.md`
|
|
||||||
3. Extract Git workflows → `skills/branch-strategy/SKILL.md`
|
|
||||||
4. Remove duplication from agent prompts
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
- Skills are referenced by agents, not primary orchestrators
|
|
||||||
- Less token usage per interaction
|
|
||||||
- Knowledge is reusable across agents
|
|
||||||
|
|
||||||
### Phase 6: Local Testing (Week 4)
|
|
||||||
|
|
||||||
**Goal:** Validate entire plugin in CuisineFlow
|
|
||||||
|
|
||||||
**Tasks:**
|
|
||||||
1. Create local marketplace for testing
|
|
||||||
2. Install plugin in CuisineFlow project
|
|
||||||
3. Run through complete sprint cycle
|
|
||||||
4. Compare to current workflow
|
|
||||||
5. Fix issues and iterate
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
- Plugin performs equivalently to current system
|
|
||||||
- Workflow feels smoother, not worse
|
|
||||||
- No major regressions
|
|
||||||
|
|
||||||
### Phase 7: Distribution (Week 5)
|
|
||||||
|
|
||||||
**Goal:** Package for others to use
|
|
||||||
|
|
||||||
**Tasks:**
|
|
||||||
1. Write comprehensive README
|
|
||||||
2. Add installation instructions
|
|
||||||
3. Document configuration requirements
|
|
||||||
4. Create example `.env` template
|
|
||||||
5. Publish to plugin marketplace
|
|
||||||
|
|
||||||
**Success Criteria:**
|
|
||||||
- Someone else can install and use it
|
|
||||||
- Clear documentation
|
|
||||||
- Configuration is straightforward
|
|
||||||
|
|
||||||
## Directory Structure
|
|
||||||
|
|
||||||
```
|
|
||||||
projman/
|
|
||||||
├── .claude-plugin/
|
|
||||||
│ └── plugin.json
|
|
||||||
├── commands/
|
|
||||||
│ ├── sprint-plan.md
|
|
||||||
│ ├── sprint-start.md
|
|
||||||
│ ├── sprint-status.md
|
|
||||||
│ ├── issue-create.md
|
|
||||||
│ ├── issue-list.md
|
|
||||||
│ └── deploy-check.md
|
|
||||||
├── agents/
|
|
||||||
│ ├── planner.md
|
|
||||||
│ ├── orchestrator.md
|
|
||||||
│ └── executor.md
|
|
||||||
├── skills/
|
|
||||||
│ ├── gitea-api/
|
|
||||||
│ │ └── SKILL.md
|
|
||||||
│ ├── agile-pm/
|
|
||||||
│ │ └── SKILL.md
|
|
||||||
│ └── branch-strategy/
|
|
||||||
│ └── SKILL.md
|
|
||||||
├── hooks/
|
|
||||||
│ └── hooks.json
|
|
||||||
├── .mcp.json
|
|
||||||
├── mcp-server/
|
|
||||||
│ ├── package.json
|
|
||||||
│ ├── tsconfig.json
|
|
||||||
│ ├── gitea-server.ts
|
|
||||||
│ └── types.ts
|
|
||||||
├── README.md
|
|
||||||
├── LICENSE
|
|
||||||
└── CHANGELOG.md
|
|
||||||
```
|
|
||||||
|
|
||||||
## Key Decisions
|
|
||||||
|
|
||||||
### Decision 1: MCP vs Direct API Calls in Commands
|
|
||||||
|
|
||||||
**Choice:** Use MCP Server
|
|
||||||
|
|
||||||
**Rationale:**
|
|
||||||
- Agents can use tools naturally in conversation
|
|
||||||
- Easier to test MCP server independently
|
|
||||||
- Future-proof for adding more integrations (Asana, Linear)
|
|
||||||
- Follows Claude Code best practices
|
|
||||||
|
|
||||||
### Decision 2: Three Agents vs One Agent with Modes
|
|
||||||
|
|
||||||
**Choice:** Three Distinct Agents
|
|
||||||
|
|
||||||
**Rationale:**
|
|
||||||
- Clear separation of concerns matches Leo's three-chat workflow
|
|
||||||
- Each agent has distinct personality and tool access
|
|
||||||
- User knows exactly which agent they're talking to
|
|
||||||
- Prevents mode confusion
|
|
||||||
|
|
||||||
### Decision 3: Branch Detection in Plugin vs CLAUDE.md
|
|
||||||
|
|
||||||
**Choice:** Both
|
|
||||||
|
|
||||||
**Rationale:**
|
|
||||||
- CLAUDE.md provides base-level permissions (file access)
|
|
||||||
- Plugin agents adapt behavior based on branch (tool usage)
|
|
||||||
- Defense in depth - two layers of protection
|
|
||||||
- Plugin works with or without CLAUDE.md
|
|
||||||
|
|
||||||
### Decision 4: Skills as Orchestrators vs Knowledge
|
|
||||||
|
|
||||||
**Choice:** Skills as Supporting Knowledge
|
|
||||||
|
|
||||||
**Rationale:**
|
|
||||||
- Agents are the primary interface
|
|
||||||
- Skills reduce token usage (loaded only when relevant)
|
|
||||||
- Skills can be shared across agents
|
|
||||||
- Follows Anthropic's Agent Skills spec
|
|
||||||
|
|
||||||
## Validated Requirements from Leo
|
|
||||||
|
|
||||||
**Q1: Asana Integration**
|
|
||||||
- ✅ Build Gitea-only first, add Asana as separate MCP server later
|
|
||||||
|
|
||||||
**Q2: Agent Invocation**
|
|
||||||
- ✅ Via commands only (`/sprint-plan` → planner agent)
|
|
||||||
|
|
||||||
**Q3: Multi-Project Support**
|
|
||||||
- ✅ Two plugins needed:
|
|
||||||
- `projman`: Single-repo project management (build first)
|
|
||||||
- `projman-pmo`: Multi-project orchestration (build second)
|
|
||||||
- **Context:** Leo manages interdependent projects:
|
|
||||||
- CuisineFlow (main product)
|
|
||||||
- CuisineFlow-Site (demo sync + customer gateway)
|
|
||||||
- Intuit Engine Service (API aggregator extraction - imminent)
|
|
||||||
- HHL-Site (company presence)
|
|
||||||
- These have real deployment dependencies and require coordination
|
|
||||||
|
|
||||||
**Q4: Deployment Environment**
|
|
||||||
- ✅ Same plugin on laptop + VPS servers, branch-aware behavior handles differences
|
|
||||||
|
|
||||||
**Q5: Label System**
|
|
||||||
- ✅ Leo has sophisticated 43-label taxonomy at org level (enforced consistency)
|
|
||||||
- ✅ Include label suggestion in v1
|
|
||||||
- ✅ Plugin maintains local reference, syncs from Gitea with agent review
|
|
||||||
|
|
||||||
**Q6: Lessons Learned**
|
|
||||||
- ✅ Wiki-based implementation in v1 (NOT v2)
|
|
||||||
- **Critical pain point:** 15 sprints with no lesson capture causing repeated mistakes
|
|
||||||
- **Real example:** Claude Code infinite loops on same issues 2-3 times
|
|
||||||
- Must capture at sprint close, reference at sprint start
|
|
||||||
|
|
||||||
## Success Metrics
|
|
||||||
|
|
||||||
**Technical:**
|
|
||||||
- ✅ MCP server passes all integration tests
|
|
||||||
- ✅ Agents invoke correctly via commands
|
|
||||||
- ✅ Branch detection works 100% reliably
|
|
||||||
- ✅ No token usage increase vs current system
|
|
||||||
|
|
||||||
**User Experience:**
|
|
||||||
- ✅ Leo completes sprint cycle faster than before
|
|
||||||
- ✅ Less context switching between chats
|
|
||||||
- ✅ Fewer manual script invocations
|
|
||||||
- ✅ Clearer agent personalities
|
|
||||||
|
|
||||||
**Distribution:**
|
|
||||||
- ✅ Another PM can install and use it
|
|
||||||
- ✅ Documentation is clear enough
|
|
||||||
- ✅ Configuration takes <10 minutes
|
|
||||||
|
|
||||||
## Next Steps
|
|
||||||
|
|
||||||
**Immediate (Today):**
|
|
||||||
1. Leo reviews this analysis
|
|
||||||
2. Answer open questions (Q1-Q4)
|
|
||||||
3. Decide: build MCP server first or start with agents?
|
|
||||||
|
|
||||||
**Short-term (This Week):**
|
|
||||||
1. Begin Phase 1 (MCP server) OR Phase 2 (agents)
|
|
||||||
2. Set up local marketplace for testing
|
|
||||||
3. Create `plugin.json` manifest
|
|
||||||
|
|
||||||
**Medium-term (Next 2 Weeks):**
|
|
||||||
1. Complete Phases 1-4 (MCP, agents, commands, hooks)
|
|
||||||
2. Test in real CuisineFlow sprint
|
|
||||||
3. Iterate based on friction points
|
|
||||||
|
|
||||||
## Anti-Over-Engineering Checklist
|
|
||||||
|
|
||||||
Before building anything, verify:
|
|
||||||
- [ ] Have we done this manually 3+ times? ✅ (15 sprints)
|
|
||||||
- [ ] Is current system actually broken? ✅ (messy, but Leo identified pain points)
|
|
||||||
- [ ] Will plugin reduce friction? ✅ (fewer manual steps, clearer roles)
|
|
||||||
- [ ] Can we build incrementally? ✅ (7-phase plan)
|
|
||||||
- [ ] Is scope contained? ✅ (Gitea only, not all possible features)
|
|
||||||
|
|
||||||
**Verdict:** This plugin is justified. Proceed with confidence.
|
|
||||||
325
docs/references/projman-pmo/CORRECT-ARCHITECTURE.md
Normal file
325
docs/references/projman-pmo/CORRECT-ARCHITECTURE.md
Normal file
@@ -0,0 +1,325 @@
|
|||||||
|
# DEFINITIVE ARCHITECTURE - FINAL CORRECT VERSION
|
||||||
|
|
||||||
|
## ⚠️ THIS IS THE ONLY CORRECT STRUCTURE ⚠️
|
||||||
|
|
||||||
|
If you see ANY other structure in ANY other document, **THIS ONE IS CORRECT**.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Repository Structure (FINAL)
|
||||||
|
|
||||||
|
```
|
||||||
|
your-gitea/hyperhivelabs/claude-plugins/
|
||||||
|
├── .claude-plugin/
|
||||||
|
│ └── marketplace.json
|
||||||
|
├── mcp-servers/ # ← SHARED BY BOTH PLUGINS
|
||||||
|
│ ├── gitea/
|
||||||
|
│ │ ├── .venv/
|
||||||
|
│ │ ├── requirements.txt
|
||||||
|
│ │ ├── mcp_server/
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── server.py
|
||||||
|
│ │ │ ├── config.py
|
||||||
|
│ │ │ ├── gitea_client.py
|
||||||
|
│ │ │ └── tools/
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── issues.py
|
||||||
|
│ │ │ └── labels.py
|
||||||
|
│ │ └── tests/
|
||||||
|
│ │ ├── test_config.py
|
||||||
|
│ │ ├── test_gitea_client.py
|
||||||
|
│ │ └── test_tools.py
|
||||||
|
│ └── wikijs/
|
||||||
|
│ ├── .venv/
|
||||||
|
│ ├── requirements.txt
|
||||||
|
│ ├── mcp_server/
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ ├── server.py
|
||||||
|
│ │ ├── config.py
|
||||||
|
│ │ ├── wikijs_client.py
|
||||||
|
│ │ └── tools/
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ ├── pages.py
|
||||||
|
│ │ ├── lessons_learned.py
|
||||||
|
│ │ └── documentation.py
|
||||||
|
│ └── tests/
|
||||||
|
│ ├── test_config.py
|
||||||
|
│ ├── test_wikijs_client.py
|
||||||
|
│ └── test_tools.py
|
||||||
|
├── projman/ # ← PROJECT PLUGIN
|
||||||
|
│ ├── .claude-plugin/
|
||||||
|
│ │ └── plugin.json
|
||||||
|
│ ├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
│ ├── commands/
|
||||||
|
│ │ ├── sprint-plan.md
|
||||||
|
│ │ ├── sprint-start.md
|
||||||
|
│ │ ├── sprint-status.md
|
||||||
|
│ │ ├── sprint-close.md
|
||||||
|
│ │ └── labels-sync.md
|
||||||
|
│ ├── agents/
|
||||||
|
│ │ ├── planner.md
|
||||||
|
│ │ ├── orchestrator.md
|
||||||
|
│ │ └── executor.md
|
||||||
|
│ ├── skills/
|
||||||
|
│ │ └── label-taxonomy/
|
||||||
|
│ │ └── labels-reference.md
|
||||||
|
│ ├── README.md
|
||||||
|
│ └── CONFIGURATION.md
|
||||||
|
└── projman-pmo/ # ← PMO PLUGIN
|
||||||
|
├── .claude-plugin/
|
||||||
|
│ └── plugin.json
|
||||||
|
├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
├── commands/
|
||||||
|
│ ├── pmo-status.md
|
||||||
|
│ ├── pmo-priorities.md
|
||||||
|
│ ├── pmo-dependencies.md
|
||||||
|
│ └── pmo-schedule.md
|
||||||
|
├── agents/
|
||||||
|
│ └── pmo-coordinator.md
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Points
|
||||||
|
|
||||||
|
### 1. MCP Servers Are SHARED
|
||||||
|
- Location: `mcp-servers/` at repository root
|
||||||
|
- NOT inside `projman/` or `projman-pmo/`
|
||||||
|
- Built ONCE, used by BOTH plugins
|
||||||
|
|
||||||
|
### 2. Plugins Reference MCP Servers
|
||||||
|
- Both plugins use `.mcp.json` to point to `../mcp-servers/`
|
||||||
|
- No MCP code inside plugin directories
|
||||||
|
- Only commands, agents, and skills in plugin directories
|
||||||
|
|
||||||
|
### 3. Mode Detection
|
||||||
|
- MCP servers detect mode based on environment variables
|
||||||
|
- Project mode: When `GITEA_REPO` and `WIKIJS_PROJECT` present
|
||||||
|
- Company mode: When those variables absent (PMO)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration Files
|
||||||
|
|
||||||
|
### projman/.mcp.json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"gitea-projman": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"GITEA_API_URL": "${GITEA_API_URL}",
|
||||||
|
"GITEA_API_TOKEN": "${GITEA_API_TOKEN}",
|
||||||
|
"GITEA_OWNER": "${GITEA_OWNER}",
|
||||||
|
"GITEA_REPO": "${GITEA_REPO}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wikijs-projman": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"WIKIJS_API_URL": "${WIKIJS_API_URL}",
|
||||||
|
"WIKIJS_API_TOKEN": "${WIKIJS_API_TOKEN}",
|
||||||
|
"WIKIJS_BASE_PATH": "${WIKIJS_BASE_PATH}",
|
||||||
|
"WIKIJS_PROJECT": "${WIKIJS_PROJECT}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### projman-pmo/.mcp.json
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"gitea-pmo": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"GITEA_API_URL": "${GITEA_API_URL}",
|
||||||
|
"GITEA_API_TOKEN": "${GITEA_API_TOKEN}",
|
||||||
|
"GITEA_OWNER": "${GITEA_OWNER}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wikijs-pmo": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"WIKIJS_API_URL": "${WIKIJS_API_URL}",
|
||||||
|
"WIKIJS_API_TOKEN": "${WIKIJS_API_TOKEN}",
|
||||||
|
"WIKIJS_BASE_PATH": "${WIKIJS_BASE_PATH}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Critical:** Both plugins point to `../mcp-servers/` using relative paths.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Setup Instructions
|
||||||
|
|
||||||
|
### 1. System Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create config directory
|
||||||
|
mkdir -p ~/.config/claude
|
||||||
|
|
||||||
|
# Gitea config
|
||||||
|
cat > ~/.config/claude/gitea.env << EOF
|
||||||
|
GITEA_API_URL=https://gitea.hyperhivelabs.com/api/v1
|
||||||
|
GITEA_API_TOKEN=your_token
|
||||||
|
GITEA_OWNER=hyperhivelabs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Wiki.js config
|
||||||
|
cat > ~/.config/claude/wikijs.env << EOF
|
||||||
|
WIKIJS_API_URL=https://wiki.hyperhivelabs.com/graphql
|
||||||
|
WIKIJS_API_TOKEN=your_token
|
||||||
|
WIKIJS_BASE_PATH=/hyper-hive-labs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Secure files
|
||||||
|
chmod 600 ~/.config/claude/*.env
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Project Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In each project root
|
||||||
|
cat > .env << EOF
|
||||||
|
GITEA_REPO=cuisineflow
|
||||||
|
WIKIJS_PROJECT=projects/cuisineflow
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Add to .gitignore
|
||||||
|
echo ".env" >> .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Install MCP Servers (ONE TIME)
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Gitea MCP Server
|
||||||
|
cd /path/to/claude-plugins/mcp-servers/gitea
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Wiki.js MCP Server
|
||||||
|
cd /path/to/claude-plugins/mcp-servers/wikijs
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## What Makes This Work
|
||||||
|
|
||||||
|
### Mode Detection in config.py
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-servers/gitea/mcp_server/config.py
|
||||||
|
def load(self):
|
||||||
|
# ... load configs ...
|
||||||
|
|
||||||
|
self.repo = os.getenv('GITEA_REPO') # Optional
|
||||||
|
|
||||||
|
if self.repo:
|
||||||
|
self.mode = 'project'
|
||||||
|
logger.info(f"Running in project mode: {self.repo}")
|
||||||
|
else:
|
||||||
|
self.mode = 'company'
|
||||||
|
logger.info("Running in company-wide mode (PMO)")
|
||||||
|
|
||||||
|
return {
|
||||||
|
'api_url': self.api_url,
|
||||||
|
'api_token': self.api_token,
|
||||||
|
'owner': self.owner,
|
||||||
|
'repo': self.repo,
|
||||||
|
'mode': self.mode
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Same MCP Code, Different Behavior
|
||||||
|
|
||||||
|
The SAME MCP server code runs differently based on environment variables:
|
||||||
|
|
||||||
|
**When projman calls it:**
|
||||||
|
- Has `GITEA_REPO` → operates on single repository
|
||||||
|
- Has `WIKIJS_PROJECT` → operates on single project path
|
||||||
|
|
||||||
|
**When projman-pmo calls it:**
|
||||||
|
- No `GITEA_REPO` → operates on all repositories
|
||||||
|
- No `WIKIJS_PROJECT` → operates on entire company namespace
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Visual Path Flow
|
||||||
|
|
||||||
|
### projman Plugin Flow
|
||||||
|
```
|
||||||
|
projman/.mcp.json
|
||||||
|
↓ (cwd: ../mcp-servers/gitea)
|
||||||
|
mcp-servers/gitea/mcp_server/server.py
|
||||||
|
↓ (loads config)
|
||||||
|
mcp-servers/gitea/mcp_server/config.py
|
||||||
|
↓ (detects GITEA_REPO present)
|
||||||
|
→ PROJECT MODE
|
||||||
|
```
|
||||||
|
|
||||||
|
### projman-pmo Plugin Flow
|
||||||
|
```
|
||||||
|
projman-pmo/.mcp.json
|
||||||
|
↓ (cwd: ../mcp-servers/gitea)
|
||||||
|
mcp-servers/gitea/mcp_server/server.py
|
||||||
|
↓ (loads config)
|
||||||
|
mcp-servers/gitea/mcp_server/config.py
|
||||||
|
↓ (detects NO GITEA_REPO)
|
||||||
|
→ COMPANY MODE
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## File Paths Quick Reference
|
||||||
|
|
||||||
|
### Gitea MCP Server Files
|
||||||
|
- Config loader: `mcp-servers/gitea/mcp_server/config.py`
|
||||||
|
- API client: `mcp-servers/gitea/mcp_server/gitea_client.py`
|
||||||
|
- Server entry: `mcp-servers/gitea/mcp_server/server.py`
|
||||||
|
- Issue tools: `mcp-servers/gitea/mcp_server/tools/issues.py`
|
||||||
|
- Label tools: `mcp-servers/gitea/mcp_server/tools/labels.py`
|
||||||
|
|
||||||
|
### Wiki.js MCP Server Files
|
||||||
|
- Config loader: `mcp-servers/wikijs/mcp_server/config.py`
|
||||||
|
- API client: `mcp-servers/wikijs/mcp_server/wikijs_client.py`
|
||||||
|
- Server entry: `mcp-servers/wikijs/mcp_server/server.py`
|
||||||
|
- Page tools: `mcp-servers/wikijs/mcp_server/tools/pages.py`
|
||||||
|
- Lessons tools: `mcp-servers/wikijs/mcp_server/tools/lessons_learned.py`
|
||||||
|
|
||||||
|
### Plugin Files
|
||||||
|
- projman config: `projman/.mcp.json`
|
||||||
|
- projman-pmo config: `projman-pmo/.mcp.json`
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## This Is The Truth
|
||||||
|
|
||||||
|
**If ANY other document shows MCP servers inside plugin directories, that document is WRONG.**
|
||||||
|
|
||||||
|
**THIS document shows the CORRECT, FINAL architecture.**
|
||||||
|
|
||||||
|
Use this as your reference. Period.
|
||||||
241
docs/references/projman-pmo/DOCUMENT-INDEX.md
Normal file
241
docs/references/projman-pmo/DOCUMENT-INDEX.md
Normal file
@@ -0,0 +1,241 @@
|
|||||||
|
# ProjMan Implementation - Document Index
|
||||||
|
|
||||||
|
All documentation for building the projman and projman-pmo plugins.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ⚠️ START HERE - CORRECT ARCHITECTURE
|
||||||
|
|
||||||
|
### [CORRECT-ARCHITECTURE.md](./CORRECT-ARCHITECTURE.md)
|
||||||
|
**⚠️ THIS IS THE DEFINITIVE REFERENCE ⚠️**
|
||||||
|
**Use when:** You need to verify the correct repository structure
|
||||||
|
**Contains:**
|
||||||
|
- THE ONLY CORRECT repository structure
|
||||||
|
- MCP servers are SHARED at root level (`mcp-servers/` directory)
|
||||||
|
- Configuration file examples
|
||||||
|
- Setup instructions
|
||||||
|
- Path references
|
||||||
|
- Mode detection implementation
|
||||||
|
|
||||||
|
**If any other document conflicts with this, THIS ONE IS CORRECT.**
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📚 Core Implementation Documents
|
||||||
|
|
||||||
|
### [projman-implementation-plan-updated.md](./projman-implementation-plan-updated.md)
|
||||||
|
**Purpose:** Complete, detailed implementation plan
|
||||||
|
**Use when:** Actually building the plugins (your main reference)
|
||||||
|
**Contains:**
|
||||||
|
- 12 detailed implementation phases
|
||||||
|
- Configuration architecture
|
||||||
|
- Complete code examples
|
||||||
|
- Success criteria per phase
|
||||||
|
- Testing strategies
|
||||||
|
- No timelines - work at your pace
|
||||||
|
- **Length:** Comprehensive (2000+ lines)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🐍 Python-Specific Guides
|
||||||
|
|
||||||
|
### [projman-python-quickstart.md](./projman-python-quickstart.md)
|
||||||
|
**Purpose:** Python-specific implementation guide
|
||||||
|
**Use when:** Setting up Python environment, writing code
|
||||||
|
**Contains:**
|
||||||
|
- Python project structure
|
||||||
|
- Virtual environment setup
|
||||||
|
- Requirements.txt examples
|
||||||
|
- Configuration loader code
|
||||||
|
- Modular code patterns
|
||||||
|
- Testing with pytest
|
||||||
|
- Debugging tips
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🏗️ Architecture Documentation
|
||||||
|
|
||||||
|
### [two-mcp-architecture-guide.md](./two-mcp-architecture-guide.md)
|
||||||
|
**Purpose:** Deep dive into two-MCP-server architecture
|
||||||
|
**Use when:** Understanding the MCP server design
|
||||||
|
**Contains:**
|
||||||
|
- Wiki.js structure at `/hyper-hive-labs`
|
||||||
|
- Complete Gitea MCP server code
|
||||||
|
- Complete Wiki.js MCP server code (GraphQL)
|
||||||
|
- Configuration examples
|
||||||
|
- Mode detection implementation
|
||||||
|
- Setup instructions
|
||||||
|
- Migration guidance
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 How to Use These Documents
|
||||||
|
|
||||||
|
### Phase 1: Planning & Setup
|
||||||
|
1. Read **CORRECT-ARCHITECTURE.md** to understand the definitive repository structure
|
||||||
|
2. Review **projman-implementation-plan-updated.md** Phase 1 for setup overview
|
||||||
|
3. Set up your Gitea and Wiki.js instances
|
||||||
|
4. Create system-level configuration files
|
||||||
|
|
||||||
|
### Phase 2: Starting Implementation
|
||||||
|
1. Open **projman-implementation-plan-updated.md** (your main reference for all 12 phases)
|
||||||
|
2. Start with Phase 1.1a (Gitea MCP Server)
|
||||||
|
3. Reference **projman-python-quickstart.md** for Python patterns and virtual environment setup
|
||||||
|
4. Reference **two-mcp-architecture-guide.md** for detailed MCP server code examples
|
||||||
|
|
||||||
|
### Phase 3: During Development
|
||||||
|
1. **Main reference:** projman-implementation-plan-updated.md (follow phase by phase)
|
||||||
|
2. **Structure reference:** CORRECT-ARCHITECTURE.md (when in doubt about paths)
|
||||||
|
3. **Code patterns:** projman-python-quickstart.md
|
||||||
|
4. **Architecture deep dive:** two-mcp-architecture-guide.md
|
||||||
|
|
||||||
|
### Phase 4: Troubleshooting
|
||||||
|
1. Check **CORRECT-ARCHITECTURE.md** for definitive path references
|
||||||
|
2. Review configuration examples in **two-mcp-architecture-guide.md**
|
||||||
|
3. Check Python-specific debugging in **projman-python-quickstart.md**
|
||||||
|
4. Verify setup instructions in **projman-implementation-plan-updated.md** Phase 1.3
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📖 Document Relationships
|
||||||
|
|
||||||
|
```
|
||||||
|
CORRECT-ARCHITECTURE.md (definitive structure)
|
||||||
|
↓ (referenced by)
|
||||||
|
├── projman-implementation-plan-updated.md (main implementation guide)
|
||||||
|
│ ↓ (uses Python patterns from)
|
||||||
|
│ ├── projman-python-quickstart.md
|
||||||
|
│ ↓ (references architecture from)
|
||||||
|
│ └── two-mcp-architecture-guide.md
|
||||||
|
└── DOCUMENT-INDEX.md (this file - navigation)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎨 Quick Reference by Topic
|
||||||
|
|
||||||
|
### Repository Structure
|
||||||
|
- **Definitive reference:** CORRECT-ARCHITECTURE.md (lines 9-80)
|
||||||
|
- **Key point:** MCP servers are SHARED at `mcp-servers/` directory (not inside plugins)
|
||||||
|
|
||||||
|
### Configuration
|
||||||
|
- **Setup instructions:** CORRECT-ARCHITECTURE.md (lines 172-229)
|
||||||
|
- **Implementation details:** projman-implementation-plan-updated.md (Phase 1.3)
|
||||||
|
- **Python code examples:** projman-python-quickstart.md (lines 140-214)
|
||||||
|
- **Config loader:** two-mcp-architecture-guide.md (lines 281-358)
|
||||||
|
|
||||||
|
### MCP Servers
|
||||||
|
- **Architecture overview:** CORRECT-ARCHITECTURE.md (Key Points section)
|
||||||
|
- **Gitea MCP:** projman-implementation-plan-updated.md (Phase 1.1a)
|
||||||
|
- **Wiki.js MCP:** projman-implementation-plan-updated.md (Phase 1.1b)
|
||||||
|
- **Complete implementation:** two-mcp-architecture-guide.md (lines 277-680)
|
||||||
|
|
||||||
|
### Wiki.js Structure
|
||||||
|
- **Full structure:** two-mcp-architecture-guide.md (lines 13-70)
|
||||||
|
- **Path resolution:** projman-implementation-plan-updated.md (lines 110-115)
|
||||||
|
- **Integration:** projman-implementation-plan-updated.md (Phase 4.1)
|
||||||
|
|
||||||
|
### Python Patterns
|
||||||
|
- **Setup & dependencies:** projman-python-quickstart.md (lines 15-111)
|
||||||
|
- **Modular code structure:** projman-python-quickstart.md (lines 511-575)
|
||||||
|
- **Virtual environment:** projman-python-quickstart.md (lines 579-616)
|
||||||
|
|
||||||
|
### Sprint Workflow
|
||||||
|
- **Commands:** projman-implementation-plan-updated.md (Phase 2)
|
||||||
|
- **Agents:** projman-implementation-plan-updated.md (Phase 3)
|
||||||
|
- **Lessons Learned:** projman-implementation-plan-updated.md (Phase 4)
|
||||||
|
|
||||||
|
### PMO Plugin
|
||||||
|
- **Requirements:** projman-implementation-plan-updated.md (Phase 9)
|
||||||
|
- **Implementation:** projman-implementation-plan-updated.md (Phase 10-11)
|
||||||
|
- **Multi-project methods:** two-mcp-architecture-guide.md (lines 639-679)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🚀 Suggested Reading Order
|
||||||
|
|
||||||
|
### First Time (Understanding the Project)
|
||||||
|
1. **CORRECT-ARCHITECTURE.md** (15 minutes)
|
||||||
|
- Understand the definitive repository structure
|
||||||
|
- See MCP server placement (shared at root)
|
||||||
|
- Review configuration approach
|
||||||
|
|
||||||
|
2. **projman-python-quickstart.md** (30 minutes)
|
||||||
|
- Understand Python setup
|
||||||
|
- See code patterns
|
||||||
|
- Virtual environment setup
|
||||||
|
|
||||||
|
3. **projman-implementation-plan-updated.md** (2-3 hours)
|
||||||
|
- Read Phase 1 in detail
|
||||||
|
- Skim Phases 2-12 to understand the flow
|
||||||
|
- This is your main implementation guide
|
||||||
|
|
||||||
|
4. **two-mcp-architecture-guide.md** (1 hour)
|
||||||
|
- Deep dive into MCP server architecture
|
||||||
|
- Complete code examples
|
||||||
|
- Wiki.js structure and integration
|
||||||
|
|
||||||
|
### During Implementation
|
||||||
|
- Keep **projman-implementation-plan-updated.md** open (your main reference)
|
||||||
|
- Reference **CORRECT-ARCHITECTURE.md** when unsure about paths
|
||||||
|
- Use **projman-python-quickstart.md** for Python-specific code
|
||||||
|
- Use **two-mcp-architecture-guide.md** for detailed MCP implementation
|
||||||
|
|
||||||
|
### When You Need Quick Answers
|
||||||
|
- **"What's the correct repository structure?"** → CORRECT-ARCHITECTURE.md
|
||||||
|
- **"How do I set up Python?"** → projman-python-quickstart.md
|
||||||
|
- **"How does configuration work?"** → CORRECT-ARCHITECTURE.md or two-mcp-architecture-guide.md
|
||||||
|
- **"What's the full MCP server code?"** → two-mcp-architecture-guide.md
|
||||||
|
- **"What do I build in Phase X?"** → projman-implementation-plan-updated.md
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 📊 Document Statistics
|
||||||
|
|
||||||
|
| Document | Lines | Focus | Primary Use |
|
||||||
|
|----------|-------|-------|-------------|
|
||||||
|
| CORRECT-ARCHITECTURE.md | 325 | Definitive Structure | Reference (paths, config) |
|
||||||
|
| projman-implementation-plan-updated.md | 2081 | Complete Implementation | Main guide (building) |
|
||||||
|
| projman-python-quickstart.md | 727 | Python Patterns | Code patterns & setup |
|
||||||
|
| two-mcp-architecture-guide.md | 941 | Architecture Deep Dive | MCP implementation |
|
||||||
|
|
||||||
|
**Total:** ~4,074 lines of comprehensive documentation
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## ✅ Pre-Implementation Checklist
|
||||||
|
|
||||||
|
Before starting Phase 1, verify you have:
|
||||||
|
- [ ] Read CORRECT-ARCHITECTURE.md (understand structure)
|
||||||
|
- [ ] Understand the two-MCP-server architecture (Gitea + Wiki.js)
|
||||||
|
- [ ] Understand shared MCP codebase at `mcp-servers/` (not in plugin dirs)
|
||||||
|
- [ ] Understand Wiki.js structure at `/hyper-hive-labs`
|
||||||
|
- [ ] Understand hybrid configuration (system + project levels)
|
||||||
|
- [ ] Python 3.11+ installed
|
||||||
|
- [ ] Access to Gitea instance
|
||||||
|
- [ ] Access to Wiki.js instance
|
||||||
|
- [ ] API tokens for both services
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎯 Key Architectural Decisions
|
||||||
|
|
||||||
|
These are the final decisions documented across all files:
|
||||||
|
|
||||||
|
1. **Two MCP Servers** - Separate Gitea and Wiki.js servers for better maintainability
|
||||||
|
2. **Shared MCP Codebase** - Located at `mcp-servers/` (root level), used by both plugins
|
||||||
|
3. **Python Implementation** - MCP servers written in Python 3.11+
|
||||||
|
4. **Hybrid Configuration** - System-level tokens + project-level paths
|
||||||
|
5. **Wiki.js for Lessons** - Superior to Git-based Wiki for documentation and search
|
||||||
|
6. **Mode Detection** - MCP servers detect project vs company-wide mode via environment variables
|
||||||
|
7. **Build Order** - projman first (Phases 1-8), then projman-pmo (Phases 9-12)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 🎉 You're Ready!
|
||||||
|
|
||||||
|
You have everything you need to build the projman and projman-pmo plugins. All architectural decisions are finalized and documented.
|
||||||
|
|
||||||
|
**Start here:** [projman-implementation-plan-updated.md](./projman-implementation-plan-updated.md) - Phase 1.1a
|
||||||
|
|
||||||
|
Good luck with the build!
|
||||||
2086
docs/references/projman-pmo/projman-implementation-plan-updated.md
Normal file
2086
docs/references/projman-pmo/projman-implementation-plan-updated.md
Normal file
File diff suppressed because it is too large
Load Diff
729
docs/references/projman-pmo/projman-python-quickstart.md
Normal file
729
docs/references/projman-pmo/projman-python-quickstart.md
Normal file
@@ -0,0 +1,729 @@
|
|||||||
|
# ProjMan Plugins - Python Quick Start
|
||||||
|
|
||||||
|
This guide provides Python-specific setup and development information for the projman and projman-pmo plugins.
|
||||||
|
|
||||||
|
> **⚠️ IMPORTANT:** For the definitive repository structure, refer to [CORRECT-ARCHITECTURE.md](./CORRECT-ARCHITECTURE.md). This guide shows Python-specific patterns and setup.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Technology Stack
|
||||||
|
|
||||||
|
- **MCP Server:** Python 3.11+
|
||||||
|
- **Commands:** Markdown files
|
||||||
|
- **Agents:** Markdown files
|
||||||
|
- **Dependencies:** pip with requirements.txt
|
||||||
|
- **Virtual Environment:** .venv (per plugin)
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Initial Setup
|
||||||
|
|
||||||
|
### 1. System Requirements
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Python 3.11 or higher
|
||||||
|
python --version
|
||||||
|
|
||||||
|
# pip (latest)
|
||||||
|
pip --version
|
||||||
|
|
||||||
|
# git
|
||||||
|
git --version
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. System-Level Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create config directory
|
||||||
|
mkdir -p ~/.config/claude
|
||||||
|
|
||||||
|
# Create gitea.env with your credentials
|
||||||
|
cat > ~/.config/claude/gitea.env << EOF
|
||||||
|
GITEA_API_URL=https://gitea.hyperhivelabs.com/api/v1
|
||||||
|
GITEA_API_TOKEN=your_token_here
|
||||||
|
GITEA_OWNER=hyperhivelabs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Secure the file
|
||||||
|
chmod 600 ~/.config/claude/gitea.env
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Project-Level Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In each repository root
|
||||||
|
echo "GITEA_REPO=cuisineflow" > .env
|
||||||
|
|
||||||
|
# Add to .gitignore
|
||||||
|
echo ".env" >> .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MCP Server Structure
|
||||||
|
|
||||||
|
```
|
||||||
|
hyperhivelabs/claude-plugins/
|
||||||
|
├── mcp-servers/ # SHARED by both plugins
|
||||||
|
│ ├── gitea/
|
||||||
|
│ │ ├── .venv/
|
||||||
|
│ │ ├── requirements.txt
|
||||||
|
│ │ ├── mcp_server/
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── server.py
|
||||||
|
│ │ │ ├── config.py
|
||||||
|
│ │ │ ├── gitea_client.py
|
||||||
|
│ │ │ └── tools/
|
||||||
|
│ │ └── tests/
|
||||||
|
│ └── wikijs/
|
||||||
|
│ ├── .venv/
|
||||||
|
│ ├── requirements.txt
|
||||||
|
│ ├── mcp_server/
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ ├── server.py
|
||||||
|
│ │ ├── config.py
|
||||||
|
│ │ └── wikijs_client.py
|
||||||
|
│ └── tests/
|
||||||
|
├── projman/
|
||||||
|
│ ├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
│ ├── commands/
|
||||||
|
│ └── agents/
|
||||||
|
└── projman-pmo/
|
||||||
|
├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
└── commands/
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Dependencies (requirements.txt)
|
||||||
|
|
||||||
|
```txt
|
||||||
|
# anthropic-sdk==0.18.0 # MCP SDK
|
||||||
|
anthropic-sdk>=0.18.0
|
||||||
|
# python-dotenv==1.0.0 # Environment variable loading
|
||||||
|
python-dotenv>=1.0.0
|
||||||
|
# requests==2.31.0 # HTTP client for Gitea API
|
||||||
|
requests>=2.31.0
|
||||||
|
# pydantic==2.5.0 # Data validation
|
||||||
|
pydantic>=2.5.0
|
||||||
|
# pytest==7.4.3 # Testing framework
|
||||||
|
pytest>=7.4.3
|
||||||
|
# pytest-asyncio==0.23.0 # Async testing support
|
||||||
|
pytest-asyncio>=0.23.0
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Following your coding preferences, library versions are specified with comments showing the exact version being used.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Development Workflow
|
||||||
|
|
||||||
|
### Initial MCP Server Setup
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Navigate to MCP servers directory
|
||||||
|
cd /path/to/claude-plugins/mcp-servers/gitea
|
||||||
|
|
||||||
|
# Create virtual environment
|
||||||
|
python -m venv .venv
|
||||||
|
|
||||||
|
# Activate virtual environment
|
||||||
|
source .venv/bin/activate # Linux/Mac
|
||||||
|
# or
|
||||||
|
.venv\Scripts\activate # Windows
|
||||||
|
|
||||||
|
# Install dependencies
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Verify installation
|
||||||
|
python -c "import anthropic; print('SDK installed')"
|
||||||
|
```
|
||||||
|
|
||||||
|
### Configuration Loader (config.py)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-servers/gitea/mcp_server/config.py
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
class Config:
|
||||||
|
"""Hybrid configuration loader for projman plugins"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.api_url: Optional[str] = None
|
||||||
|
self.api_token: Optional[str] = None
|
||||||
|
self.owner: Optional[str] = None
|
||||||
|
self.repo: Optional[str] = None
|
||||||
|
|
||||||
|
def load(self) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Load configuration from system and project levels.
|
||||||
|
Project-level configuration overrides system-level.
|
||||||
|
"""
|
||||||
|
# Load system config
|
||||||
|
system_config = Path.home() / '.config' / 'claude' / 'gitea.env'
|
||||||
|
if system_config.exists():
|
||||||
|
load_dotenv(system_config)
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError(
|
||||||
|
f"System config not found: {system_config}\n"
|
||||||
|
"Create it with: mkdir -p ~/.config/claude && "
|
||||||
|
"cat > ~/.config/claude/gitea.env"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Load project config (overrides system)
|
||||||
|
project_config = Path.cwd() / '.env'
|
||||||
|
if project_config.exists():
|
||||||
|
load_dotenv(project_config, override=True)
|
||||||
|
|
||||||
|
# Extract values
|
||||||
|
self.api_url = os.getenv('GITEA_API_URL')
|
||||||
|
self.api_token = os.getenv('GITEA_API_TOKEN')
|
||||||
|
self.owner = os.getenv('GITEA_OWNER')
|
||||||
|
self.repo = os.getenv('GITEA_REPO') # Optional for PMO
|
||||||
|
|
||||||
|
# Validate required variables
|
||||||
|
self._validate()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'api_url': self.api_url,
|
||||||
|
'api_token': self.api_token,
|
||||||
|
'owner': self.owner,
|
||||||
|
'repo': self.repo
|
||||||
|
}
|
||||||
|
|
||||||
|
def _validate(self) -> None:
|
||||||
|
"""Validate that required configuration is present"""
|
||||||
|
required = {
|
||||||
|
'GITEA_API_URL': self.api_url,
|
||||||
|
'GITEA_API_TOKEN': self.api_token,
|
||||||
|
'GITEA_OWNER': self.owner
|
||||||
|
}
|
||||||
|
|
||||||
|
missing = [key for key, value in required.items() if not value]
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
raise ValueError(
|
||||||
|
f"Missing required configuration: {', '.join(missing)}\n"
|
||||||
|
"Check your ~/.config/claude/gitea.env file"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Usage
|
||||||
|
config = Config()
|
||||||
|
config_dict = config.load()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Gitea API Client (gitea_client.py)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-servers/gitea/mcp_server/gitea_client.py
|
||||||
|
import requests
|
||||||
|
from typing import List, Dict, Optional
|
||||||
|
from .config import Config
|
||||||
|
|
||||||
|
class GiteaClient:
|
||||||
|
"""Client for interacting with Gitea API"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
config = Config()
|
||||||
|
config_dict = config.load()
|
||||||
|
|
||||||
|
self.base_url = config_dict['api_url']
|
||||||
|
self.token = config_dict['api_token']
|
||||||
|
self.owner = config_dict['owner']
|
||||||
|
self.repo = config_dict.get('repo') # Optional
|
||||||
|
|
||||||
|
self.session = requests.Session()
|
||||||
|
self.session.headers.update({
|
||||||
|
'Authorization': f'token {self.token}',
|
||||||
|
'Content-Type': 'application/json'
|
||||||
|
})
|
||||||
|
|
||||||
|
def list_issues(
|
||||||
|
self,
|
||||||
|
state: str = 'open',
|
||||||
|
labels: Optional[List[str]] = None,
|
||||||
|
repo: Optional[str] = None
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
List issues from Gitea repository.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
state: Issue state (open, closed, all)
|
||||||
|
labels: Filter by labels
|
||||||
|
repo: Override configured repo (for PMO multi-repo)
|
||||||
|
"""
|
||||||
|
target_repo = repo or self.repo
|
||||||
|
if not target_repo:
|
||||||
|
raise ValueError("Repository not specified")
|
||||||
|
|
||||||
|
url = f"{self.base_url}/repos/{self.owner}/{target_repo}/issues"
|
||||||
|
params = {'state': state}
|
||||||
|
|
||||||
|
if labels:
|
||||||
|
params['labels'] = ','.join(labels)
|
||||||
|
|
||||||
|
response = self.session.get(url, params=params)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def create_issue(
|
||||||
|
self,
|
||||||
|
title: str,
|
||||||
|
body: str,
|
||||||
|
labels: Optional[List[str]] = None,
|
||||||
|
repo: Optional[str] = None
|
||||||
|
) -> Dict:
|
||||||
|
"""Create a new issue in Gitea"""
|
||||||
|
target_repo = repo or self.repo
|
||||||
|
if not target_repo:
|
||||||
|
raise ValueError("Repository not specified")
|
||||||
|
|
||||||
|
url = f"{self.base_url}/repos/{self.owner}/{target_repo}/issues"
|
||||||
|
data = {
|
||||||
|
'title': title,
|
||||||
|
'body': body
|
||||||
|
}
|
||||||
|
|
||||||
|
if labels:
|
||||||
|
data['labels'] = labels
|
||||||
|
|
||||||
|
response = self.session.post(url, json=data)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
|
||||||
|
def get_labels(
|
||||||
|
self,
|
||||||
|
repo: Optional[str] = None
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""Get all labels from repository"""
|
||||||
|
target_repo = repo or self.repo
|
||||||
|
if not target_repo:
|
||||||
|
raise ValueError("Repository not specified")
|
||||||
|
|
||||||
|
url = f"{self.base_url}/repos/{self.owner}/{target_repo}/labels"
|
||||||
|
response = self.session.get(url)
|
||||||
|
response.raise_for_status()
|
||||||
|
return response.json()
|
||||||
|
```
|
||||||
|
|
||||||
|
### MCP Server Entry Point (server.py)
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-servers/gitea/mcp_server/server.py
|
||||||
|
from anthropic import Anthropic
|
||||||
|
from .gitea_client import GiteaClient
|
||||||
|
from .tools import IssueTools, LabelTools, WikiTools
|
||||||
|
|
||||||
|
class ProjManMCPServer:
|
||||||
|
"""Main MCP server for projman plugin"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.gitea = GiteaClient()
|
||||||
|
self.issue_tools = IssueTools(self.gitea)
|
||||||
|
self.label_tools = LabelTools(self.gitea)
|
||||||
|
self.wiki_tools = WikiTools(self.gitea)
|
||||||
|
|
||||||
|
def register_tools(self):
|
||||||
|
"""Register all available MCP tools"""
|
||||||
|
return [
|
||||||
|
# Issue tools
|
||||||
|
self.issue_tools.list_issues,
|
||||||
|
self.issue_tools.get_issue,
|
||||||
|
self.issue_tools.create_issue,
|
||||||
|
self.issue_tools.update_issue,
|
||||||
|
self.issue_tools.add_comment,
|
||||||
|
|
||||||
|
# Label tools
|
||||||
|
self.label_tools.get_labels,
|
||||||
|
self.label_tools.suggest_labels,
|
||||||
|
|
||||||
|
# Wiki tools
|
||||||
|
self.wiki_tools.search_wiki,
|
||||||
|
self.wiki_tools.get_wiki_page,
|
||||||
|
self.wiki_tools.create_wiki_page
|
||||||
|
]
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
server = ProjManMCPServer()
|
||||||
|
# MCP server startup logic here
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Testing
|
||||||
|
|
||||||
|
### Unit Tests
|
||||||
|
|
||||||
|
```python
|
||||||
|
# tests/test_config.py
|
||||||
|
import pytest
|
||||||
|
from pathlib import Path
|
||||||
|
from mcp_server.config import Config
|
||||||
|
|
||||||
|
def test_load_system_config(tmp_path):
|
||||||
|
"""Test loading system-level configuration"""
|
||||||
|
# Create mock system config
|
||||||
|
config_dir = tmp_path / '.config' / 'claude'
|
||||||
|
config_dir.mkdir(parents=True)
|
||||||
|
|
||||||
|
config_file = config_dir / 'gitea.env'
|
||||||
|
config_file.write_text(
|
||||||
|
"GITEA_API_URL=https://test.com/api/v1\n"
|
||||||
|
"GITEA_API_TOKEN=test_token\n"
|
||||||
|
"GITEA_OWNER=test_owner\n"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Test config loading
|
||||||
|
config = Config()
|
||||||
|
# ... test assertions
|
||||||
|
|
||||||
|
def test_project_config_override(tmp_path):
|
||||||
|
"""Test that project config overrides system config"""
|
||||||
|
# ... test implementation
|
||||||
|
|
||||||
|
def test_missing_required_config():
|
||||||
|
"""Test error handling for missing configuration"""
|
||||||
|
with pytest.raises(ValueError):
|
||||||
|
config = Config()
|
||||||
|
config.load()
|
||||||
|
```
|
||||||
|
|
||||||
|
### Integration Tests
|
||||||
|
|
||||||
|
```python
|
||||||
|
# tests/test_gitea_client.py
|
||||||
|
import pytest
|
||||||
|
from mcp_server.gitea_client import GiteaClient
|
||||||
|
|
||||||
|
@pytest.fixture
|
||||||
|
def gitea_client():
|
||||||
|
"""Fixture providing configured Gitea client"""
|
||||||
|
return GiteaClient()
|
||||||
|
|
||||||
|
def test_list_issues(gitea_client):
|
||||||
|
"""Test listing issues from Gitea"""
|
||||||
|
issues = gitea_client.list_issues(state='open')
|
||||||
|
assert isinstance(issues, list)
|
||||||
|
|
||||||
|
def test_create_issue(gitea_client):
|
||||||
|
"""Test creating an issue in Gitea"""
|
||||||
|
issue = gitea_client.create_issue(
|
||||||
|
title="Test Issue",
|
||||||
|
body="Test body",
|
||||||
|
labels=["Type/Bug"]
|
||||||
|
)
|
||||||
|
assert issue['title'] == "Test Issue"
|
||||||
|
assert "Type/Bug" in [label['name'] for label in issue['labels']]
|
||||||
|
```
|
||||||
|
|
||||||
|
### Running Tests
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Activate virtual environment
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
# Run all tests
|
||||||
|
pytest
|
||||||
|
|
||||||
|
# Run with coverage
|
||||||
|
pytest --cov=mcp_server --cov-report=html
|
||||||
|
|
||||||
|
# Run specific test file
|
||||||
|
pytest tests/test_config.py
|
||||||
|
|
||||||
|
# Run with verbose output
|
||||||
|
pytest -v
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## .mcp.json Configuration
|
||||||
|
|
||||||
|
### projman (Repository-Specific)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"gitea-projman": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"GITEA_API_URL": "${GITEA_API_URL}",
|
||||||
|
"GITEA_API_TOKEN": "${GITEA_API_TOKEN}",
|
||||||
|
"GITEA_OWNER": "${GITEA_OWNER}",
|
||||||
|
"GITEA_REPO": "${GITEA_REPO}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wikijs-projman": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"WIKIJS_API_URL": "${WIKIJS_API_URL}",
|
||||||
|
"WIKIJS_API_TOKEN": "${WIKIJS_API_TOKEN}",
|
||||||
|
"WIKIJS_BASE_PATH": "${WIKIJS_BASE_PATH}",
|
||||||
|
"WIKIJS_PROJECT": "${WIKIJS_PROJECT}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### projman-pmo (Multi-Project)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"gitea-pmo": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"GITEA_API_URL": "${GITEA_API_URL}",
|
||||||
|
"GITEA_API_TOKEN": "${GITEA_API_TOKEN}",
|
||||||
|
"GITEA_OWNER": "${GITEA_OWNER}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wikijs-pmo": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"WIKIJS_API_URL": "${WIKIJS_API_URL}",
|
||||||
|
"WIKIJS_API_TOKEN": "${WIKIJS_API_TOKEN}",
|
||||||
|
"WIKIJS_BASE_PATH": "${WIKIJS_BASE_PATH}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Note:** Both plugins reference `../mcp-servers/` (shared location). PMO doesn't use `GITEA_REPO` since it operates across all repositories.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Modular Code Structure (Following Your Preferences)
|
||||||
|
|
||||||
|
### Single Responsibility Functions
|
||||||
|
|
||||||
|
```python
|
||||||
|
def validate_configuration(config: Dict[str, str]) -> None:
|
||||||
|
"""
|
||||||
|
Validate that all required configuration values are present.
|
||||||
|
Raises ValueError if any required values are missing.
|
||||||
|
"""
|
||||||
|
required_keys = ['api_url', 'api_token', 'owner']
|
||||||
|
missing = [key for key in required_keys if not config.get(key)]
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
raise ValueError(f"Missing configuration: {', '.join(missing)}")
|
||||||
|
|
||||||
|
def load_system_config() -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Load configuration from system-level gitea.env file.
|
||||||
|
Returns dictionary of configuration values.
|
||||||
|
"""
|
||||||
|
config_path = Path.home() / '.config' / 'claude' / 'gitea.env'
|
||||||
|
|
||||||
|
if not config_path.exists():
|
||||||
|
raise FileNotFoundError(f"System config not found: {config_path}")
|
||||||
|
|
||||||
|
load_dotenv(config_path)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'api_url': os.getenv('GITEA_API_URL'),
|
||||||
|
'api_token': os.getenv('GITEA_API_TOKEN'),
|
||||||
|
'owner': os.getenv('GITEA_OWNER')
|
||||||
|
}
|
||||||
|
|
||||||
|
def load_project_config() -> Dict[str, Optional[str]]:
|
||||||
|
"""
|
||||||
|
Load project-specific configuration from local .env file.
|
||||||
|
Returns dictionary with 'repo' key, value may be None if not configured.
|
||||||
|
"""
|
||||||
|
project_env = Path.cwd() / '.env'
|
||||||
|
|
||||||
|
if project_env.exists():
|
||||||
|
load_dotenv(project_env, override=True)
|
||||||
|
|
||||||
|
return {
|
||||||
|
'repo': os.getenv('GITEA_REPO')
|
||||||
|
}
|
||||||
|
|
||||||
|
def merge_configurations(system: Dict, project: Dict) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Merge system and project configurations.
|
||||||
|
Project values override system values where present.
|
||||||
|
"""
|
||||||
|
merged = system.copy()
|
||||||
|
merged.update({k: v for k, v in project.items() if v is not None})
|
||||||
|
return merged
|
||||||
|
|
||||||
|
def main():
|
||||||
|
"""Main entry point that orchestrates configuration loading"""
|
||||||
|
system_config = load_system_config()
|
||||||
|
project_config = load_project_config()
|
||||||
|
final_config = merge_configurations(system_config, project_config)
|
||||||
|
validate_configuration(final_config)
|
||||||
|
return final_config
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Virtual Environment Management
|
||||||
|
|
||||||
|
### Creation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In plugin mcp-server directory
|
||||||
|
python -m venv .venv
|
||||||
|
```
|
||||||
|
|
||||||
|
### Activation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Linux/Mac
|
||||||
|
source .venv/bin/activate
|
||||||
|
|
||||||
|
# Windows
|
||||||
|
.venv\Scripts\activate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Deactivation
|
||||||
|
|
||||||
|
```bash
|
||||||
|
deactivate
|
||||||
|
```
|
||||||
|
|
||||||
|
### Cleanup & Rebuild
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Remove old virtual environment
|
||||||
|
rm -rf .venv
|
||||||
|
|
||||||
|
# Create fresh virtual environment
|
||||||
|
python -m venv .venv
|
||||||
|
|
||||||
|
# Activate and reinstall
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Debugging
|
||||||
|
|
||||||
|
### Enable Debug Logging
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Add to server.py
|
||||||
|
import logging
|
||||||
|
|
||||||
|
logging.basicConfig(
|
||||||
|
level=logging.DEBUG,
|
||||||
|
format='%(asctime)s - %(name)s - %(levelname)s - %(message)s'
|
||||||
|
)
|
||||||
|
|
||||||
|
logger = logging.getLogger(__name__)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Common Issues
|
||||||
|
|
||||||
|
**Issue:** Module not found
|
||||||
|
```bash
|
||||||
|
# Solution: Ensure PYTHONPATH is set in .mcp.json
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/mcp-server"
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Issue:** Configuration not loading
|
||||||
|
```bash
|
||||||
|
# Solution: Check file permissions
|
||||||
|
chmod 600 ~/.config/claude/gitea.env
|
||||||
|
|
||||||
|
# Verify file exists
|
||||||
|
cat ~/.config/claude/gitea.env
|
||||||
|
```
|
||||||
|
|
||||||
|
**Issue:** API authentication failing
|
||||||
|
```bash
|
||||||
|
# Solution: Test token manually
|
||||||
|
curl -H "Authorization: token YOUR_TOKEN" \
|
||||||
|
https://your-gitea.com/api/v1/user
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Performance Optimization
|
||||||
|
|
||||||
|
### Caching with functools
|
||||||
|
|
||||||
|
```python
|
||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
@lru_cache(maxsize=128)
|
||||||
|
def get_labels_cached(repo: str) -> List[Dict]:
|
||||||
|
"""Cached label retrieval to reduce API calls"""
|
||||||
|
return self.gitea.get_labels(repo)
|
||||||
|
```
|
||||||
|
|
||||||
|
### Async Operations
|
||||||
|
|
||||||
|
```python
|
||||||
|
import asyncio
|
||||||
|
import aiohttp
|
||||||
|
|
||||||
|
async def fetch_multiple_repos(repos: List[str]) -> List[Dict]:
|
||||||
|
"""Fetch data from multiple repositories concurrently"""
|
||||||
|
async with aiohttp.ClientSession() as session:
|
||||||
|
tasks = [fetch_repo_data(session, repo) for repo in repos]
|
||||||
|
return await asyncio.gather(*tasks)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. **Set up system configuration** as shown above
|
||||||
|
2. **Create project configuration** in your first repository
|
||||||
|
3. **Navigate to Phase 1.1** of the implementation plan
|
||||||
|
4. **Build the MCP server** following the structure above
|
||||||
|
5. **Write tests** as you implement each component
|
||||||
|
6. **Test with real Gitea instance** early and often
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Key Differences from Node.js Approach
|
||||||
|
|
||||||
|
| Aspect | Node.js | Python (Your Choice) |
|
||||||
|
|--------|---------|---------------------|
|
||||||
|
| Dependencies | package.json | requirements.txt |
|
||||||
|
| Package Manager | npm/yarn | pip |
|
||||||
|
| Isolation | node_modules | .venv |
|
||||||
|
| Module System | ES6 imports | Python imports |
|
||||||
|
| Async | async/await | async/await |
|
||||||
|
| Type Checking | TypeScript | Type hints + Pydantic |
|
||||||
|
| Testing | Jest | pytest |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Resources
|
||||||
|
|
||||||
|
- **Anthropic MCP SDK (Python):** https://github.com/anthropics/anthropic-sdk-python
|
||||||
|
- **Python Requests:** https://docs.python-requests.org/
|
||||||
|
- **Pydantic:** https://docs.pydantic.dev/
|
||||||
|
- **pytest:** https://docs.pytest.org/
|
||||||
|
- **Gitea API Docs:** https://docs.gitea.com/api/
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
Ready to build! 🚀
|
||||||
944
docs/references/projman-pmo/two-mcp-architecture-guide.md
Normal file
944
docs/references/projman-pmo/two-mcp-architecture-guide.md
Normal file
@@ -0,0 +1,944 @@
|
|||||||
|
# Two MCP Server Architecture - Implementation Guide
|
||||||
|
|
||||||
|
## Overview
|
||||||
|
|
||||||
|
The projman plugin now uses **two separate MCP servers**:
|
||||||
|
1. **Gitea MCP Server** - Issues, labels, repository management
|
||||||
|
2. **Wiki.js MCP Server** - Documentation, lessons learned, knowledge base
|
||||||
|
|
||||||
|
This separation provides better maintainability, independent configuration, and leverages Wiki.js's superior documentation features.
|
||||||
|
|
||||||
|
> **⚠️ IMPORTANT:** For the definitive repository structure and configuration paths, refer to [CORRECT-ARCHITECTURE.md](./CORRECT-ARCHITECTURE.md). This guide provides detailed implementation examples and architectural deep-dive.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wiki.js Structure at Hyper Hive Labs
|
||||||
|
|
||||||
|
### Company-Wide Organization
|
||||||
|
|
||||||
|
```
|
||||||
|
Wiki.js Instance: https://wiki.hyperhivelabs.com
|
||||||
|
└── /hyper-hive-labs/ # Base path for all HHL content
|
||||||
|
├── projects/ # Project-specific documentation
|
||||||
|
│ ├── cuisineflow/
|
||||||
|
│ │ ├── lessons-learned/
|
||||||
|
│ │ │ ├── sprints/
|
||||||
|
│ │ │ │ ├── sprint-01-auth.md
|
||||||
|
│ │ │ │ ├── sprint-02-api.md
|
||||||
|
│ │ │ │ └── ...
|
||||||
|
│ │ │ ├── patterns/
|
||||||
|
│ │ │ │ ├── service-extraction.md
|
||||||
|
│ │ │ │ └── database-migration.md
|
||||||
|
│ │ │ └── INDEX.md
|
||||||
|
│ │ └── documentation/
|
||||||
|
│ │ ├── architecture/
|
||||||
|
│ │ ├── api/
|
||||||
|
│ │ └── deployment/
|
||||||
|
│ ├── cuisineflow-site/
|
||||||
|
│ │ ├── lessons-learned/
|
||||||
|
│ │ └── documentation/
|
||||||
|
│ ├── intuit-engine/
|
||||||
|
│ │ ├── lessons-learned/
|
||||||
|
│ │ └── documentation/
|
||||||
|
│ └── hhl-site/
|
||||||
|
│ ├── lessons-learned/
|
||||||
|
│ └── documentation/
|
||||||
|
├── company/ # Company-wide documentation
|
||||||
|
│ ├── processes/
|
||||||
|
│ │ ├── onboarding.md
|
||||||
|
│ │ ├── deployment.md
|
||||||
|
│ │ └── code-review.md
|
||||||
|
│ ├── standards/
|
||||||
|
│ │ ├── python-style-guide.md
|
||||||
|
│ │ ├── api-design.md
|
||||||
|
│ │ └── security.md
|
||||||
|
│ └── tools/
|
||||||
|
│ ├── gitea-guide.md
|
||||||
|
│ ├── wikijs-guide.md
|
||||||
|
│ └── claude-plugins.md
|
||||||
|
└── shared/ # Cross-project resources
|
||||||
|
├── architecture-patterns/
|
||||||
|
│ ├── microservices.md
|
||||||
|
│ ├── api-gateway.md
|
||||||
|
│ └── database-per-service.md
|
||||||
|
├── best-practices/
|
||||||
|
│ ├── error-handling.md
|
||||||
|
│ ├── logging.md
|
||||||
|
│ └── testing.md
|
||||||
|
└── tech-stack/
|
||||||
|
├── python-ecosystem.md
|
||||||
|
├── docker.md
|
||||||
|
└── ci-cd.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Configuration Architecture
|
||||||
|
|
||||||
|
### System-Level Configuration
|
||||||
|
|
||||||
|
**File: `~/.config/claude/gitea.env`**
|
||||||
|
```bash
|
||||||
|
GITEA_API_URL=https://gitea.hyperhivelabs.com/api/v1
|
||||||
|
GITEA_API_TOKEN=your_gitea_token_here
|
||||||
|
GITEA_OWNER=hyperhivelabs
|
||||||
|
```
|
||||||
|
|
||||||
|
**File: `~/.config/claude/wikijs.env`**
|
||||||
|
```bash
|
||||||
|
WIKIJS_API_URL=https://wiki.hyperhivelabs.com/graphql
|
||||||
|
WIKIJS_API_TOKEN=your_wikijs_token_here
|
||||||
|
WIKIJS_BASE_PATH=/hyper-hive-labs
|
||||||
|
```
|
||||||
|
|
||||||
|
**Why separate files?**
|
||||||
|
- Different services, different authentication
|
||||||
|
- Can update one without affecting the other
|
||||||
|
- Clear separation of concerns
|
||||||
|
- Easier to revoke/rotate tokens per service
|
||||||
|
|
||||||
|
### Project-Level Configuration
|
||||||
|
|
||||||
|
**File: `project-root/.env`**
|
||||||
|
```bash
|
||||||
|
# Gitea repository name
|
||||||
|
GITEA_REPO=cuisineflow
|
||||||
|
|
||||||
|
# Wiki.js project path (relative to /hyper-hive-labs)
|
||||||
|
WIKIJS_PROJECT=projects/cuisineflow
|
||||||
|
```
|
||||||
|
|
||||||
|
**Path Resolution:**
|
||||||
|
- Full Wiki.js path = `{WIKIJS_BASE_PATH}/{WIKIJS_PROJECT}`
|
||||||
|
- For cuisineflow: `/hyper-hive-labs/projects/cuisineflow`
|
||||||
|
- For intuit-engine: `/hyper-hive-labs/projects/intuit-engine`
|
||||||
|
|
||||||
|
### PMO Configuration (No Project Scope)
|
||||||
|
|
||||||
|
**PMO operates at company level:**
|
||||||
|
- **Gitea**: No `GITEA_REPO` → accesses all repos
|
||||||
|
- **Wiki.js**: No `WIKIJS_PROJECT` → accesses entire `/hyper-hive-labs` namespace
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Plugin Structure
|
||||||
|
|
||||||
|
### Repository Structure (CORRECT)
|
||||||
|
|
||||||
|
```
|
||||||
|
hyperhivelabs/claude-plugins/
|
||||||
|
├── mcp-servers/ # SHARED by both plugins
|
||||||
|
│ ├── gitea/
|
||||||
|
│ │ ├── .venv/
|
||||||
|
│ │ ├── requirements.txt
|
||||||
|
│ │ │ # anthropic-sdk>=0.18.0
|
||||||
|
│ │ │ # python-dotenv>=1.0.0
|
||||||
|
│ │ │ # requests>=2.31.0
|
||||||
|
│ │ │ # pydantic>=2.5.0
|
||||||
|
│ │ ├── .env.example
|
||||||
|
│ │ ├── mcp_server/
|
||||||
|
│ │ │ ├── __init__.py
|
||||||
|
│ │ │ ├── server.py
|
||||||
|
│ │ │ ├── config.py
|
||||||
|
│ │ │ ├── gitea_client.py
|
||||||
|
│ │ │ └── tools/
|
||||||
|
│ │ │ ├── issues.py
|
||||||
|
│ │ │ └── labels.py
|
||||||
|
│ │ └── tests/
|
||||||
|
│ │ ├── test_config.py
|
||||||
|
│ │ ├── test_gitea_client.py
|
||||||
|
│ │ └── test_tools.py
|
||||||
|
│ └── wikijs/
|
||||||
|
│ ├── .venv/
|
||||||
|
│ ├── requirements.txt
|
||||||
|
│ │ # anthropic-sdk>=0.18.0
|
||||||
|
│ │ # python-dotenv>=1.0.0
|
||||||
|
│ │ # gql>=3.4.0
|
||||||
|
│ │ # aiohttp>=3.9.0
|
||||||
|
│ │ # pydantic>=2.5.0
|
||||||
|
│ ├── .env.example
|
||||||
|
│ ├── mcp_server/
|
||||||
|
│ │ ├── __init__.py
|
||||||
|
│ │ ├── server.py
|
||||||
|
│ │ ├── config.py
|
||||||
|
│ │ ├── wikijs_client.py
|
||||||
|
│ │ └── tools/
|
||||||
|
│ │ ├── pages.py
|
||||||
|
│ │ ├── lessons_learned.py
|
||||||
|
│ │ └── documentation.py
|
||||||
|
│ └── tests/
|
||||||
|
│ ├── test_config.py
|
||||||
|
│ ├── test_wikijs_client.py
|
||||||
|
│ └── test_tools.py
|
||||||
|
├── projman/ # Project plugin
|
||||||
|
│ ├── .claude-plugin/
|
||||||
|
│ │ └── plugin.json
|
||||||
|
│ ├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
│ ├── commands/
|
||||||
|
│ │ ├── sprint-plan.md
|
||||||
|
│ │ ├── sprint-start.md
|
||||||
|
│ │ ├── sprint-status.md
|
||||||
|
│ │ ├── sprint-close.md
|
||||||
|
│ │ └── labels-sync.md
|
||||||
|
│ ├── agents/
|
||||||
|
│ │ ├── planner.md
|
||||||
|
│ │ ├── orchestrator.md
|
||||||
|
│ │ └── executor.md
|
||||||
|
│ ├── skills/
|
||||||
|
│ │ └── label-taxonomy/
|
||||||
|
│ │ └── labels-reference.md
|
||||||
|
│ ├── README.md
|
||||||
|
│ └── CONFIGURATION.md
|
||||||
|
└── projman-pmo/ # PMO plugin
|
||||||
|
├── .claude-plugin/
|
||||||
|
│ └── plugin.json
|
||||||
|
├── .mcp.json # Points to ../mcp-servers/
|
||||||
|
├── commands/
|
||||||
|
│ ├── pmo-status.md
|
||||||
|
│ ├── pmo-priorities.md
|
||||||
|
│ ├── pmo-dependencies.md
|
||||||
|
│ └── pmo-schedule.md
|
||||||
|
├── agents/
|
||||||
|
│ └── pmo-coordinator.md
|
||||||
|
└── README.md
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MCP Configuration Files
|
||||||
|
|
||||||
|
### projman .mcp.json (Project-Scoped)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"gitea-projman": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"GITEA_API_URL": "${GITEA_API_URL}",
|
||||||
|
"GITEA_API_TOKEN": "${GITEA_API_TOKEN}",
|
||||||
|
"GITEA_OWNER": "${GITEA_OWNER}",
|
||||||
|
"GITEA_REPO": "${GITEA_REPO}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wikijs-projman": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"WIKIJS_API_URL": "${WIKIJS_API_URL}",
|
||||||
|
"WIKIJS_API_TOKEN": "${WIKIJS_API_TOKEN}",
|
||||||
|
"WIKIJS_BASE_PATH": "${WIKIJS_BASE_PATH}",
|
||||||
|
"WIKIJS_PROJECT": "${WIKIJS_PROJECT}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### projman-pmo .mcp.json (Company-Wide)
|
||||||
|
|
||||||
|
```json
|
||||||
|
{
|
||||||
|
"mcpServers": {
|
||||||
|
"gitea-pmo": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea",
|
||||||
|
"GITEA_API_URL": "${GITEA_API_URL}",
|
||||||
|
"GITEA_API_TOKEN": "${GITEA_API_TOKEN}",
|
||||||
|
"GITEA_OWNER": "${GITEA_OWNER}"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"wikijs-pmo": {
|
||||||
|
"command": "python",
|
||||||
|
"args": ["-m", "mcp_server.server"],
|
||||||
|
"cwd": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"env": {
|
||||||
|
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/wikijs",
|
||||||
|
"WIKIJS_API_URL": "${WIKIJS_API_URL}",
|
||||||
|
"WIKIJS_API_TOKEN": "${WIKIJS_API_TOKEN}",
|
||||||
|
"WIKIJS_BASE_PATH": "${WIKIJS_BASE_PATH}"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
**Critical Notes:**
|
||||||
|
- Both plugins reference `../mcp-servers/` (shared location at repository root)
|
||||||
|
- **projman**: Includes `GITEA_REPO` and `WIKIJS_PROJECT` for project-scoped operations
|
||||||
|
- **projman-pmo**: Omits project-specific variables for company-wide operations
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Wiki.js MCP Server Implementation
|
||||||
|
|
||||||
|
### Configuration Loader
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-wikijs/mcp_server/config.py
|
||||||
|
from pathlib import Path
|
||||||
|
from dotenv import load_dotenv
|
||||||
|
import os
|
||||||
|
from typing import Dict, Optional
|
||||||
|
|
||||||
|
class WikiJSConfig:
|
||||||
|
"""Hybrid configuration loader for Wiki.js"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.api_url: Optional[str] = None
|
||||||
|
self.api_token: Optional[str] = None
|
||||||
|
self.base_path: Optional[str] = None
|
||||||
|
self.project_path: Optional[str] = None
|
||||||
|
self.full_path: Optional[str] = None
|
||||||
|
|
||||||
|
def load(self) -> Dict[str, str]:
|
||||||
|
"""
|
||||||
|
Load Wiki.js configuration from system and project levels.
|
||||||
|
Composes full path from base_path + project_path.
|
||||||
|
"""
|
||||||
|
# Load system config
|
||||||
|
system_config = Path.home() / '.config' / 'claude' / 'wikijs.env'
|
||||||
|
if system_config.exists():
|
||||||
|
load_dotenv(system_config)
|
||||||
|
else:
|
||||||
|
raise FileNotFoundError(
|
||||||
|
f"System config not found: {system_config}\n"
|
||||||
|
"Create it with: cat > ~/.config/claude/wikijs.env"
|
||||||
|
)
|
||||||
|
|
||||||
|
# Load project config (if exists, optional for PMO)
|
||||||
|
project_config = Path.cwd() / '.env'
|
||||||
|
if project_config.exists():
|
||||||
|
load_dotenv(project_config, override=True)
|
||||||
|
|
||||||
|
# Extract values
|
||||||
|
self.api_url = os.getenv('WIKIJS_API_URL')
|
||||||
|
self.api_token = os.getenv('WIKIJS_API_TOKEN')
|
||||||
|
self.base_path = os.getenv('WIKIJS_BASE_PATH') # /hyper-hive-labs
|
||||||
|
self.project_path = os.getenv('WIKIJS_PROJECT') # projects/cuisineflow (optional)
|
||||||
|
|
||||||
|
# Compose full path
|
||||||
|
if self.project_path:
|
||||||
|
self.full_path = f"{self.base_path}/{self.project_path}"
|
||||||
|
else:
|
||||||
|
# PMO mode - entire company namespace
|
||||||
|
self.full_path = self.base_path
|
||||||
|
|
||||||
|
# Validate required variables
|
||||||
|
self._validate()
|
||||||
|
|
||||||
|
return {
|
||||||
|
'api_url': self.api_url,
|
||||||
|
'api_token': self.api_token,
|
||||||
|
'base_path': self.base_path,
|
||||||
|
'project_path': self.project_path,
|
||||||
|
'full_path': self.full_path
|
||||||
|
}
|
||||||
|
|
||||||
|
def _validate(self) -> None:
|
||||||
|
"""Validate that required configuration is present"""
|
||||||
|
required = {
|
||||||
|
'WIKIJS_API_URL': self.api_url,
|
||||||
|
'WIKIJS_API_TOKEN': self.api_token,
|
||||||
|
'WIKIJS_BASE_PATH': self.base_path
|
||||||
|
}
|
||||||
|
|
||||||
|
missing = [key for key, value in required.items() if not value]
|
||||||
|
|
||||||
|
if missing:
|
||||||
|
raise ValueError(
|
||||||
|
f"Missing required configuration: {', '.join(missing)}\n"
|
||||||
|
"Check your ~/.config/claude/wikijs.env file"
|
||||||
|
)
|
||||||
|
```
|
||||||
|
|
||||||
|
### GraphQL Client
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-wikijs/mcp_server/wikijs_client.py
|
||||||
|
from gql import gql, Client
|
||||||
|
from gql.transport.aiohttp import AIOHTTPTransport
|
||||||
|
from typing import List, Dict, Optional
|
||||||
|
from .config import WikiJSConfig
|
||||||
|
|
||||||
|
class WikiJSClient:
|
||||||
|
"""Client for interacting with Wiki.js GraphQL API"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
config = WikiJSConfig()
|
||||||
|
config_dict = config.load()
|
||||||
|
|
||||||
|
self.api_url = config_dict['api_url']
|
||||||
|
self.api_token = config_dict['api_token']
|
||||||
|
self.base_path = config_dict['base_path']
|
||||||
|
self.project_path = config_dict.get('project_path')
|
||||||
|
self.full_path = config_dict['full_path']
|
||||||
|
|
||||||
|
# Set up GraphQL client
|
||||||
|
transport = AIOHTTPTransport(
|
||||||
|
url=self.api_url,
|
||||||
|
headers={'Authorization': f'Bearer {self.api_token}'}
|
||||||
|
)
|
||||||
|
self.client = Client(
|
||||||
|
transport=transport,
|
||||||
|
fetch_schema_from_transport=True
|
||||||
|
)
|
||||||
|
|
||||||
|
async def search_pages(
|
||||||
|
self,
|
||||||
|
query: str,
|
||||||
|
path: Optional[str] = None,
|
||||||
|
tags: Optional[List[str]] = None
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Search pages in Wiki.js within a specific path.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Search query string
|
||||||
|
path: Optional path to search within (defaults to full_path)
|
||||||
|
tags: Optional list of tags to filter by
|
||||||
|
"""
|
||||||
|
search_path = path or self.full_path
|
||||||
|
|
||||||
|
gql_query = gql("""
|
||||||
|
query SearchPages($query: String!, $path: String) {
|
||||||
|
pages {
|
||||||
|
search(query: $query, path: $path) {
|
||||||
|
results {
|
||||||
|
id
|
||||||
|
path
|
||||||
|
title
|
||||||
|
description
|
||||||
|
tags
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
result = await self.client.execute(
|
||||||
|
gql_query,
|
||||||
|
variable_values={'query': query, 'path': search_path}
|
||||||
|
)
|
||||||
|
|
||||||
|
pages = result['pages']['search']['results']
|
||||||
|
|
||||||
|
# Filter by tags if specified
|
||||||
|
if tags:
|
||||||
|
pages = [
|
||||||
|
p for p in pages
|
||||||
|
if any(tag in p['tags'] for tag in tags)
|
||||||
|
]
|
||||||
|
|
||||||
|
return pages
|
||||||
|
|
||||||
|
async def get_page(self, path: str) -> Dict:
|
||||||
|
"""Fetch a specific page by path"""
|
||||||
|
gql_query = gql("""
|
||||||
|
query GetPage($path: String!) {
|
||||||
|
pages {
|
||||||
|
single(path: $path) {
|
||||||
|
id
|
||||||
|
path
|
||||||
|
title
|
||||||
|
description
|
||||||
|
content
|
||||||
|
tags
|
||||||
|
createdAt
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
result = await self.client.execute(
|
||||||
|
gql_query,
|
||||||
|
variable_values={'path': path}
|
||||||
|
)
|
||||||
|
return result['pages']['single']
|
||||||
|
|
||||||
|
async def create_page(
|
||||||
|
self,
|
||||||
|
path: str,
|
||||||
|
title: str,
|
||||||
|
content: str,
|
||||||
|
tags: List[str],
|
||||||
|
description: str = ""
|
||||||
|
) -> Dict:
|
||||||
|
"""
|
||||||
|
Create a new page in Wiki.js.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
path: Full path for the page (e.g., /hyper-hive-labs/projects/cuisineflow/lessons-learned/sprints/sprint-01)
|
||||||
|
title: Page title
|
||||||
|
content: Page content (markdown)
|
||||||
|
tags: List of tags
|
||||||
|
description: Optional description
|
||||||
|
"""
|
||||||
|
gql_mutation = gql("""
|
||||||
|
mutation CreatePage(
|
||||||
|
$path: String!,
|
||||||
|
$title: String!,
|
||||||
|
$content: String!,
|
||||||
|
$tags: [String]!,
|
||||||
|
$description: String
|
||||||
|
) {
|
||||||
|
pages {
|
||||||
|
create(
|
||||||
|
path: $path,
|
||||||
|
title: $title,
|
||||||
|
content: $content,
|
||||||
|
tags: $tags,
|
||||||
|
description: $description,
|
||||||
|
isPublished: true,
|
||||||
|
editor: "markdown"
|
||||||
|
) {
|
||||||
|
responseResult {
|
||||||
|
succeeded
|
||||||
|
errorCode
|
||||||
|
message
|
||||||
|
}
|
||||||
|
page {
|
||||||
|
id
|
||||||
|
path
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
result = await self.client.execute(
|
||||||
|
gql_mutation,
|
||||||
|
variable_values={
|
||||||
|
'path': path,
|
||||||
|
'title': title,
|
||||||
|
'content': content,
|
||||||
|
'tags': tags,
|
||||||
|
'description': description
|
||||||
|
}
|
||||||
|
)
|
||||||
|
return result['pages']['create']
|
||||||
|
|
||||||
|
async def update_page(
|
||||||
|
self,
|
||||||
|
page_id: int,
|
||||||
|
content: str,
|
||||||
|
tags: Optional[List[str]] = None
|
||||||
|
) -> Dict:
|
||||||
|
"""Update existing page"""
|
||||||
|
variables = {
|
||||||
|
'id': page_id,
|
||||||
|
'content': content
|
||||||
|
}
|
||||||
|
|
||||||
|
if tags is not None:
|
||||||
|
variables['tags'] = tags
|
||||||
|
|
||||||
|
gql_mutation = gql("""
|
||||||
|
mutation UpdatePage(
|
||||||
|
$id: Int!,
|
||||||
|
$content: String!,
|
||||||
|
$tags: [String]
|
||||||
|
) {
|
||||||
|
pages {
|
||||||
|
update(
|
||||||
|
id: $id,
|
||||||
|
content: $content,
|
||||||
|
tags: $tags
|
||||||
|
) {
|
||||||
|
responseResult {
|
||||||
|
succeeded
|
||||||
|
errorCode
|
||||||
|
message
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
result = await self.client.execute(gql_mutation, variable_values=variables)
|
||||||
|
return result['pages']['update']
|
||||||
|
|
||||||
|
async def list_pages(self, path: str) -> List[Dict]:
|
||||||
|
"""List all pages within a path"""
|
||||||
|
gql_query = gql("""
|
||||||
|
query ListPages($path: String!) {
|
||||||
|
pages {
|
||||||
|
list(path: $path, orderBy: TITLE) {
|
||||||
|
id
|
||||||
|
path
|
||||||
|
title
|
||||||
|
description
|
||||||
|
tags
|
||||||
|
updatedAt
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
""")
|
||||||
|
|
||||||
|
result = await self.client.execute(
|
||||||
|
gql_query,
|
||||||
|
variable_values={'path': path}
|
||||||
|
)
|
||||||
|
return result['pages']['list']
|
||||||
|
|
||||||
|
# Lessons Learned Specific Methods
|
||||||
|
|
||||||
|
async def create_lesson(
|
||||||
|
self,
|
||||||
|
sprint_name: str,
|
||||||
|
lesson_content: str,
|
||||||
|
tags: List[str]
|
||||||
|
) -> Dict:
|
||||||
|
"""
|
||||||
|
Create a lessons learned document for a sprint.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
sprint_name: Sprint identifier (e.g., "sprint-16-intuit-engine")
|
||||||
|
lesson_content: Full lesson markdown content
|
||||||
|
tags: Tags for categorization
|
||||||
|
"""
|
||||||
|
# Compose path within project's lessons-learned/sprints/
|
||||||
|
lesson_path = f"{self.full_path}/lessons-learned/sprints/{sprint_name}"
|
||||||
|
title = f"Sprint {sprint_name.split('-')[1]}: {' '.join(sprint_name.split('-')[2:]).title()}"
|
||||||
|
|
||||||
|
return await self.create_page(
|
||||||
|
path=lesson_path,
|
||||||
|
title=title,
|
||||||
|
content=lesson_content,
|
||||||
|
tags=tags,
|
||||||
|
description=f"Lessons learned from {sprint_name}"
|
||||||
|
)
|
||||||
|
|
||||||
|
async def search_lessons(
|
||||||
|
self,
|
||||||
|
query: str,
|
||||||
|
tags: Optional[List[str]] = None
|
||||||
|
) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Search lessons learned within the current project.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
query: Search keywords
|
||||||
|
tags: Optional tags to filter by
|
||||||
|
"""
|
||||||
|
lessons_path = f"{self.full_path}/lessons-learned"
|
||||||
|
return await self.search_pages(
|
||||||
|
query=query,
|
||||||
|
path=lessons_path,
|
||||||
|
tags=tags
|
||||||
|
)
|
||||||
|
|
||||||
|
# PMO Multi-Project Methods
|
||||||
|
|
||||||
|
async def search_all_projects(
|
||||||
|
self,
|
||||||
|
query: str,
|
||||||
|
tags: Optional[List[str]] = None
|
||||||
|
) -> Dict[str, List[Dict]]:
|
||||||
|
"""
|
||||||
|
Search lessons across all projects (PMO mode).
|
||||||
|
Returns results grouped by project.
|
||||||
|
"""
|
||||||
|
all_projects_path = f"{self.base_path}/projects"
|
||||||
|
results = await self.search_pages(
|
||||||
|
query=query,
|
||||||
|
path=all_projects_path,
|
||||||
|
tags=tags
|
||||||
|
)
|
||||||
|
|
||||||
|
# Group by project
|
||||||
|
by_project = {}
|
||||||
|
for result in results:
|
||||||
|
# Extract project name from path
|
||||||
|
# e.g., "/hyper-hive-labs/projects/cuisineflow/..." -> "cuisineflow"
|
||||||
|
path_parts = result['path'].split('/')
|
||||||
|
if len(path_parts) >= 4:
|
||||||
|
project = path_parts[3]
|
||||||
|
if project not in by_project:
|
||||||
|
by_project[project] = []
|
||||||
|
by_project[project].append(result)
|
||||||
|
|
||||||
|
return by_project
|
||||||
|
|
||||||
|
async def get_shared_docs(self, category: str) -> List[Dict]:
|
||||||
|
"""
|
||||||
|
Access company-wide shared documentation.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
category: Category within shared/ (e.g., "architecture-patterns", "best-practices")
|
||||||
|
"""
|
||||||
|
shared_path = f"{self.base_path}/shared/{category}"
|
||||||
|
return await self.list_pages(path=shared_path)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## MCP Tools Structure
|
||||||
|
|
||||||
|
### Gitea MCP Tools
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-gitea/mcp_server/tools/issues.py
|
||||||
|
class IssueTools:
|
||||||
|
def __init__(self, gitea_client):
|
||||||
|
self.gitea = gitea_client
|
||||||
|
|
||||||
|
async def list_issues(self, state='open', labels=None):
|
||||||
|
"""List issues in current repository"""
|
||||||
|
return await self.gitea.list_issues(state=state, labels=labels)
|
||||||
|
|
||||||
|
async def get_issue(self, issue_number):
|
||||||
|
"""Get specific issue details"""
|
||||||
|
return await self.gitea.get_issue(issue_number)
|
||||||
|
|
||||||
|
async def create_issue(self, title, body, labels=None):
|
||||||
|
"""Create new issue"""
|
||||||
|
return await self.gitea.create_issue(title, body, labels)
|
||||||
|
|
||||||
|
# ... other issue tools
|
||||||
|
|
||||||
|
# mcp-gitea/mcp_server/tools/labels.py
|
||||||
|
class LabelTools:
|
||||||
|
def __init__(self, gitea_client):
|
||||||
|
self.gitea = gitea_client
|
||||||
|
|
||||||
|
async def get_labels(self):
|
||||||
|
"""Get all labels from repository"""
|
||||||
|
return await self.gitea.get_labels()
|
||||||
|
|
||||||
|
async def suggest_labels(self, context):
|
||||||
|
"""Suggest appropriate labels based on context"""
|
||||||
|
# Label suggestion logic using taxonomy
|
||||||
|
pass
|
||||||
|
```
|
||||||
|
|
||||||
|
### Wiki.js MCP Tools
|
||||||
|
|
||||||
|
```python
|
||||||
|
# mcp-wikijs/mcp_server/tools/pages.py
|
||||||
|
class PageTools:
|
||||||
|
def __init__(self, wikijs_client):
|
||||||
|
self.wikijs = wikijs_client
|
||||||
|
|
||||||
|
async def search_pages(self, query, path=None, tags=None):
|
||||||
|
"""Search Wiki.js pages"""
|
||||||
|
return await self.wikijs.search_pages(query, path, tags)
|
||||||
|
|
||||||
|
async def get_page(self, path):
|
||||||
|
"""Get specific page"""
|
||||||
|
return await self.wikijs.get_page(path)
|
||||||
|
|
||||||
|
async def create_page(self, path, title, content, tags):
|
||||||
|
"""Create new page"""
|
||||||
|
return await self.wikijs.create_page(path, title, content, tags)
|
||||||
|
|
||||||
|
# ... other page tools
|
||||||
|
|
||||||
|
# mcp-wikijs/mcp_server/tools/lessons_learned.py
|
||||||
|
class LessonsLearnedTools:
|
||||||
|
def __init__(self, wikijs_client):
|
||||||
|
self.wikijs = wikijs_client
|
||||||
|
|
||||||
|
async def create_lesson(self, sprint_name, content, tags):
|
||||||
|
"""Create lessons learned document"""
|
||||||
|
return await self.wikijs.create_lesson(sprint_name, content, tags)
|
||||||
|
|
||||||
|
async def search_lessons(self, query, tags=None):
|
||||||
|
"""Search past lessons"""
|
||||||
|
return await self.wikijs.search_lessons(query, tags)
|
||||||
|
|
||||||
|
async def search_all_projects(self, query, tags=None):
|
||||||
|
"""Search lessons across all projects (PMO)"""
|
||||||
|
return await self.wikijs.search_all_projects(query, tags)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Setup Instructions
|
||||||
|
|
||||||
|
### 1. System Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Create config directory
|
||||||
|
mkdir -p ~/.config/claude
|
||||||
|
|
||||||
|
# Create Gitea config
|
||||||
|
cat > ~/.config/claude/gitea.env << EOF
|
||||||
|
GITEA_API_URL=https://gitea.hyperhivelabs.com/api/v1
|
||||||
|
GITEA_API_TOKEN=your_gitea_token
|
||||||
|
GITEA_OWNER=hyperhivelabs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Create Wiki.js config
|
||||||
|
cat > ~/.config/claude/wikijs.env << EOF
|
||||||
|
WIKIJS_API_URL=https://wiki.hyperhivelabs.com/graphql
|
||||||
|
WIKIJS_API_TOKEN=your_wikijs_token
|
||||||
|
WIKIJS_BASE_PATH=/hyper-hive-labs
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Secure config files
|
||||||
|
chmod 600 ~/.config/claude/*.env
|
||||||
|
```
|
||||||
|
|
||||||
|
### 2. Project Configuration
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# In each project root
|
||||||
|
cat > .env << EOF
|
||||||
|
GITEA_REPO=cuisineflow
|
||||||
|
WIKIJS_PROJECT=projects/cuisineflow
|
||||||
|
EOF
|
||||||
|
|
||||||
|
# Add to .gitignore
|
||||||
|
echo ".env" >> .gitignore
|
||||||
|
```
|
||||||
|
|
||||||
|
### 3. Install MCP Servers
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Gitea MCP Server
|
||||||
|
cd /path/to/claude-plugins/mcp-servers/gitea
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
|
||||||
|
# Wiki.js MCP Server
|
||||||
|
cd /path/to/claude-plugins/mcp-servers/wikijs
|
||||||
|
python -m venv .venv
|
||||||
|
source .venv/bin/activate
|
||||||
|
pip install -r requirements.txt
|
||||||
|
```
|
||||||
|
|
||||||
|
### 4. Initialize Wiki.js Structure
|
||||||
|
|
||||||
|
Create the base structure in Wiki.js web interface:
|
||||||
|
1. Navigate to https://wiki.hyperhivelabs.com
|
||||||
|
2. Create `/hyper-hive-labs` page
|
||||||
|
3. Create `/hyper-hive-labs/projects` page
|
||||||
|
4. Create `/hyper-hive-labs/company` page
|
||||||
|
5. Create `/hyper-hive-labs/shared` page
|
||||||
|
|
||||||
|
Or use the Wiki.js API:
|
||||||
|
```python
|
||||||
|
# One-time setup script
|
||||||
|
import asyncio
|
||||||
|
from wikijs_client import WikiJSClient
|
||||||
|
|
||||||
|
async def initialize_wiki_structure():
|
||||||
|
client = WikiJSClient()
|
||||||
|
|
||||||
|
# Create base pages
|
||||||
|
await client.create_page(
|
||||||
|
path="/hyper-hive-labs",
|
||||||
|
title="Hyper Hive Labs",
|
||||||
|
content="# Hyper Hive Labs Documentation",
|
||||||
|
tags=["company"]
|
||||||
|
)
|
||||||
|
|
||||||
|
await client.create_page(
|
||||||
|
path="/hyper-hive-labs/projects",
|
||||||
|
title="Projects",
|
||||||
|
content="# Project Documentation",
|
||||||
|
tags=["projects"]
|
||||||
|
)
|
||||||
|
|
||||||
|
# ... create other base pages
|
||||||
|
|
||||||
|
asyncio.run(initialize_wiki_structure())
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Benefits of This Architecture
|
||||||
|
|
||||||
|
### 1. Separation of Concerns
|
||||||
|
- **Gitea MCP**: Project tracking, issues, labels
|
||||||
|
- **Wiki.js MCP**: Knowledge management, documentation
|
||||||
|
|
||||||
|
### 2. Independent Configuration
|
||||||
|
- Update Gitea credentials without affecting Wiki.js
|
||||||
|
- Different token expiration policies
|
||||||
|
- Independent service availability
|
||||||
|
|
||||||
|
### 3. Better Documentation Features
|
||||||
|
- Wiki.js rich editor
|
||||||
|
- Built-in search and indexing
|
||||||
|
- Tag system
|
||||||
|
- Version history
|
||||||
|
- Access control
|
||||||
|
- Web-based review and editing
|
||||||
|
|
||||||
|
### 4. Company-Wide Knowledge Base
|
||||||
|
- Shared documentation accessible to all projects
|
||||||
|
- Cross-project lesson learning
|
||||||
|
- Best practices repository
|
||||||
|
- Onboarding materials
|
||||||
|
- Technical standards
|
||||||
|
|
||||||
|
### 5. Scalability
|
||||||
|
- Add new projects easily
|
||||||
|
- Grow company documentation organically
|
||||||
|
- PMO has visibility across everything
|
||||||
|
- Individual projects stay focused
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Migration from Single MCP
|
||||||
|
|
||||||
|
If you have existing Wiki content in Git:
|
||||||
|
|
||||||
|
```python
|
||||||
|
# Migration script
|
||||||
|
import asyncio
|
||||||
|
from wikijs_client import WikiJSClient
|
||||||
|
from pathlib import Path
|
||||||
|
|
||||||
|
async def migrate_lessons_to_wikijs():
|
||||||
|
"""Migrate existing lessons learned from Git to Wiki.js"""
|
||||||
|
client = WikiJSClient()
|
||||||
|
|
||||||
|
# Read existing markdown files
|
||||||
|
lessons_dir = Path("wiki/lessons-learned/sprints")
|
||||||
|
|
||||||
|
for lesson_file in lessons_dir.glob("*.md"):
|
||||||
|
content = lesson_file.read_text()
|
||||||
|
sprint_name = lesson_file.stem
|
||||||
|
|
||||||
|
# Extract tags from content (e.g., from frontmatter or hashtags)
|
||||||
|
tags = extract_tags(content)
|
||||||
|
|
||||||
|
# Create in Wiki.js
|
||||||
|
await client.create_lesson(
|
||||||
|
sprint_name=sprint_name,
|
||||||
|
lesson_content=content,
|
||||||
|
tags=tags
|
||||||
|
)
|
||||||
|
|
||||||
|
print(f"Migrated: {sprint_name}")
|
||||||
|
|
||||||
|
asyncio.run(migrate_lessons_to_wikijs())
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## Next Steps
|
||||||
|
|
||||||
|
1. **Set up Wiki.js instance** if not already done
|
||||||
|
2. **Create base structure** in Wiki.js
|
||||||
|
3. **Implement both MCP servers** (Phase 1.1a and 1.1b)
|
||||||
|
4. **Test configuration** with both services
|
||||||
|
5. **Migrate existing lessons** (if applicable)
|
||||||
|
6. **Start using with next sprint**
|
||||||
|
|
||||||
|
The two-MCP-server architecture provides a solid foundation for both project-level and company-wide knowledge management!
|
||||||
Reference in New Issue
Block a user