Merge pull request 'plan/documentation-review' (#1) from plan/documentation-review into development
Reviewed-on: hhl/hhl-claude-agents#1
This commit was merged in pull request #1.
This commit is contained in:
2
.gitignore
vendored
2
.gitignore
vendored
@@ -35,7 +35,7 @@ env/
|
||||
|
||||
# VS Code
|
||||
.vscode/
|
||||
*.code-workspace
|
||||
# *.code-workspace
|
||||
|
||||
# Jupyter Notebook
|
||||
.ipynb_checkpoints
|
||||
|
||||
27
CLAUDE.md
27
CLAUDE.md
@@ -258,11 +258,22 @@ hyperhivelabs/claude-plugins/
|
||||
- Plugin works with or without CLAUDE.md
|
||||
|
||||
**Plugin Development:**
|
||||
- Use `claude-plugin-developer` skill for all plugin-related work
|
||||
- Reference when creating/updating plugin manifests, commands, agents, hooks, or MCP servers
|
||||
- Ensures compliance with Anthropic's security requirements and best practices
|
||||
- Provides templates, validation tools, and troubleshooting guidance
|
||||
- Critical for proper plugin structure, path safety, and marketplace publication
|
||||
- **ALWAYS use the `claude-plugin-developer` skill for all plugin-related work**
|
||||
- Invoke the skill when:
|
||||
- Creating new plugin manifests (`plugin.json`)
|
||||
- Developing commands, agents, hooks, or MCP servers
|
||||
- Validating plugin structure and security
|
||||
- Troubleshooting plugin loading issues
|
||||
- Publishing to marketplaces
|
||||
- The skill provides:
|
||||
- Security best practices and validation
|
||||
- Templates and helper scripts
|
||||
- Complete reference documentation
|
||||
- Path safety requirements (`${CLAUDE_PLUGIN_ROOT}`)
|
||||
- Manifest schema validation
|
||||
- **Critical:** Ensures compliance with Anthropic's security requirements
|
||||
- Location: `.claude/skills/claude-plugin-developer/`
|
||||
- Usage: Invoke via Skill tool when working on plugin components
|
||||
|
||||
## Multi-Project Context (PMO Plugin)
|
||||
|
||||
@@ -328,6 +339,12 @@ This repository contains comprehensive planning documentation:
|
||||
- **`docs/projman-python-quickstart.md`** - Python-specific implementation guide
|
||||
- **`docs/two-mcp-architecture-guide.md`** - Deep dive into two-MCP architecture
|
||||
|
||||
**Skills:**
|
||||
- **`.claude/skills/claude-plugin-developer/`** - Plugin development guidance and validation tools
|
||||
- Use this skill for all plugin-related work (manifests, commands, agents, hooks, MCP servers)
|
||||
- Includes security validation, templates, and helper scripts
|
||||
- Invoke via Skill tool when working on plugin components
|
||||
|
||||
**Start with:** `docs/DOCUMENT-INDEX.md` for navigation guidance
|
||||
|
||||
## Recent Updates (Updated: 2025-06-11)
|
||||
|
||||
831
docs/references/MCP-GITEA.md
Normal file
831
docs/references/MCP-GITEA.md
Normal file
@@ -0,0 +1,831 @@
|
||||
# Gitea MCP Server Reference
|
||||
|
||||
## Overview
|
||||
|
||||
The Gitea MCP Server provides integration with Gitea for issue management, label operations, and repository tracking. It's shared by both `projman` and `projman-pmo` plugins, detecting its operating mode based on environment variables.
|
||||
|
||||
**Location:** `mcp-servers/gitea/` (repository root)
|
||||
|
||||
**Key Features:**
|
||||
- Issue CRUD operations
|
||||
- Label taxonomy management (43-label system)
|
||||
- Mode detection (project-scoped vs company-wide)
|
||||
- Hybrid configuration (system + project level)
|
||||
- Python 3.11+ implementation
|
||||
|
||||
---
|
||||
|
||||
## Architecture
|
||||
|
||||
### Mode Detection
|
||||
|
||||
The MCP server operates in two modes based on environment variables:
|
||||
|
||||
**Project Mode (projman):**
|
||||
- When `GITEA_REPO` is present
|
||||
- Operates on single repository
|
||||
- Used by projman plugin
|
||||
|
||||
**Company Mode (pmo):**
|
||||
- When `GITEA_REPO` is absent
|
||||
- Operates on all repositories in organization
|
||||
- Used by projman-pmo plugin
|
||||
|
||||
```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
|
||||
}
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### System-Level Configuration
|
||||
|
||||
**File:** `~/.config/claude/gitea.env`
|
||||
|
||||
```bash
|
||||
GITEA_API_URL=https://gitea.hyperhivelabs.com/api/v1
|
||||
GITEA_API_TOKEN=your_gitea_token
|
||||
GITEA_OWNER=hyperhivelabs
|
||||
```
|
||||
|
||||
**Setup:**
|
||||
```bash
|
||||
# Create config directory
|
||||
mkdir -p ~/.config/claude
|
||||
|
||||
# Create gitea.env
|
||||
cat > ~/.config/claude/gitea.env << EOF
|
||||
GITEA_API_URL=https://gitea.hyperhivelabs.com/api/v1
|
||||
GITEA_API_TOKEN=your_token
|
||||
GITEA_OWNER=hyperhivelabs
|
||||
EOF
|
||||
|
||||
# Secure the file
|
||||
chmod 600 ~/.config/claude/gitea.env
|
||||
```
|
||||
|
||||
### Project-Level Configuration
|
||||
|
||||
**File:** `project-root/.env`
|
||||
|
||||
```bash
|
||||
# Repository name (project mode only)
|
||||
GITEA_REPO=cuisineflow
|
||||
```
|
||||
|
||||
**Setup:**
|
||||
```bash
|
||||
# In each project root
|
||||
echo "GITEA_REPO=cuisineflow" > .env
|
||||
|
||||
# Add to .gitignore
|
||||
echo ".env" >> .gitignore
|
||||
```
|
||||
|
||||
### Configuration Loading Strategy
|
||||
|
||||
```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 GiteaConfig:
|
||||
"""Hybrid configuration loader"""
|
||||
|
||||
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
|
||||
self.mode: str = 'project'
|
||||
|
||||
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
|
||||
|
||||
# Detect mode
|
||||
self.mode = 'project' if self.repo else 'company'
|
||||
|
||||
# Validate required variables
|
||||
self._validate()
|
||||
|
||||
return {
|
||||
'api_url': self.api_url,
|
||||
'api_token': self.api_token,
|
||||
'owner': self.owner,
|
||||
'repo': self.repo,
|
||||
'mode': self.mode
|
||||
}
|
||||
|
||||
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"
|
||||
)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Directory Structure
|
||||
|
||||
```
|
||||
mcp-servers/gitea/
|
||||
├── .venv/ # Python virtual environment
|
||||
├── requirements.txt # Python dependencies
|
||||
├── .env.example # Configuration template
|
||||
├── mcp_server/
|
||||
│ ├── __init__.py
|
||||
│ ├── server.py # MCP server entry point
|
||||
│ ├── config.py # Configuration loader
|
||||
│ ├── gitea_client.py # Gitea API client
|
||||
│ └── tools/
|
||||
│ ├── __init__.py
|
||||
│ ├── issues.py # Issue CRUD tools
|
||||
│ └── labels.py # Label management tools
|
||||
└── tests/
|
||||
├── test_config.py
|
||||
├── test_gitea_client.py
|
||||
└── test_tools.py
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Dependencies
|
||||
|
||||
**File:** `mcp-servers/gitea/requirements.txt`
|
||||
|
||||
```txt
|
||||
anthropic-sdk>=0.18.0 # MCP SDK
|
||||
python-dotenv>=1.0.0 # Environment variable loading
|
||||
requests>=2.31.0 # HTTP client for Gitea API
|
||||
pydantic>=2.5.0 # Data validation
|
||||
pytest>=7.4.3 # Testing framework
|
||||
pytest-asyncio>=0.23.0 # Async testing support
|
||||
```
|
||||
|
||||
**Installation:**
|
||||
```bash
|
||||
cd mcp-servers/gitea
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate # Linux/Mac
|
||||
# or .venv\Scripts\activate # Windows
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Gitea API Client
|
||||
|
||||
```python
|
||||
# mcp-servers/gitea/mcp_server/gitea_client.py
|
||||
import requests
|
||||
from typing import List, Dict, Optional
|
||||
from .config import GiteaConfig
|
||||
|
||||
class GiteaClient:
|
||||
"""Client for interacting with Gitea API"""
|
||||
|
||||
def __init__(self):
|
||||
config = GiteaConfig()
|
||||
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 for PMO
|
||||
self.mode = config_dict['mode']
|
||||
|
||||
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 get_issue(
|
||||
self,
|
||||
issue_number: int,
|
||||
repo: Optional[str] = None
|
||||
) -> Dict:
|
||||
"""Get specific issue details"""
|
||||
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/{issue_number}"
|
||||
response = self.session.get(url)
|
||||
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 update_issue(
|
||||
self,
|
||||
issue_number: int,
|
||||
title: Optional[str] = None,
|
||||
body: Optional[str] = None,
|
||||
state: Optional[str] = None,
|
||||
labels: Optional[List[str]] = None,
|
||||
repo: Optional[str] = None
|
||||
) -> Dict:
|
||||
"""Update existing issue"""
|
||||
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/{issue_number}"
|
||||
data = {}
|
||||
|
||||
if title is not None:
|
||||
data['title'] = title
|
||||
if body is not None:
|
||||
data['body'] = body
|
||||
if state is not None:
|
||||
data['state'] = state
|
||||
if labels is not None:
|
||||
data['labels'] = labels
|
||||
|
||||
response = self.session.patch(url, json=data)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def add_comment(
|
||||
self,
|
||||
issue_number: int,
|
||||
comment: str,
|
||||
repo: Optional[str] = None
|
||||
) -> Dict:
|
||||
"""Add comment to issue"""
|
||||
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/{issue_number}/comments"
|
||||
data = {'body': comment}
|
||||
|
||||
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()
|
||||
|
||||
def get_org_labels(self) -> List[Dict]:
|
||||
"""Get organization-level labels"""
|
||||
url = f"{self.base_url}/orgs/{self.owner}/labels"
|
||||
response = self.session.get(url)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
# PMO-specific methods
|
||||
|
||||
def list_repos(self) -> List[Dict]:
|
||||
"""List all repositories in organization (PMO mode)"""
|
||||
url = f"{self.base_url}/orgs/{self.owner}/repos"
|
||||
response = self.session.get(url)
|
||||
response.raise_for_status()
|
||||
return response.json()
|
||||
|
||||
def aggregate_issues(
|
||||
self,
|
||||
state: str = 'open',
|
||||
labels: Optional[List[str]] = None
|
||||
) -> Dict[str, List[Dict]]:
|
||||
"""
|
||||
Fetch issues across all repositories (PMO mode).
|
||||
Returns dict keyed by repository name.
|
||||
"""
|
||||
repos = self.list_repos()
|
||||
aggregated = {}
|
||||
|
||||
for repo in repos:
|
||||
repo_name = repo['name']
|
||||
try:
|
||||
issues = self.list_issues(
|
||||
state=state,
|
||||
labels=labels,
|
||||
repo=repo_name
|
||||
)
|
||||
if issues:
|
||||
aggregated[repo_name] = issues
|
||||
except Exception as e:
|
||||
# Log error but continue with other repos
|
||||
print(f"Error fetching issues from {repo_name}: {e}")
|
||||
|
||||
return aggregated
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Label Taxonomy System
|
||||
|
||||
### 43-Label System
|
||||
|
||||
**Organization Labels (27):**
|
||||
- Agent/2
|
||||
- Complexity/3
|
||||
- Efforts/5
|
||||
- Priority/4
|
||||
- Risk/3
|
||||
- Source/4
|
||||
- Type/6 (includes Type/Refactor)
|
||||
|
||||
**Repository Labels (16):**
|
||||
- Component/9
|
||||
- Tech/7
|
||||
|
||||
### Label Suggestion Logic
|
||||
|
||||
```python
|
||||
# mcp-servers/gitea/mcp_server/tools/labels.py
|
||||
from typing import List, Dict
|
||||
import re
|
||||
|
||||
class LabelTools:
|
||||
def __init__(self, gitea_client):
|
||||
self.gitea = gitea_client
|
||||
|
||||
async def get_labels(self, repo: str = None) -> List[Dict]:
|
||||
"""Get all labels (org + repo)"""
|
||||
org_labels = self.gitea.get_org_labels()
|
||||
|
||||
if repo or self.gitea.repo:
|
||||
target_repo = repo or self.gitea.repo
|
||||
repo_labels = self.gitea.get_labels(target_repo)
|
||||
return org_labels + repo_labels
|
||||
|
||||
return org_labels
|
||||
|
||||
async def suggest_labels(self, context: str) -> List[str]:
|
||||
"""
|
||||
Analyze context and suggest appropriate labels.
|
||||
|
||||
Args:
|
||||
context: Issue title + description or sprint context
|
||||
"""
|
||||
suggested = []
|
||||
context_lower = context.lower()
|
||||
|
||||
# Type detection (exclusive - only one)
|
||||
if any(word in context_lower for word in ['bug', 'error', 'fix', 'broken']):
|
||||
suggested.append('Type/Bug')
|
||||
elif any(word in context_lower for word in ['refactor', 'extract', 'restructure', 'architecture', 'service extraction']):
|
||||
suggested.append('Type/Refactor')
|
||||
elif any(word in context_lower for word in ['feature', 'add', 'implement', 'new']):
|
||||
suggested.append('Type/Feature')
|
||||
elif any(word in context_lower for word in ['docs', 'documentation', 'readme']):
|
||||
suggested.append('Type/Documentation')
|
||||
elif any(word in context_lower for word in ['test', 'testing', 'spec']):
|
||||
suggested.append('Type/Test')
|
||||
elif any(word in context_lower for word in ['chore', 'maintenance', 'update']):
|
||||
suggested.append('Type/Chore')
|
||||
|
||||
# Priority detection
|
||||
if any(word in context_lower for word in ['critical', 'urgent', 'blocker', 'blocking']):
|
||||
suggested.append('Priority/Critical')
|
||||
elif any(word in context_lower for word in ['high', 'important', 'asap']):
|
||||
suggested.append('Priority/High')
|
||||
elif any(word in context_lower for word in ['low', 'nice-to-have', 'optional']):
|
||||
suggested.append('Priority/Low')
|
||||
else:
|
||||
suggested.append('Priority/Medium')
|
||||
|
||||
# Component detection (based on keywords)
|
||||
component_keywords = {
|
||||
'Component/Backend': ['backend', 'server', 'api', 'database', 'service'],
|
||||
'Component/Frontend': ['frontend', 'ui', 'interface', 'react', 'vue'],
|
||||
'Component/API': ['api', 'endpoint', 'rest', 'graphql'],
|
||||
'Component/Database': ['database', 'db', 'sql', 'migration', 'schema'],
|
||||
'Component/Auth': ['auth', 'authentication', 'login', 'oauth', 'token'],
|
||||
'Component/Deploy': ['deploy', 'deployment', 'docker', 'kubernetes'],
|
||||
'Component/Testing': ['test', 'testing', 'spec', 'jest', 'pytest'],
|
||||
'Component/Docs': ['docs', 'documentation', 'readme', 'guide']
|
||||
}
|
||||
|
||||
for label, keywords in component_keywords.items():
|
||||
if any(keyword in context_lower for keyword in keywords):
|
||||
suggested.append(label)
|
||||
|
||||
# Source detection (based on git branch or context)
|
||||
if 'development' in context_lower or 'dev/' in context_lower:
|
||||
suggested.append('Source/Development')
|
||||
elif 'staging' in context_lower:
|
||||
suggested.append('Source/Staging')
|
||||
elif 'production' in context_lower or 'prod' in context_lower:
|
||||
suggested.append('Source/Production')
|
||||
|
||||
return suggested
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## MCP Tools
|
||||
|
||||
### Issue Tools
|
||||
|
||||
```python
|
||||
# mcp-servers/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, repo=None):
|
||||
"""List issues in repository"""
|
||||
return self.gitea.list_issues(state=state, labels=labels, repo=repo)
|
||||
|
||||
async def get_issue(self, issue_number, repo=None):
|
||||
"""Get specific issue details"""
|
||||
return self.gitea.get_issue(issue_number, repo=repo)
|
||||
|
||||
async def create_issue(self, title, body, labels=None, repo=None):
|
||||
"""Create new issue"""
|
||||
return self.gitea.create_issue(title, body, labels=labels, repo=repo)
|
||||
|
||||
async def update_issue(self, issue_number, title=None, body=None, state=None, labels=None, repo=None):
|
||||
"""Update existing issue"""
|
||||
return self.gitea.update_issue(
|
||||
issue_number,
|
||||
title=title,
|
||||
body=body,
|
||||
state=state,
|
||||
labels=labels,
|
||||
repo=repo
|
||||
)
|
||||
|
||||
async def add_comment(self, issue_number, comment, repo=None):
|
||||
"""Add comment to issue"""
|
||||
return self.gitea.add_comment(issue_number, comment, repo=repo)
|
||||
|
||||
# PMO-specific
|
||||
async def aggregate_issues(self, state='open', labels=None):
|
||||
"""Aggregate issues across all repositories (PMO mode)"""
|
||||
if self.gitea.mode != 'company':
|
||||
raise ValueError("aggregate_issues only available in company mode")
|
||||
return self.gitea.aggregate_issues(state=state, labels=labels)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Testing
|
||||
|
||||
### Unit Tests
|
||||
|
||||
```python
|
||||
# tests/test_config.py
|
||||
import pytest
|
||||
from pathlib import Path
|
||||
from mcp_server.config import GiteaConfig
|
||||
|
||||
def test_load_system_config(tmp_path, monkeypatch):
|
||||
"""Test loading system-level configuration"""
|
||||
# Mock home directory
|
||||
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"
|
||||
)
|
||||
|
||||
monkeypatch.setenv('HOME', str(tmp_path))
|
||||
|
||||
config = GiteaConfig()
|
||||
result = config.load()
|
||||
|
||||
assert result['api_url'] == 'https://test.com/api/v1'
|
||||
assert result['api_token'] == 'test_token'
|
||||
assert result['owner'] == 'test_owner'
|
||||
assert result['mode'] == 'company' # No repo specified
|
||||
|
||||
def test_project_config_override(tmp_path, monkeypatch):
|
||||
"""Test that project config overrides system config"""
|
||||
# Set up system config
|
||||
system_config_dir = tmp_path / '.config' / 'claude'
|
||||
system_config_dir.mkdir(parents=True)
|
||||
|
||||
system_config = system_config_dir / 'gitea.env'
|
||||
system_config.write_text(
|
||||
"GITEA_API_URL=https://test.com/api/v1\n"
|
||||
"GITEA_API_TOKEN=test_token\n"
|
||||
"GITEA_OWNER=test_owner\n"
|
||||
)
|
||||
|
||||
# Set up project config
|
||||
project_dir = tmp_path / 'project'
|
||||
project_dir.mkdir()
|
||||
|
||||
project_config = project_dir / '.env'
|
||||
project_config.write_text("GITEA_REPO=test_repo\n")
|
||||
|
||||
monkeypatch.setenv('HOME', str(tmp_path))
|
||||
monkeypatch.chdir(project_dir)
|
||||
|
||||
config = GiteaConfig()
|
||||
result = config.load()
|
||||
|
||||
assert result['repo'] == 'test_repo'
|
||||
assert result['mode'] == 'project'
|
||||
|
||||
def test_missing_required_config():
|
||||
"""Test error handling for missing configuration"""
|
||||
with pytest.raises(FileNotFoundError):
|
||||
config = GiteaConfig()
|
||||
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", "Priority/Low"]
|
||||
)
|
||||
assert issue['title'] == "Test Issue"
|
||||
assert any(label['name'] == "Type/Bug" for label in issue['labels'])
|
||||
|
||||
def test_get_labels(gitea_client):
|
||||
"""Test fetching labels"""
|
||||
labels = gitea_client.get_labels()
|
||||
assert isinstance(labels, list)
|
||||
assert len(labels) > 0
|
||||
|
||||
def test_pmo_mode_aggregate_issues():
|
||||
"""Test PMO mode aggregation (no repo specified)"""
|
||||
# Set up client without repo
|
||||
client = GiteaClient() # Should detect company mode
|
||||
|
||||
if client.mode == 'company':
|
||||
aggregated = client.aggregate_issues(state='open')
|
||||
assert isinstance(aggregated, dict)
|
||||
# Each key should be a repo name
|
||||
for repo_name, issues in aggregated.items():
|
||||
assert isinstance(issues, list)
|
||||
```
|
||||
|
||||
### 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Performance Optimization
|
||||
|
||||
### Caching
|
||||
|
||||
```python
|
||||
from functools import lru_cache
|
||||
|
||||
@lru_cache(maxsize=128)
|
||||
def get_labels_cached(self, repo: str) -> List[Dict]:
|
||||
"""Cached label retrieval to reduce API calls"""
|
||||
return self.get_labels(repo)
|
||||
```
|
||||
|
||||
### Retry Logic
|
||||
|
||||
```python
|
||||
import time
|
||||
from typing import Callable
|
||||
|
||||
def retry_on_failure(max_retries=3, delay=1):
|
||||
"""Decorator for retrying failed API calls"""
|
||||
def decorator(func: Callable):
|
||||
def wrapper(*args, **kwargs):
|
||||
for attempt in range(max_retries):
|
||||
try:
|
||||
return func(*args, **kwargs)
|
||||
except requests.exceptions.RequestException as e:
|
||||
if attempt == max_retries - 1:
|
||||
raise
|
||||
time.sleep(delay * (attempt + 1))
|
||||
return wrapper
|
||||
return decorator
|
||||
|
||||
@retry_on_failure(max_retries=3)
|
||||
def list_issues(self, state='open', labels=None, repo=None):
|
||||
"""List issues with automatic retry"""
|
||||
# Implementation
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Common Issues
|
||||
|
||||
**Issue:** Module not found
|
||||
```bash
|
||||
# Solution: Ensure PYTHONPATH is set in .mcp.json
|
||||
"env": {
|
||||
"PYTHONPATH": "${CLAUDE_PLUGIN_ROOT}/../mcp-servers/gitea"
|
||||
}
|
||||
```
|
||||
|
||||
**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
|
||||
```
|
||||
|
||||
**Issue:** PMO mode not working
|
||||
```bash
|
||||
# Solution: Ensure GITEA_REPO is NOT set
|
||||
# Check environment variables
|
||||
env | grep GITEA
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Security
|
||||
|
||||
### Best Practices
|
||||
|
||||
1. **Token Storage:**
|
||||
- Store tokens in `~/.config/claude/gitea.env`
|
||||
- Set file permissions to 600
|
||||
- Never commit tokens to git
|
||||
|
||||
2. **Input Validation:**
|
||||
- Validate all user input before API calls
|
||||
- Sanitize issue titles and descriptions
|
||||
- Prevent injection attacks
|
||||
|
||||
3. **Error Handling:**
|
||||
- Don't leak tokens in error messages
|
||||
- Log errors without sensitive data
|
||||
- Provide user-friendly error messages
|
||||
|
||||
4. **API Rate Limiting:**
|
||||
- Implement exponential backoff
|
||||
- Cache frequently accessed data
|
||||
- Batch requests where possible
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Set up system configuration**
|
||||
2. **Create virtual environment**
|
||||
3. **Install dependencies**
|
||||
4. **Run tests against actual Gitea instance**
|
||||
5. **Integrate with projman plugin**
|
||||
1295
docs/references/MCP-WIKIJS.md
Normal file
1295
docs/references/MCP-WIKIJS.md
Normal file
File diff suppressed because it is too large
Load Diff
902
docs/references/PLUGIN-PMO.md
Normal file
902
docs/references/PLUGIN-PMO.md
Normal file
@@ -0,0 +1,902 @@
|
||||
# PMO Plugin Reference (projman-pmo)
|
||||
|
||||
## Overview
|
||||
|
||||
The `projman-pmo` plugin provides multi-project PMO coordination with cross-project dependency tracking, resource allocation, and company-wide visibility. It builds on projman but operates at the organization level.
|
||||
|
||||
**Build Order:** Build AFTER projman is working and validated
|
||||
**Target Users:** PMO coordinators, engineering managers, CTOs
|
||||
**Scope:** Multi-project coordination across entire organization
|
||||
|
||||
**Key Features:**
|
||||
- Cross-project status aggregation
|
||||
- Dependency tracking and visualization
|
||||
- Resource conflict detection
|
||||
- Release coordination
|
||||
- Company-wide lessons learned search
|
||||
- Multi-project prioritization
|
||||
|
||||
---
|
||||
|
||||
## Plugin Structure
|
||||
|
||||
```
|
||||
projman-pmo/
|
||||
├── .claude-plugin/
|
||||
│ └── plugin.json # Plugin manifest
|
||||
├── .mcp.json # Points to ../mcp-servers/ (company mode)
|
||||
├── commands/
|
||||
│ ├── pmo-status.md # Multi-project status overview
|
||||
│ ├── pmo-priorities.md # Cross-project prioritization
|
||||
│ ├── pmo-dependencies.md # Dependency visualization
|
||||
│ ├── pmo-conflicts.md # Resource conflict detection
|
||||
│ └── pmo-schedule.md # Deployment schedule coordination
|
||||
├── agents/
|
||||
│ └── pmo-coordinator.md # Multi-project coordination agent
|
||||
└── README.md # Installation and usage guide
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration
|
||||
|
||||
### Plugin .mcp.json
|
||||
|
||||
**File:** `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 Differences from projman:**
|
||||
- **NO** `GITEA_REPO` → operates on all repositories
|
||||
- **NO** `WIKIJS_PROJECT` → operates on entire `/hyper-hive-labs` namespace
|
||||
- Same shared MCP servers at `../mcp-servers/`
|
||||
|
||||
### Environment Variables
|
||||
|
||||
**Required (System-Level Only):**
|
||||
- `GITEA_API_URL`
|
||||
- `GITEA_API_TOKEN`
|
||||
- `GITEA_OWNER`
|
||||
- `WIKIJS_API_URL`
|
||||
- `WIKIJS_API_TOKEN`
|
||||
- `WIKIJS_BASE_PATH`
|
||||
|
||||
**NOT Required:**
|
||||
- `GITEA_REPO` - PMO operates across all repos
|
||||
- `WIKIJS_PROJECT` - PMO operates across entire namespace
|
||||
|
||||
---
|
||||
|
||||
## PMO Coordinator Agent
|
||||
|
||||
**File:** `agents/pmo-coordinator.md`
|
||||
|
||||
### Agent Personality
|
||||
|
||||
```markdown
|
||||
You are the PMO Coordinator for Hyper Hive Labs.
|
||||
|
||||
Your role:
|
||||
- Maintain strategic view across all projects
|
||||
- Identify cross-project dependencies
|
||||
- Detect resource conflicts
|
||||
- Balance competing priorities
|
||||
- Coordinate release timing
|
||||
- Track customer deployment schedules
|
||||
- Surface company-wide lessons learned
|
||||
|
||||
You are:
|
||||
- Strategic thinker
|
||||
- Dependency-aware
|
||||
- Conflict detector
|
||||
- Priority balancer
|
||||
- Team coordinator
|
||||
- NOT a micromanager
|
||||
|
||||
You delegate to project-level agents:
|
||||
- Don't micromanage single projects
|
||||
- Focus on cross-project issues
|
||||
- Surface conflicts early
|
||||
- Facilitate coordination
|
||||
- Provide strategic guidance
|
||||
|
||||
Available Tools:
|
||||
- aggregate_issues: Fetch issues across all repositories
|
||||
- search_all_projects: Search lessons across all projects
|
||||
- list_repos: Get all organization repositories
|
||||
- get_shared_docs: Access company-wide patterns and best practices
|
||||
|
||||
Key Principles:
|
||||
1. Strategic overview, not tactical details
|
||||
2. Cross-project coordination, not single-project management
|
||||
3. Identify conflicts before they become problems
|
||||
4. Balance competing priorities across teams
|
||||
5. Learn from patterns across all projects
|
||||
```
|
||||
|
||||
### Delegation Model
|
||||
|
||||
```
|
||||
PMO Agent (projman-pmo)
|
||||
├─ Identifies cross-project issues
|
||||
├─ Detects resource conflicts
|
||||
├─ Coordinates release timing
|
||||
└─ Delegates to...
|
||||
├─ Planner Agent (projman) → for project planning
|
||||
├─ Orchestrator Agent (projman) → for project execution
|
||||
└─ Executor Agent (projman) → for implementation
|
||||
```
|
||||
|
||||
**Example:**
|
||||
```
|
||||
User: /pmo-status
|
||||
|
||||
PMO: Projects Overview:
|
||||
|
||||
CuisineFlow: Sprint in progress, 60% complete
|
||||
└─ Blocking: CuisineFlow-Site deployment
|
||||
|
||||
I notice CuisineFlow-Site is waiting on API changes.
|
||||
Use projman in the cuisineflow-site repo to plan the sync work.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Commands
|
||||
|
||||
### 1. PMO Status Command
|
||||
|
||||
**File:** `commands/pmo-status.md`
|
||||
|
||||
**Usage:** `/pmo-status`
|
||||
|
||||
**Description:** Consolidated view of all active projects
|
||||
|
||||
**Flow:**
|
||||
|
||||
```
|
||||
User: /pmo-status
|
||||
|
||||
PMO: Projects Overview
|
||||
================
|
||||
|
||||
CuisineFlow (main product)
|
||||
├── Sprint: Intuit Engine Extraction
|
||||
├── Status: In Progress (60%)
|
||||
├── Issue: #47
|
||||
├── Blockers: None
|
||||
├── Next: API testing
|
||||
└── Timeline: On track (1 week remaining)
|
||||
|
||||
CuisineFlow-Site (demo)
|
||||
├── Sprint: Dashboard Updates
|
||||
├── Status: Waiting on dependencies
|
||||
├── Issue: #12
|
||||
├── Blockers: Depends on CuisineFlow #47 (API changes)
|
||||
├── Next: Deploy when API ready
|
||||
└── Timeline: Blocked (waiting on CuisineFlow)
|
||||
|
||||
Intuit-Engine (service)
|
||||
├── Sprint: Initial Setup
|
||||
├── Status: Planning
|
||||
├── Issue: #3
|
||||
├── Blockers: Architecture decisions needed
|
||||
├── Next: Service boundary definition
|
||||
└── Timeline: Not started
|
||||
|
||||
HHL-Site (marketing)
|
||||
├── Sprint: Content Updates
|
||||
├── Status: Complete
|
||||
├── Issue: #8 (closed)
|
||||
├── Blockers: None
|
||||
├── Next: Deploy to production
|
||||
└── Timeline: Ready for deployment
|
||||
|
||||
Cross-Project Insights:
|
||||
- CuisineFlow-Site blocked by CuisineFlow #47
|
||||
- Intuit-Engine needs architectural guidance
|
||||
- HHL-Site ready for deployment
|
||||
|
||||
Suggested Actions:
|
||||
1. Prioritize CuisineFlow #47 completion (unblocks Site)
|
||||
2. Schedule architecture review for Intuit-Engine
|
||||
3. Deploy HHL-Site content updates
|
||||
```
|
||||
|
||||
**Success Criteria:**
|
||||
- Shows all active projects
|
||||
- Identifies blockers
|
||||
- Surfaces dependencies
|
||||
- Provides actionable insights
|
||||
|
||||
### 2. PMO Priorities Command
|
||||
|
||||
**File:** `commands/pmo-priorities.md`
|
||||
|
||||
**Usage:** `/pmo-priorities`
|
||||
|
||||
**Description:** Review and adjust priorities across projects
|
||||
|
||||
**Flow:**
|
||||
|
||||
```
|
||||
User: /pmo-priorities
|
||||
|
||||
PMO: Priority Analysis Across Projects
|
||||
=================================
|
||||
|
||||
Critical (Blocks launches):
|
||||
1. CuisineFlow #47 - Intuit Engine Extraction
|
||||
→ Blocks: CuisineFlow v2.0 launch (Nov 15)
|
||||
→ Blocks: CuisineFlow-Site deployment
|
||||
→ Status: 60% complete, 1 week remaining
|
||||
→ Recommendation: Maintain focus
|
||||
|
||||
High (Important features):
|
||||
2. CuisineFlow-Site #12 - Dashboard Updates
|
||||
→ Depends on: CuisineFlow #47
|
||||
→ Status: Waiting
|
||||
→ Recommendation: Begin planning, wait for #47
|
||||
|
||||
3. Intuit-Engine #3 - Initial Setup
|
||||
→ Enables: Service architecture
|
||||
→ Status: Planning phase
|
||||
→ Recommendation: Schedule architecture review
|
||||
|
||||
Medium (Enhancements):
|
||||
4. HHL-Site #8 - Content Updates
|
||||
→ Status: Complete, ready to deploy
|
||||
→ Recommendation: Deploy this week
|
||||
|
||||
Resource Analysis:
|
||||
Leo (primary developer):
|
||||
- Working on: CuisineFlow #47 (Critical)
|
||||
- Next: CuisineFlow-Site #12 (High)
|
||||
- Later: Intuit-Engine #3 (High)
|
||||
|
||||
⚠️ Potential Conflict:
|
||||
Leo is assigned to 3 high-priority items. Consider:
|
||||
- Maintaining focus on #47 (blocks launch)
|
||||
- Queueing #12 for after #47 completion
|
||||
- Scheduling #3 architecture review with team
|
||||
|
||||
Recommend any priority changes?
|
||||
```
|
||||
|
||||
**Success Criteria:**
|
||||
- Clear priority ranking
|
||||
- Resource allocation visibility
|
||||
- Conflict identification
|
||||
- Actionable recommendations
|
||||
|
||||
### 3. PMO Dependencies Command
|
||||
|
||||
**File:** `commands/pmo-dependencies.md`
|
||||
|
||||
**Usage:** `/pmo-dependencies`
|
||||
|
||||
**Description:** Visualize and manage project dependencies
|
||||
|
||||
**Flow:**
|
||||
|
||||
```
|
||||
User: /pmo-dependencies
|
||||
|
||||
PMO: Project Dependencies
|
||||
====================
|
||||
|
||||
Dependency Graph:
|
||||
|
||||
Intuit-Engine (service)
|
||||
↓ (must complete before)
|
||||
CuisineFlow (main)
|
||||
↓ (API changes required by)
|
||||
CuisineFlow-Site (demo)
|
||||
↓ (deploy together)
|
||||
Customer VPS (deployments)
|
||||
|
||||
Detailed Dependencies:
|
||||
|
||||
1. CuisineFlow → Intuit-Engine
|
||||
Type: Service extraction
|
||||
Status: In progress
|
||||
Blocker: Must complete #47 before v2.0 launch
|
||||
Impact: High (blocks launch)
|
||||
|
||||
2. CuisineFlow → CuisineFlow-Site
|
||||
Type: Feature sync
|
||||
Status: Waiting
|
||||
Blocker: Dashboard updates need API changes from #47
|
||||
Impact: Medium (demo consistency)
|
||||
|
||||
3. CuisineFlow → Customer VPS
|
||||
Type: Deployment
|
||||
Status: Pending
|
||||
Blocker: v2.0 launch must complete before customer updates
|
||||
Impact: High (customer commitments)
|
||||
|
||||
Deployment Order:
|
||||
1. Complete Intuit-Engine service extraction
|
||||
2. Deploy CuisineFlow v2.0 to production
|
||||
3. Sync CuisineFlow-Site demo
|
||||
4. Update customer VPS instances
|
||||
|
||||
Critical Path:
|
||||
Intuit-Engine (#3) → CuisineFlow (#47) → Site (#12) → Customer VPS
|
||||
Estimated timeline: 3 weeks total
|
||||
|
||||
Risks:
|
||||
- CuisineFlow #47 delay would cascade to all downstream
|
||||
- Customer VPS updates have Nov 20 deadline
|
||||
```
|
||||
|
||||
**Success Criteria:**
|
||||
- Dependencies clearly visualized
|
||||
- Critical path identified
|
||||
- Deployment order defined
|
||||
- Risks highlighted
|
||||
|
||||
### 4. PMO Conflicts Command
|
||||
|
||||
**File:** `commands/pmo-conflicts.md`
|
||||
|
||||
**Usage:** `/pmo-conflicts`
|
||||
|
||||
**Description:** Detect and resolve resource conflicts
|
||||
|
||||
**Flow:**
|
||||
|
||||
```
|
||||
User: /pmo-conflicts
|
||||
|
||||
PMO: Resource Conflict Analysis
|
||||
==========================
|
||||
|
||||
⚠️ Resource Conflict Detected
|
||||
|
||||
Leo (Developer):
|
||||
Assigned to:
|
||||
- CuisineFlow #47: Intuit Engine extraction (Priority: Critical)
|
||||
- CuisineFlow-Site #12: Dashboard redesign (Priority: High)
|
||||
- HHL-Site #8: Content update (Priority: Medium)
|
||||
- Intuit-Engine #3: Service setup (Priority: High)
|
||||
|
||||
Conflict Analysis:
|
||||
- 4 active assignments across 3 projects
|
||||
- 2 are high priority or above
|
||||
- Estimated total effort: 4 weeks
|
||||
- Timeline: 2 weeks available
|
||||
|
||||
Recommendations:
|
||||
1. FOCUS: CuisineFlow #47 (Critical, blocks launch)
|
||||
→ Keep as primary focus
|
||||
→ Estimated completion: 1 week
|
||||
|
||||
2. QUEUE: CuisineFlow-Site #12 (High, depends on #47)
|
||||
→ Start after #47 completes
|
||||
→ Natural sequencing
|
||||
|
||||
3. DELEGATE: HHL-Site #8 (Medium, content work)
|
||||
→ Can be handled by marketing team
|
||||
→ Low technical complexity
|
||||
|
||||
4. SCHEDULE: Intuit-Engine #3 (High, planning phase)
|
||||
→ Schedule architecture review session
|
||||
→ Team collaboration, not solo work
|
||||
|
||||
Timeline Conflict:
|
||||
|
||||
Without changes:
|
||||
Week 1-2: CuisineFlow #47
|
||||
Week 3-4: Site #12 + Engine #3 (CONFLICT)
|
||||
|
||||
With recommendations:
|
||||
Week 1-2: CuisineFlow #47 (FOCUS)
|
||||
Week 3: CuisineFlow-Site #12 (QUEUE)
|
||||
Week 4: Intuit-Engine #3 (SCHEDULE)
|
||||
HHL-Site #8: Marketing (DELEGATE)
|
||||
|
||||
Apply recommendations?
|
||||
```
|
||||
|
||||
**Success Criteria:**
|
||||
- Conflicts identified automatically
|
||||
- Clear impact analysis
|
||||
- Actionable recommendations
|
||||
- Timeline visualization
|
||||
|
||||
### 5. PMO Schedule Command
|
||||
|
||||
**File:** `commands/pmo-schedule.md`
|
||||
|
||||
**Usage:** `/pmo-schedule`
|
||||
|
||||
**Description:** Coordinate deployment schedules
|
||||
|
||||
**Flow:**
|
||||
|
||||
```
|
||||
User: /pmo-schedule
|
||||
|
||||
PMO: Deployment Schedule
|
||||
===================
|
||||
|
||||
Week of Nov 6:
|
||||
- CuisineFlow: Continue Sprint #47 (Intuit Engine)
|
||||
- HHL-Site: Deploy content updates (#8) ✅
|
||||
|
||||
Week of Nov 13:
|
||||
- CuisineFlow: Complete Sprint #47 ⚠️
|
||||
→ Critical: Must complete by Nov 15 for launch
|
||||
- CuisineFlow-Site: Begin Dashboard updates (#12)
|
||||
|
||||
Week of Nov 20:
|
||||
- CuisineFlow: Deploy v2.0 to production 🚀
|
||||
→ Deployment window: Nov 20-22
|
||||
- CuisineFlow-Site: Sync demo with v2.0
|
||||
- Customer VPS: Begin rollout (Deadline: Nov 20)
|
||||
|
||||
Week of Nov 27:
|
||||
- Customer VPS: Continue rollout
|
||||
- Intuit-Engine: Begin service implementation (#3)
|
||||
|
||||
Critical Dates:
|
||||
- Nov 15: CuisineFlow v2.0 feature freeze
|
||||
- Nov 20: Production deployment
|
||||
- Nov 20: Customer VPS deadline
|
||||
- Nov 22: Demo site sync
|
||||
|
||||
Dependencies:
|
||||
✅ Intuit-Engine service boundaries defined
|
||||
🔄 CuisineFlow #47 in progress (60%)
|
||||
⏳ CuisineFlow-Site #12 waiting
|
||||
⏳ Customer VPS rollout pending
|
||||
|
||||
Risks:
|
||||
⚠️ CuisineFlow #47 delay would impact:
|
||||
- v2.0 launch date (Nov 20)
|
||||
- Customer VPS deadline (Nov 20)
|
||||
- Demo site sync (Nov 22)
|
||||
|
||||
Mitigation:
|
||||
- Monitor #47 progress daily
|
||||
- Prepare rollback plan for customer VPS
|
||||
- Communicate delays early if detected
|
||||
```
|
||||
|
||||
**Success Criteria:**
|
||||
- Clear timeline visibility
|
||||
- Dependencies tracked
|
||||
- Critical dates highlighted
|
||||
- Risk mitigation planned
|
||||
|
||||
---
|
||||
|
||||
## Multi-Project Coordination Workflows
|
||||
|
||||
### Cross-Project Lessons Learned
|
||||
|
||||
```
|
||||
User: Search for lessons about service extraction across all projects
|
||||
|
||||
PMO: Searching lessons across all projects...
|
||||
|
||||
Found 5 relevant lessons:
|
||||
|
||||
CuisineFlow:
|
||||
- Sprint 08: Service boundary issues with shared DB
|
||||
Tags: #service-extraction #database #refactoring
|
||||
Key: Define boundaries at data model level first
|
||||
|
||||
- Sprint 12: API versioning during extraction
|
||||
Tags: #api #versioning #refactoring
|
||||
Key: Version APIs from the start
|
||||
|
||||
Intuit-Engine:
|
||||
- Sprint 02: Circular dependencies in service init
|
||||
Tags: #service-extraction #dependencies
|
||||
Key: Watch for import cycles
|
||||
|
||||
CuisineFlow-Site:
|
||||
- Sprint 05: Sync issues during backend refactor
|
||||
Tags: #sync #refactoring
|
||||
Key: Coordinate deployments during major changes
|
||||
|
||||
Shared Patterns:
|
||||
- /hyper-hive-labs/shared/architecture-patterns/service-extraction
|
||||
Key: Service Extraction Playbook
|
||||
|
||||
Common Themes:
|
||||
1. Data model boundaries are critical
|
||||
2. API versioning prevents integration issues
|
||||
3. Watch for circular dependencies
|
||||
4. Coordinate deployments during refactors
|
||||
|
||||
Apply these insights to current Intuit Engine extraction?
|
||||
```
|
||||
|
||||
### Resource Allocation
|
||||
|
||||
```
|
||||
User: /pmo-status
|
||||
|
||||
PMO: [Shows status]
|
||||
|
||||
Resource Analysis:
|
||||
- Leo: 3 active projects (CuisineFlow, Site, Engine)
|
||||
- Marketing: 1 project (HHL-Site)
|
||||
|
||||
Bottleneck detected: Leo is on critical path for all technical work
|
||||
|
||||
Recommendations:
|
||||
1. Prioritize work that unblocks others
|
||||
2. Consider hiring/contracting for parallel work
|
||||
3. Delegate non-critical work (HHL-Site content)
|
||||
|
||||
Would you like a detailed resource allocation report?
|
||||
```
|
||||
|
||||
### Release Coordination
|
||||
|
||||
```
|
||||
User: Plan the v2.0 release across all affected projects
|
||||
|
||||
PMO: Release Coordination: CuisineFlow v2.0
|
||||
======================================
|
||||
|
||||
Affected Projects:
|
||||
1. CuisineFlow (main product)
|
||||
2. Intuit-Engine (new service)
|
||||
3. CuisineFlow-Site (demo)
|
||||
4. Customer VPS instances
|
||||
|
||||
Pre-Release Checklist:
|
||||
✅ Intuit-Engine service deployed
|
||||
🔄 CuisineFlow #47 complete (60%)
|
||||
⏳ Integration tests pending
|
||||
⏳ Demo site updates pending
|
||||
⏳ Customer migration scripts ready
|
||||
|
||||
Deployment Sequence:
|
||||
1. Deploy Intuit-Engine service (backend)
|
||||
→ Date: Nov 18
|
||||
→ Duration: 2 hours
|
||||
→ Rollback plan: Ready
|
||||
|
||||
2. Deploy CuisineFlow v2.0 (main app)
|
||||
→ Date: Nov 20
|
||||
→ Duration: 4 hours
|
||||
→ Rollback plan: Ready
|
||||
|
||||
3. Sync CuisineFlow-Site (demo)
|
||||
→ Date: Nov 22
|
||||
→ Duration: 1 hour
|
||||
→ Dependencies: Step 2 complete
|
||||
|
||||
4. Update Customer VPS (production instances)
|
||||
→ Date: Nov 23-25
|
||||
→ Duration: Phased rollout
|
||||
→ Dependencies: Steps 2 and 3 complete
|
||||
|
||||
Communication Plan:
|
||||
- Nov 15: Feature freeze announcement
|
||||
- Nov 19: Deployment notification
|
||||
- Nov 20: v2.0 launch announcement
|
||||
- Nov 25: Completion report
|
||||
|
||||
Risks & Mitigation:
|
||||
- Risk: #47 completion delayed
|
||||
Mitigation: Daily progress checks, adjust timeline early
|
||||
|
||||
- Risk: Integration issues during deployment
|
||||
Mitigation: Comprehensive testing, rollback plan ready
|
||||
|
||||
- Risk: Customer VPS migration issues
|
||||
Mitigation: Phased rollout, support on standby
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Company-Wide Patterns
|
||||
|
||||
### Accessing Shared Documentation
|
||||
|
||||
```python
|
||||
# PMO agent can access company-wide patterns
|
||||
shared_patterns = await wikijs.get_shared_docs("architecture-patterns")
|
||||
|
||||
# Returns:
|
||||
# - microservices.md
|
||||
# - api-gateway.md
|
||||
# - database-per-service.md
|
||||
# - service-extraction.md (created from lessons learned)
|
||||
```
|
||||
|
||||
### Creating Shared Patterns
|
||||
|
||||
```
|
||||
User: Create a shared pattern document for service extraction
|
||||
|
||||
PMO: I'll create a pattern document based on lessons from:
|
||||
- CuisineFlow Sprint 08
|
||||
- CuisineFlow Sprint 12
|
||||
- Intuit-Engine Sprint 02
|
||||
|
||||
Creating: /hyper-hive-labs/shared/architecture-patterns/service-extraction
|
||||
|
||||
Service Extraction Pattern
|
||||
=========================
|
||||
|
||||
## When to Use
|
||||
- Extracting microservice from monolith
|
||||
- Creating separate deployable service
|
||||
- Isolating domain boundaries
|
||||
|
||||
## Prerequisites
|
||||
- Clear service boundaries defined
|
||||
- Data model dependencies mapped
|
||||
- API contracts specified
|
||||
|
||||
## Steps
|
||||
1. Define service boundaries at data model level
|
||||
2. Design and version APIs first
|
||||
3. Extract data layer with foreign key awareness
|
||||
4. Implement service logic
|
||||
5. Update integration points
|
||||
6. Deploy and test
|
||||
|
||||
## Common Pitfalls
|
||||
- Not defining boundaries at data level first
|
||||
- Missing API versioning
|
||||
- Circular dependencies in initialization
|
||||
- Uncoordinated deployments
|
||||
|
||||
## Lessons Learned
|
||||
[Links to specific sprint lessons]
|
||||
|
||||
Created ✅
|
||||
Tags: #service-extraction #microservices #refactoring #architecture
|
||||
|
||||
This pattern is now available to all projects.
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Implementation Phases
|
||||
|
||||
### Phase 9: PMO Plugin Foundation
|
||||
|
||||
**Deliverable:** PMO plugin requirements and design
|
||||
|
||||
**Tasks:**
|
||||
1. Analyze multi-project workflows
|
||||
2. Identify coordination pain points
|
||||
3. Design PMO agent scope
|
||||
4. Extend MCP server for multi-repo operations
|
||||
5. Define delegation model
|
||||
|
||||
**Success Criteria:**
|
||||
- Clear PMO plugin scope
|
||||
- Multi-repo queries working
|
||||
- Delegation model defined
|
||||
- Doesn't duplicate projman functionality
|
||||
|
||||
### Phase 10: PMO Commands & Workflows
|
||||
|
||||
**Deliverable:** PMO-specific commands working
|
||||
|
||||
**Tasks:**
|
||||
1. Implement `/pmo-status` command
|
||||
2. Implement `/pmo-priorities` command
|
||||
3. Implement `/pmo-dependencies` command
|
||||
4. Implement `/pmo-conflicts` command
|
||||
5. Implement `/pmo-schedule` command
|
||||
6. Build conflict detection logic
|
||||
7. Create dependency visualization
|
||||
8. Design release coordination workflow
|
||||
|
||||
**Success Criteria:**
|
||||
- All commands provide valuable insights
|
||||
- Dependencies clearly visualized
|
||||
- Conflicts easily identified
|
||||
- Coordination reduces manual overhead
|
||||
|
||||
### Phase 11: PMO Testing & Integration
|
||||
|
||||
**Deliverable:** Validated PMO plugin integrated with projman
|
||||
|
||||
**Tasks:**
|
||||
1. Test with multiple projects (CuisineFlow, Site, Engine, HHL-Site)
|
||||
2. Simulate deployment coordination scenarios
|
||||
3. Test priority conflict resolution
|
||||
4. Validate dependency tracking
|
||||
5. Test cross-project lessons search
|
||||
6. Ensure PMO delegates to projman agents
|
||||
|
||||
**Success Criteria:**
|
||||
- Handles multiple projects correctly
|
||||
- Dependencies respected
|
||||
- Conflicts detected and surfaced
|
||||
- Seamless integration with projman
|
||||
- Cross-project lessons accessible
|
||||
|
||||
### Phase 12: Production Deployment
|
||||
|
||||
**Deliverable:** PMO plugin deployed and operational
|
||||
|
||||
**Tasks:**
|
||||
1. Deploy across all environments (laptop, staging, production)
|
||||
2. Configure for company-wide access
|
||||
3. Set up backup and recovery
|
||||
4. Establish monitoring and maintenance
|
||||
5. Train team on PMO capabilities
|
||||
|
||||
**Success Criteria:**
|
||||
- Works in all environments
|
||||
- Configuration portable
|
||||
- Backup procedures documented
|
||||
- Team trained and comfortable
|
||||
|
||||
---
|
||||
|
||||
## PMO vs Projman: Key Differences
|
||||
|
||||
| Aspect | projman | projman-pmo |
|
||||
|--------|---------|-------------|
|
||||
| **Scope** | Single repository | All repositories |
|
||||
| **Configuration** | `GITEA_REPO` + `WIKIJS_PROJECT` | Neither (company-wide) |
|
||||
| **Agents** | Planner, Orchestrator, Executor | PMO Coordinator |
|
||||
| **Commands** | Sprint-focused | Cross-project coordination |
|
||||
| **Gitea Access** | Single repo issues | All repos issues |
|
||||
| **Wiki.js Access** | Project path | Entire namespace |
|
||||
| **Primary User** | Developer, Team Lead | PMO, Manager, CTO |
|
||||
| **Focus** | Tactical execution | Strategic coordination |
|
||||
| **Delegation** | N/A | Delegates to projman |
|
||||
|
||||
---
|
||||
|
||||
## Usage Examples
|
||||
|
||||
### Example 1: Detecting Blocked Work
|
||||
|
||||
```
|
||||
User: /pmo-status
|
||||
|
||||
PMO: CuisineFlow-Site: Waiting on dependencies
|
||||
Blocked by: CuisineFlow #47 (API changes)
|
||||
|
||||
Recommendation: Focus resources on CuisineFlow #47 to unblock Site work
|
||||
```
|
||||
|
||||
### Example 2: Resource Conflict Resolution
|
||||
|
||||
```
|
||||
User: /pmo-conflicts
|
||||
|
||||
PMO: Leo assigned to 4 tasks across 3 projects
|
||||
Estimated: 4 weeks work in 2 weeks timeline
|
||||
|
||||
Recommendations:
|
||||
- Maintain focus on Critical priority (CuisineFlow #47)
|
||||
- Delegate content work (HHL-Site #8) to marketing
|
||||
- Schedule architectural review (Intuit-Engine #3) as team session
|
||||
```
|
||||
|
||||
### Example 3: Release Planning
|
||||
|
||||
```
|
||||
User: /pmo-schedule
|
||||
|
||||
PMO: Critical Path: Engine → CuisineFlow → Site → Customer VPS
|
||||
Deadline: Nov 20 (Customer VPS commitment)
|
||||
|
||||
Current: Week 1 of 3
|
||||
Status: On track
|
||||
|
||||
Risk: If CuisineFlow #47 delayed, entire timeline at risk
|
||||
Mitigation: Daily progress monitoring
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Best Practices
|
||||
|
||||
### 1. Use PMO for Strategic View
|
||||
|
||||
- Don't micromanage individual projects
|
||||
- Focus on cross-project issues
|
||||
- Identify blockers and dependencies
|
||||
- Balance competing priorities
|
||||
|
||||
### 2. Delegate to Projman
|
||||
|
||||
- Use projman for project-specific planning
|
||||
- Let project teams handle tactical execution
|
||||
- PMO provides coordination, not implementation
|
||||
|
||||
### 3. Monitor Critical Path
|
||||
|
||||
- Identify which work blocks others
|
||||
- Focus resources on critical path items
|
||||
- Communicate delays early
|
||||
|
||||
### 4. Learn Across Projects
|
||||
|
||||
- Search lessons across all projects
|
||||
- Create shared patterns from common themes
|
||||
- Build company-wide knowledge base
|
||||
|
||||
### 5. Coordinate Releases
|
||||
|
||||
- Plan deployments across dependent projects
|
||||
- Communicate timelines clearly
|
||||
- Have rollback plans ready
|
||||
|
||||
---
|
||||
|
||||
## Troubleshooting
|
||||
|
||||
### Issue: PMO showing wrong mode
|
||||
|
||||
**Solution:**
|
||||
```bash
|
||||
# Ensure GITEA_REPO and WIKIJS_PROJECT are NOT set
|
||||
env | grep GITEA
|
||||
env | grep WIKIJS
|
||||
|
||||
# Should only show:
|
||||
# GITEA_API_URL, GITEA_API_TOKEN, GITEA_OWNER
|
||||
# WIKIJS_API_URL, WIKIJS_API_TOKEN, WIKIJS_BASE_PATH
|
||||
```
|
||||
|
||||
### Issue: Can't access all repositories
|
||||
|
||||
**Solution:**
|
||||
- Verify API token has organization-level access
|
||||
- Check token permissions in Gitea
|
||||
- Ensure GITEA_OWNER is correct
|
||||
|
||||
### Issue: Cross-project search not working
|
||||
|
||||
**Solution:**
|
||||
- Verify Wiki.js structure exists
|
||||
- Check base path is correct
|
||||
- Ensure projects have lessons-learned directories
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
1. **Complete projman plugin** (Phases 1-8)
|
||||
2. **Validate projman works** with real sprints
|
||||
3. **Begin PMO foundation** (Phase 9)
|
||||
4. **Implement PMO commands** (Phase 10)
|
||||
5. **Test with multiple projects** (Phase 11)
|
||||
6. **Deploy to production** (Phase 12)
|
||||
1010
docs/references/PLUGIN-PROJMAN.md
Normal file
1010
docs/references/PLUGIN-PROJMAN.md
Normal file
File diff suppressed because it is too large
Load Diff
639
docs/references/PROJECT-SUMMARY.md
Normal file
639
docs/references/PROJECT-SUMMARY.md
Normal file
@@ -0,0 +1,639 @@
|
||||
# Project Management Plugins - Project Summary
|
||||
|
||||
## Overview
|
||||
|
||||
This project builds two Claude Code plugins that transform a proven 15-sprint workflow into reusable, distributable tools for managing software development with Gitea, Wiki.js, and agile methodologies.
|
||||
|
||||
**Status:** Planning phase complete, ready for implementation
|
||||
|
||||
---
|
||||
|
||||
## The Two Plugins
|
||||
|
||||
### 1. projman (Single-Repository)
|
||||
|
||||
**Purpose:** Project management for individual repositories
|
||||
**Users:** Developers, Team Leads
|
||||
**Build Order:** Build FIRST
|
||||
|
||||
**Key Features:**
|
||||
- Sprint planning with AI agents
|
||||
- Issue creation with 43-label taxonomy
|
||||
- Lessons learned capture in Wiki.js
|
||||
- Branch-aware security model
|
||||
- Hybrid configuration system
|
||||
|
||||
**Reference:** [PLUGIN-PROJMAN.md](./PLUGIN-PROJMAN.md)
|
||||
|
||||
### 2. projman-pmo (Multi-Project)
|
||||
|
||||
**Purpose:** PMO coordination across organization
|
||||
**Users:** PMO Coordinators, Engineering Managers, CTOs
|
||||
**Build Order:** Build SECOND (after projman validated)
|
||||
|
||||
**Key Features:**
|
||||
- Cross-project status aggregation
|
||||
- Dependency tracking and visualization
|
||||
- Resource conflict detection
|
||||
- Release coordination
|
||||
- Company-wide lessons learned search
|
||||
|
||||
**Reference:** [PLUGIN-PMO.md](./PLUGIN-PMO.md)
|
||||
|
||||
---
|
||||
|
||||
## Core Architecture
|
||||
|
||||
### Shared MCP Servers
|
||||
|
||||
Both plugins share the same MCP server codebase at repository root (`mcp-servers/`):
|
||||
|
||||
**1. Gitea MCP Server**
|
||||
- Issue management (CRUD operations)
|
||||
- Label taxonomy system (43 labels)
|
||||
- Mode detection (project vs company-wide)
|
||||
|
||||
**Reference:** [MCP-GITEA.md](./MCP-GITEA.md)
|
||||
|
||||
**2. Wiki.js MCP Server**
|
||||
- Documentation management
|
||||
- Lessons learned capture and search
|
||||
- GraphQL API integration
|
||||
- Company-wide knowledge base
|
||||
|
||||
**Reference:** [MCP-WIKIJS.md](./MCP-WIKIJS.md)
|
||||
|
||||
### Mode Detection
|
||||
|
||||
The MCP servers detect their operating mode based on environment variables:
|
||||
|
||||
**Project Mode (projman):**
|
||||
- `GITEA_REPO` present → operates on single repository
|
||||
- `WIKIJS_PROJECT` present → operates on single project path
|
||||
|
||||
**Company Mode (pmo):**
|
||||
- No `GITEA_REPO` → operates on all repositories
|
||||
- No `WIKIJS_PROJECT` → operates on entire company namespace
|
||||
|
||||
---
|
||||
|
||||
## Repository Structure
|
||||
|
||||
```
|
||||
hyperhivelabs/claude-plugins/
|
||||
├── mcp-servers/ # ← SHARED BY BOTH PLUGINS
|
||||
│ ├── gitea/ # Gitea MCP Server
|
||||
│ │ ├── .venv/
|
||||
│ │ ├── requirements.txt
|
||||
│ │ ├── mcp_server/
|
||||
│ │ └── tests/
|
||||
│ └── wikijs/ # Wiki.js MCP Server
|
||||
│ ├── .venv/
|
||||
│ ├── requirements.txt
|
||||
│ ├── mcp_server/
|
||||
│ └── tests/
|
||||
├── 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/
|
||||
│ ├── 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
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Configuration Architecture
|
||||
|
||||
### Hybrid Configuration System
|
||||
|
||||
The plugins use a hybrid configuration approach that balances security and flexibility:
|
||||
|
||||
**System-Level (Once per machine):**
|
||||
- `~/.config/claude/gitea.env` - Gitea credentials
|
||||
- `~/.config/claude/wikijs.env` - Wiki.js credentials
|
||||
|
||||
**Project-Level (Per repository):**
|
||||
- `project-root/.env` - Repository and project paths
|
||||
|
||||
**Benefits:**
|
||||
- Single token per service (update once)
|
||||
- Project isolation
|
||||
- Security (tokens never committed)
|
||||
- Easy multi-project setup
|
||||
|
||||
### Configuration Example
|
||||
|
||||
**System-Level:**
|
||||
```bash
|
||||
# ~/.config/claude/gitea.env
|
||||
GITEA_API_URL=https://gitea.hyperhivelabs.com/api/v1
|
||||
GITEA_API_TOKEN=your_token
|
||||
GITEA_OWNER=hyperhivelabs
|
||||
|
||||
# ~/.config/claude/wikijs.env
|
||||
WIKIJS_API_URL=https://wiki.hyperhivelabs.com/graphql
|
||||
WIKIJS_API_TOKEN=your_token
|
||||
WIKIJS_BASE_PATH=/hyper-hive-labs
|
||||
```
|
||||
|
||||
**Project-Level:**
|
||||
```bash
|
||||
# project-root/.env (for projman)
|
||||
GITEA_REPO=cuisineflow
|
||||
WIKIJS_PROJECT=projects/cuisineflow
|
||||
|
||||
# No .env needed for pmo (company-wide mode)
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Key Architectural Decisions
|
||||
|
||||
### 1. Two MCP Servers (Shared)
|
||||
|
||||
**Decision:** Separate Gitea and Wiki.js servers at repository root
|
||||
**Why:**
|
||||
- Clear separation of concerns
|
||||
- Independent configuration
|
||||
- Better maintainability
|
||||
- Professional architecture
|
||||
|
||||
### 2. Python Implementation
|
||||
|
||||
**Decision:** Python 3.11+ for MCP servers
|
||||
**Why:**
|
||||
- Better suited for configuration management
|
||||
- Modular code structure
|
||||
- Easier to maintain and extend
|
||||
- Good async support
|
||||
|
||||
### 3. Wiki.js for Lessons Learned
|
||||
|
||||
**Decision:** Use Wiki.js instead of Git-based Wiki
|
||||
**Why:**
|
||||
- Rich editor and search
|
||||
- Built-in tag system
|
||||
- Version history
|
||||
- Web-based collaboration
|
||||
- GraphQL API
|
||||
- Company-wide accessibility
|
||||
|
||||
### 4. Hybrid Configuration
|
||||
|
||||
**Decision:** System-level + project-level configuration
|
||||
**Why:**
|
||||
- Single token per service (security)
|
||||
- Per-project customization (flexibility)
|
||||
- Easy multi-project setup
|
||||
- Never commit tokens to git
|
||||
|
||||
### 5. Mode Detection in MCP Servers
|
||||
|
||||
**Decision:** Detect mode based on environment variables
|
||||
**Why:**
|
||||
- Same codebase for both plugins
|
||||
- No code duplication
|
||||
- Fix bugs once, both benefit
|
||||
- Clear separation of concerns
|
||||
|
||||
### 6. Build Order: projman First
|
||||
|
||||
**Decision:** Build projman completely before starting pmo
|
||||
**Why:**
|
||||
- Validate core functionality
|
||||
- Establish patterns
|
||||
- Reduce risk
|
||||
- PMO builds on projman foundation
|
||||
|
||||
---
|
||||
|
||||
## The Three-Agent Model
|
||||
|
||||
### Projman Agents
|
||||
|
||||
**Planner Agent:**
|
||||
- Sprint planning and architecture analysis
|
||||
- Asks clarifying questions
|
||||
- Suggests appropriate labels
|
||||
- Creates Gitea issues
|
||||
- Searches relevant lessons learned
|
||||
|
||||
**Orchestrator Agent:**
|
||||
- Sprint progress monitoring
|
||||
- Task coordination
|
||||
- Blocker identification
|
||||
- Git operations
|
||||
- Generates lean execution prompts
|
||||
|
||||
**Executor Agent:**
|
||||
- Implementation guidance
|
||||
- Code review suggestions
|
||||
- Testing strategy
|
||||
- Quality standards enforcement
|
||||
- Documentation
|
||||
|
||||
### PMO Agent
|
||||
|
||||
**PMO Coordinator:**
|
||||
- Strategic view across all projects
|
||||
- Cross-project dependency tracking
|
||||
- Resource conflict detection
|
||||
- Release coordination
|
||||
- Delegates to projman agents for details
|
||||
|
||||
---
|
||||
|
||||
## Wiki.js Structure
|
||||
|
||||
```
|
||||
Wiki.js: https://wiki.hyperhivelabs.com
|
||||
└── /hyper-hive-labs/
|
||||
├── projects/ # Project-specific
|
||||
│ ├── cuisineflow/
|
||||
│ │ ├── lessons-learned/
|
||||
│ │ │ ├── sprints/
|
||||
│ │ │ ├── patterns/
|
||||
│ │ │ └── INDEX.md
|
||||
│ │ └── documentation/
|
||||
│ ├── cuisineflow-site/
|
||||
│ ├── intuit-engine/
|
||||
│ └── hhl-site/
|
||||
├── company/ # Company-wide
|
||||
│ ├── processes/
|
||||
│ ├── standards/
|
||||
│ └── tools/
|
||||
└── shared/ # Cross-project
|
||||
├── architecture-patterns/
|
||||
├── best-practices/
|
||||
└── tech-stack/
|
||||
```
|
||||
|
||||
**Reference:** [MCP-WIKIJS.md](./MCP-WIKIJS.md#wiki-js-structure)
|
||||
|
||||
---
|
||||
|
||||
## Label Taxonomy System
|
||||
|
||||
### 43-Label System
|
||||
|
||||
**Organization Labels (27):**
|
||||
- Agent/2
|
||||
- Complexity/3
|
||||
- Efforts/5
|
||||
- Priority/4
|
||||
- Risk/3
|
||||
- Source/4
|
||||
- Type/6 (includes Type/Refactor)
|
||||
|
||||
**Repository Labels (16):**
|
||||
- Component/9
|
||||
- Tech/7
|
||||
|
||||
### Type/Refactor Label
|
||||
|
||||
**New organization-level label** for architectural work:
|
||||
- Service extraction
|
||||
- Architecture modifications
|
||||
- Code restructuring
|
||||
- Technical debt reduction
|
||||
|
||||
**Reference:** [PLUGIN-PROJMAN.md](./PLUGIN-PROJMAN.md#label-taxonomy-system)
|
||||
|
||||
---
|
||||
|
||||
## Build Order & Phases
|
||||
|
||||
### Build projman First (Phases 1-8)
|
||||
|
||||
**Phase 1:** Core Infrastructure (MCP servers)
|
||||
**Phase 2:** Sprint Planning Commands
|
||||
**Phase 3:** Agent System
|
||||
**Phase 4:** Lessons Learned System
|
||||
**Phase 5:** Testing & Validation
|
||||
**Phase 6:** Documentation & Refinement
|
||||
**Phase 7:** Marketplace Preparation
|
||||
**Phase 8:** Production Hardening
|
||||
|
||||
**Reference:** [PLUGIN-PROJMAN.md](./PLUGIN-PROJMAN.md#implementation-phases)
|
||||
|
||||
### Build pmo Second (Phases 9-12)
|
||||
|
||||
**Phase 9:** PMO Plugin Foundation
|
||||
**Phase 10:** PMO Commands & Workflows
|
||||
**Phase 11:** PMO Testing & Integration
|
||||
**Phase 12:** Production Deployment
|
||||
|
||||
**Reference:** [PLUGIN-PMO.md](./PLUGIN-PMO.md#implementation-phases)
|
||||
|
||||
---
|
||||
|
||||
## Quick Start Guide
|
||||
|
||||
### 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_gitea_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_wikijs_token
|
||||
WIKIJS_BASE_PATH=/hyper-hive-labs
|
||||
EOF
|
||||
|
||||
# Secure files
|
||||
chmod 600 ~/.config/claude/*.env
|
||||
```
|
||||
|
||||
### 2. Project Configuration
|
||||
|
||||
```bash
|
||||
# In each project root (for projman)
|
||||
cat > .env << EOF
|
||||
GITEA_REPO=cuisineflow
|
||||
WIKIJS_PROJECT=projects/cuisineflow
|
||||
EOF
|
||||
|
||||
# Add to .gitignore
|
||||
echo ".env" >> .gitignore
|
||||
```
|
||||
|
||||
### 3. MCP Server Setup
|
||||
|
||||
```bash
|
||||
# Gitea MCP Server
|
||||
cd mcp-servers/gitea
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
|
||||
# Wiki.js MCP Server
|
||||
cd mcp-servers/wikijs
|
||||
python -m venv .venv
|
||||
source .venv/bin/activate
|
||||
pip install -r requirements.txt
|
||||
```
|
||||
|
||||
### 4. Validate Setup
|
||||
|
||||
```bash
|
||||
# Test MCP servers
|
||||
python -m mcp_server.server --test # In each MCP directory
|
||||
|
||||
# Test plugin loading
|
||||
claude plugin test projman
|
||||
claude plugin test projman-pmo
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## Document Organization
|
||||
|
||||
This documentation is organized into 4 focused files plus this summary:
|
||||
|
||||
### 1. Gitea MCP Server Reference
|
||||
|
||||
**File:** [MCP-GITEA.md](./MCP-GITEA.md)
|
||||
|
||||
**Contains:**
|
||||
- Configuration setup
|
||||
- Python implementation
|
||||
- API client code
|
||||
- Issue and label tools
|
||||
- Testing strategies
|
||||
- Mode detection
|
||||
- Performance optimization
|
||||
|
||||
**Use when:** Implementing or troubleshooting Gitea integration
|
||||
|
||||
### 2. Wiki.js MCP Server Reference
|
||||
|
||||
**File:** [MCP-WIKIJS.md](./MCP-WIKIJS.md)
|
||||
|
||||
**Contains:**
|
||||
- Configuration setup
|
||||
- GraphQL client implementation
|
||||
- Wiki.js structure
|
||||
- Lessons learned system
|
||||
- Documentation tools
|
||||
- Company-wide patterns
|
||||
- PMO multi-project methods
|
||||
|
||||
**Use when:** Implementing or troubleshooting Wiki.js integration
|
||||
|
||||
### 3. Projman Plugin Reference
|
||||
|
||||
**File:** [PLUGIN-PROJMAN.md](./PLUGIN-PROJMAN.md)
|
||||
|
||||
**Contains:**
|
||||
- Plugin structure
|
||||
- Commands (sprint-plan, sprint-start, sprint-status, sprint-close, labels-sync)
|
||||
- Three agents (planner, orchestrator, executor)
|
||||
- Sprint workflow
|
||||
- Label taxonomy
|
||||
- Branch-aware security
|
||||
- Implementation phases 1-8
|
||||
|
||||
**Use when:** Building or using the projman plugin
|
||||
|
||||
### 4. PMO Plugin Reference
|
||||
|
||||
**File:** [PLUGIN-PMO.md](./PLUGIN-PMO.md)
|
||||
|
||||
**Contains:**
|
||||
- PMO plugin structure
|
||||
- Multi-project commands
|
||||
- PMO coordinator agent
|
||||
- Cross-project coordination
|
||||
- Dependency tracking
|
||||
- Resource conflict detection
|
||||
- Implementation phases 9-12
|
||||
|
||||
**Use when:** Building or using the projman-pmo plugin
|
||||
|
||||
### 5. This Summary
|
||||
|
||||
**File:** PROJECT-SUMMARY.md (this document)
|
||||
|
||||
**Contains:**
|
||||
- Project overview
|
||||
- Architecture decisions
|
||||
- Configuration approach
|
||||
- Quick start guide
|
||||
- References to detailed docs
|
||||
|
||||
**Use when:** Getting started or need high-level overview
|
||||
|
||||
---
|
||||
|
||||
## Key Success Metrics
|
||||
|
||||
### Technical Metrics
|
||||
|
||||
- Sprint planning time reduced by 40%
|
||||
- Manual steps eliminated: 10+ per sprint
|
||||
- Lessons learned capture rate: 100% (vs 0% before)
|
||||
- Label accuracy on issues: 90%+
|
||||
- Configuration setup time: < 5 minutes
|
||||
|
||||
### User Metrics
|
||||
|
||||
- User satisfaction: Better than current manual workflow
|
||||
- Learning curve: < 1 hour to basic proficiency
|
||||
- Error rate: < 5% incorrect operations
|
||||
- Adoption rate: 100% team adoption within 1 month
|
||||
|
||||
### PMO Metrics
|
||||
|
||||
- Cross-project visibility: 100% (vs fragmented before)
|
||||
- Dependency detection: Automated (vs manual tracking)
|
||||
- Resource conflict identification: Proactive (vs reactive)
|
||||
- Release coordination: Streamlined (vs ad-hoc)
|
||||
|
||||
---
|
||||
|
||||
## Critical Lessons from 15 Sprints
|
||||
|
||||
### Why Lessons Learned Is Critical
|
||||
|
||||
After 15 sprints without systematic lesson capture, repeated mistakes occurred:
|
||||
- Claude Code infinite loops on similar issues: 2-3 times
|
||||
- Same architectural mistakes: Multiple occurrences
|
||||
- Forgotten optimizations: Re-discovered each time
|
||||
|
||||
**Solution:** Mandatory lessons learned capture at sprint close, searchable at sprint start
|
||||
|
||||
### Branch Detection Must Be 100% Reliable
|
||||
|
||||
Production accidents are unacceptable. Branch-aware security prevents:
|
||||
- Accidental code changes on production branch
|
||||
- Sprint planning on wrong branch
|
||||
- Deployment mistakes
|
||||
|
||||
**Implementation:** Two layers - CLAUDE.md (file-level) + Plugin agents (tool-level)
|
||||
|
||||
### Configuration Complexity Is a Blocker
|
||||
|
||||
Previous attempts failed due to:
|
||||
- Complex per-project setup
|
||||
- Token management overhead
|
||||
- Multiple configuration files
|
||||
|
||||
**Solution:** Hybrid approach - system-level tokens + simple project-level paths
|
||||
|
||||
---
|
||||
|
||||
## Next Steps
|
||||
|
||||
### Immediate Actions
|
||||
|
||||
1. **Set up system configuration** (Gitea + Wiki.js tokens)
|
||||
2. **Create Wiki.js base structure** at `/hyper-hive-labs`
|
||||
3. **Begin Phase 1.1a** - Gitea MCP Server implementation
|
||||
4. **Begin Phase 1.1b** - Wiki.js MCP Server implementation
|
||||
|
||||
### Phase Execution
|
||||
|
||||
1. **Phases 1-4:** Build core projman functionality
|
||||
2. **Phase 5:** Validate with real sprint (e.g., Intuit Engine extraction)
|
||||
3. **Phases 6-8:** Polish, document, and harden projman
|
||||
4. **Phases 9-12:** Build and validate pmo plugin
|
||||
|
||||
### Validation Points
|
||||
|
||||
- **After Phase 1:** MCP servers working and tested
|
||||
- **After Phase 4:** Complete projman workflow end-to-end
|
||||
- **After Phase 5:** Real sprint successfully managed
|
||||
- **After Phase 8:** Production-ready projman
|
||||
- **After Phase 11:** Multi-project coordination validated
|
||||
- **After Phase 12:** Complete system operational
|
||||
|
||||
---
|
||||
|
||||
## Important Reminders
|
||||
|
||||
1. **Build projman FIRST** - Don't start pmo until projman is validated
|
||||
2. **MCP servers are SHARED** - Located at `mcp-servers/`, not inside plugins
|
||||
3. **Lessons learned is critical** - Prevents repeated mistakes
|
||||
4. **Test with real work** - Validate with actual sprints, not just unit tests
|
||||
5. **Security first** - Branch detection must be 100% reliable
|
||||
6. **Keep it simple** - Avoid over-engineering, focus on proven workflow
|
||||
|
||||
---
|
||||
|
||||
## Getting Help
|
||||
|
||||
### Documentation Structure
|
||||
|
||||
**Need details on:**
|
||||
- Gitea integration → [MCP-GITEA.md](./MCP-GITEA.md)
|
||||
- Wiki.js integration → [MCP-WIKIJS.md](./MCP-WIKIJS.md)
|
||||
- Projman usage → [PLUGIN-PROJMAN.md](./PLUGIN-PROJMAN.md)
|
||||
- PMO usage → [PLUGIN-PMO.md](./PLUGIN-PMO.md)
|
||||
- Overview → This document
|
||||
|
||||
### Quick Reference
|
||||
|
||||
| Question | Reference |
|
||||
|----------|-----------|
|
||||
| How do I set up configuration? | This document, "Quick Start Guide" |
|
||||
| What's the repository structure? | This document, "Repository Structure" |
|
||||
| How do Gitea tools work? | [MCP-GITEA.md](./MCP-GITEA.md) |
|
||||
| How do Wiki.js tools work? | [MCP-WIKIJS.md](./MCP-WIKIJS.md) |
|
||||
| How do I use sprint commands? | [PLUGIN-PROJMAN.md](./PLUGIN-PROJMAN.md#commands) |
|
||||
| How do agents work? | [PLUGIN-PROJMAN.md](./PLUGIN-PROJMAN.md#three-agent-model) |
|
||||
| How do I coordinate multiple projects? | [PLUGIN-PMO.md](./PLUGIN-PMO.md) |
|
||||
| What's the build order? | This document, "Build Order & Phases" |
|
||||
|
||||
---
|
||||
|
||||
## Project Timeline
|
||||
|
||||
**Planning:** Complete ✅
|
||||
**Phase 1-8 (projman):** 6-8 weeks estimated
|
||||
**Phase 9-12 (pmo):** 2-4 weeks estimated
|
||||
**Total:** 8-12 weeks from start to production
|
||||
|
||||
**Note:** No fixed deadlines - work at sustainable pace and validate thoroughly
|
||||
|
||||
---
|
||||
|
||||
## 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:** [MCP-GITEA.md](./MCP-GITEA.md) - Set up Gitea MCP Server
|
||||
|
||||
Good luck with the build! 🚀
|
||||
@@ -1,325 +0,0 @@
|
||||
# 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.
|
||||
@@ -1,241 +0,0 @@
|
||||
# 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!
|
||||
File diff suppressed because it is too large
Load Diff
@@ -1,729 +0,0 @@
|
||||
# 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! 🚀
|
||||
@@ -1,944 +0,0 @@
|
||||
# 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!
|
||||
148
hhl-claude-agents.code-workspace
Normal file
148
hhl-claude-agents.code-workspace
Normal file
@@ -0,0 +1,148 @@
|
||||
{
|
||||
"folders": [
|
||||
{
|
||||
"path": "."
|
||||
}
|
||||
],
|
||||
"settings": {
|
||||
// ===== Terminal Settings =====
|
||||
"terminal.integrated.defaultLocation": "editor",
|
||||
"terminal.integrated.fontSize": 12,
|
||||
// ===== Python Interpreter & Environment =====
|
||||
"python.defaultInterpreterPath": "${workspaceFolder}/.venv/bin/python",
|
||||
"python.terminal.activateEnvInCurrentTerminal": true,
|
||||
"python.envFile": "${workspaceFolder}/.env",
|
||||
// ===== Python Analysis & Type Checking =====
|
||||
"python.analysis.autoFormatStrings": true,
|
||||
"python.analysis.typeCheckingMode": "standard",
|
||||
"python.analysis.completeFunctionParens": true,
|
||||
"python.analysis.inlayHints.functionReturnTypes": true,
|
||||
"python.analysis.inlayHints.variableTypes": true,
|
||||
"python.analysis.extraPaths": [
|
||||
"${workspaceFolder}/src"
|
||||
],
|
||||
"python.analysis.autoImportCompletions": true,
|
||||
// ===== Python Testing (pytest) =====
|
||||
"python.testing.pytestEnabled": true,
|
||||
"python.testing.unittestEnabled": false,
|
||||
"python.testing.pytestArgs": [
|
||||
"tests",
|
||||
"-v",
|
||||
"--tb=short"
|
||||
],
|
||||
"python.testing.cwd": "${workspaceFolder}",
|
||||
"python.testing.autoTestDiscoverOnSaveEnabled": true,
|
||||
// ===== Editor General Settings =====
|
||||
"editor.colorDecorators": true,
|
||||
"editor.minimap.autohide": "none",
|
||||
"editor.formatOnSave": true,
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit"
|
||||
},
|
||||
"editor.folding": true,
|
||||
"editor.foldingStrategy": "auto",
|
||||
// ===== Workbench Settings =====
|
||||
"workbench.colorCustomizations": {
|
||||
"statusBar.background": "#028bb4",
|
||||
"statusBar.foreground": "#ffffff",
|
||||
"statusBar.noFolderBackground": "#000000",
|
||||
"statusBar.debuggingBackground": "#028bb4",
|
||||
"statusBar.border": "#028bb4",
|
||||
"statusBarItem.remoteBackground": "#036685"
|
||||
},
|
||||
"workbench.panel.defaultLocation": "right",
|
||||
// ===== File Settings =====
|
||||
"files.trimTrailingWhitespace": true,
|
||||
"files.insertFinalNewline": true,
|
||||
"files.exclude": {
|
||||
"**/__pycache__": true,
|
||||
"**/*.pyc": true,
|
||||
"**/.pytest_cache": true,
|
||||
"**/.mypy_cache": true,
|
||||
"**/.venv": true,
|
||||
"**/.env": false,
|
||||
"**/.vscode": false,
|
||||
"**/.DS_Store": true,
|
||||
"**/.claude": false,
|
||||
"**/.coverage": true,
|
||||
"**/htmlcov": true
|
||||
},
|
||||
// ===== Python-Specific Settings =====
|
||||
"[python]": {
|
||||
"diffEditor.ignoreTrimWhitespace": false,
|
||||
"editor.formatOnType": true,
|
||||
"editor.wordBasedSuggestions": "off",
|
||||
"editor.defaultFormatter": "ms-python.black-formatter",
|
||||
"editor.codeActionsOnSave": {
|
||||
"source.organizeImports": "explicit"
|
||||
}
|
||||
},
|
||||
// ===== Black Formatter Settings =====
|
||||
"black-formatter.args": [
|
||||
"--line-length=88"
|
||||
],
|
||||
// ===== JSON Settings =====
|
||||
"json.format.enable": true,
|
||||
"json.format.keepLines": true,
|
||||
"[json]": {
|
||||
"editor.quickSuggestions": {
|
||||
"strings": true
|
||||
},
|
||||
"editor.suggest.insertMode": "replace",
|
||||
"editor.defaultFormatter": "vscode.json-language-features"
|
||||
},
|
||||
// ===== Favorites Extension Settings =====
|
||||
"favorites.groups": [
|
||||
"Core",
|
||||
"Planning",
|
||||
"Plugins",
|
||||
"MCP",
|
||||
"Skills"
|
||||
],
|
||||
"favorites.currentGroup": "Core",
|
||||
"favorites.resources": [
|
||||
{
|
||||
"filePath": "CLAUDE.md",
|
||||
"group": "Core"
|
||||
},
|
||||
{
|
||||
"filePath": "README.md",
|
||||
"group": "Core"
|
||||
},
|
||||
{
|
||||
"filePath": "hhl-claude-agents.code-workspace",
|
||||
"group": "Core"
|
||||
},
|
||||
{
|
||||
"filePath": ".gitignore",
|
||||
"group": "Core"
|
||||
},
|
||||
{
|
||||
"filePath": "docs/references/projman-pmo/DOCUMENT-INDEX.md",
|
||||
"group": "Planning"
|
||||
},
|
||||
{
|
||||
"filePath": "docs/references/projman-pmo/CORRECT-ARCHITECTURE.md",
|
||||
"group": "Planning"
|
||||
},
|
||||
{
|
||||
"filePath": "docs/references/projman-pmo/projman-implementation-plan-updated.md",
|
||||
"group": "Planning"
|
||||
},
|
||||
{
|
||||
"filePath": "docs/references/projman-pmo/projman-python-quickstart.md",
|
||||
"group": "Planning"
|
||||
},
|
||||
{
|
||||
"filePath": "docs/references/projman-pmo/two-mcp-architecture-guide.md",
|
||||
"group": "Planning"
|
||||
},
|
||||
{
|
||||
"filePath": ".claude-plugins/marketplace.json",
|
||||
"group": "Plugins"
|
||||
}
|
||||
]
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user