generated from coulomb/repo-seed
feat(CUST-WP-0016): kaizen-agentic integration — MCP tools, templates, direct install
- Fix /domains/{slug}/ 500: EP/TD queries now use domain_id FK (not string column)
- Remove dead cascade-slug code in rename_domain (FK handles it)
- MCP: list_kaizen_agents(category?) + get_kaizen_agent(name) via resolve_repo_path()
- TOOLS.md: Kaizen Agents section with discovery/load pattern
- agents.template: new project rule for consumer repos
- claude-md.template + register_project.sh: include agents.md in new-project scaffolding
- agents/: direct install of 6 curated agents for hub sessions
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -73,16 +73,16 @@ async def get_domain(
|
|||||||
)
|
)
|
||||||
ws_count = ws_count_row.scalar_one()
|
ws_count = ws_count_row.scalar_one()
|
||||||
|
|
||||||
# Count EPs and TDs (domain is a string column there)
|
# Count EPs and TDs
|
||||||
ep_count_row = await session.execute(
|
ep_count_row = await session.execute(
|
||||||
select(func.count()).select_from(ExtensionPoint)
|
select(func.count()).select_from(ExtensionPoint)
|
||||||
.where(ExtensionPoint.domain == slug)
|
.where(ExtensionPoint.domain_id == domain.id)
|
||||||
)
|
)
|
||||||
ep_count = ep_count_row.scalar_one()
|
ep_count = ep_count_row.scalar_one()
|
||||||
|
|
||||||
td_count_row = await session.execute(
|
td_count_row = await session.execute(
|
||||||
select(func.count()).select_from(TechnicalDebt)
|
select(func.count()).select_from(TechnicalDebt)
|
||||||
.where(TechnicalDebt.domain == slug)
|
.where(TechnicalDebt.domain_id == domain.id)
|
||||||
)
|
)
|
||||||
td_count = td_count_row.scalar_one()
|
td_count = td_count_row.scalar_one()
|
||||||
|
|
||||||
@@ -127,19 +127,6 @@ async def rename_domain(
|
|||||||
domain.slug = body.new_slug
|
domain.slug = body.new_slug
|
||||||
domain.name = body.new_name
|
domain.name = body.new_name
|
||||||
|
|
||||||
# Cascade slug rename to EP/TD string columns
|
|
||||||
if old_slug != body.new_slug:
|
|
||||||
await session.execute(
|
|
||||||
ExtensionPoint.__table__.update()
|
|
||||||
.where(ExtensionPoint.domain == old_slug)
|
|
||||||
.values(domain=body.new_slug)
|
|
||||||
)
|
|
||||||
await session.execute(
|
|
||||||
TechnicalDebt.__table__.update()
|
|
||||||
.where(TechnicalDebt.domain == old_slug)
|
|
||||||
.values(domain=body.new_slug)
|
|
||||||
)
|
|
||||||
|
|
||||||
await session.commit()
|
await session.commit()
|
||||||
await session.refresh(domain)
|
await session.refresh(domain)
|
||||||
return domain
|
return domain
|
||||||
|
|||||||
@@ -127,6 +127,30 @@ Dashboard: `http://localhost:3000/inbox`
|
|||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
## Kaizen Agents
|
||||||
|
|
||||||
|
Specialized agent personas from `kaizen-agentic/agents/`. Each agent is a markdown
|
||||||
|
instruction set — load it and follow the instructions it contains.
|
||||||
|
|
||||||
|
| Tool | Key Args | When to use |
|
||||||
|
|------|----------|-------------|
|
||||||
|
| `list_kaizen_agents(category?)` | `category`: optional filter (testing/quality/process/infrastructure) | Discover all 17 available agent personas with name, description, category. |
|
||||||
|
| `get_kaizen_agent(name)` | `name`: e.g. `"tdd-workflow"`, `"code-refactoring"` | Load full agent instructions. Read and follow them. |
|
||||||
|
|
||||||
|
**Common agents:**
|
||||||
|
|
||||||
|
| Agent | Category | When to use |
|
||||||
|
|-------|----------|-------------|
|
||||||
|
| `tdd-workflow` | testing | Step-by-step TDD8 workflow for any feature |
|
||||||
|
| `code-refactoring` | quality | Code quality analysis and safe refactoring |
|
||||||
|
| `test-maintenance` | testing | Diagnose and fix failing tests |
|
||||||
|
| `requirements-engineering` | process | Prevent interface/mock mismatches upfront |
|
||||||
|
| `keepaTodofile` | process | Maintain TODO.md during work |
|
||||||
|
| `project-management` | process | Track status, determine next steps |
|
||||||
|
| `datamodel-optimization` | quality | Optimize dataclasses and data structures |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
## Domain Slugs
|
## Domain Slugs
|
||||||
|
|
||||||
Run `list_domains()` to get the live list. Default 6: `custodian` · `railiance` · `markitect` · `coulomb_social` · `personhood` · `foerster_capabilities`
|
Run `list_domains()` to get the live list. Default 6: `custodian` · `railiance` · `markitect` · `coulomb_social` · `personhood` · `foerster_capabilities`
|
||||||
|
|||||||
@@ -992,6 +992,89 @@ def update_repo_path(repo_slug: str, path: str, host: str | None = None) -> str:
|
|||||||
return json.dumps(repo, indent=2)
|
return json.dumps(repo, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
# Kaizen Agents
|
||||||
|
# ---------------------------------------------------------------------------
|
||||||
|
|
||||||
|
def _kaizen_agents_dir() -> Path:
|
||||||
|
"""Resolve the kaizen-agentic agents/ directory via host_paths → local_path fallback."""
|
||||||
|
import socket as _socket
|
||||||
|
repo = _get("/repos/kaizen-agentic")
|
||||||
|
hostname = _socket.gethostname()
|
||||||
|
host_paths = repo.get("host_paths") or {}
|
||||||
|
base = host_paths.get(hostname) or repo.get("local_path") or ""
|
||||||
|
if not base:
|
||||||
|
raise FileNotFoundError("kaizen-agentic path not found for this host. Register it with update_repo_path().")
|
||||||
|
agents_dir = Path(base) / "agents"
|
||||||
|
if not agents_dir.is_dir():
|
||||||
|
raise FileNotFoundError(f"agents/ directory not found at {agents_dir}")
|
||||||
|
return agents_dir
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def list_kaizen_agents(category: str | None = None) -> str:
|
||||||
|
"""List all available kaizen agent personas.
|
||||||
|
|
||||||
|
Reads agent metadata from kaizen-agentic/agents/agent-*.md frontmatter.
|
||||||
|
Each agent is a specialized instruction set Claude can load and follow.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
category: Optional filter (e.g. 'testing', 'quality', 'process', 'infrastructure').
|
||||||
|
Returns all agents when omitted.
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
JSON list of {name, description, category, file} objects.
|
||||||
|
"""
|
||||||
|
import re as _re
|
||||||
|
agents_dir = _kaizen_agents_dir()
|
||||||
|
result = []
|
||||||
|
for f in sorted(agents_dir.glob("agent-*.md")):
|
||||||
|
name = f.stem.removeprefix("agent-")
|
||||||
|
text = f.read_text(encoding="utf-8")
|
||||||
|
# Extract optional YAML frontmatter fields
|
||||||
|
fm_match = _re.match(r"^---\n(.*?\n)---\n", text, _re.DOTALL)
|
||||||
|
meta: dict = {}
|
||||||
|
if fm_match:
|
||||||
|
for line in fm_match.group(1).splitlines():
|
||||||
|
if ":" in line:
|
||||||
|
k, _, v = line.partition(":")
|
||||||
|
meta[k.strip()] = v.strip()
|
||||||
|
agent_category = meta.get("category", "")
|
||||||
|
if category and agent_category.lower() != category.lower():
|
||||||
|
continue
|
||||||
|
# Fall back to first non-empty line after frontmatter as description
|
||||||
|
desc = meta.get("description", "")
|
||||||
|
if not desc:
|
||||||
|
for line in text.split("\n"):
|
||||||
|
line = line.strip()
|
||||||
|
if line and not line.startswith("#") and not line.startswith("---"):
|
||||||
|
desc = line[:120]
|
||||||
|
break
|
||||||
|
result.append({"name": name, "description": desc, "category": agent_category, "file": f.name})
|
||||||
|
return json.dumps(result, indent=2)
|
||||||
|
|
||||||
|
|
||||||
|
@mcp.tool()
|
||||||
|
def get_kaizen_agent(name: str) -> str:
|
||||||
|
"""Load the full instructions for a kaizen agent persona.
|
||||||
|
|
||||||
|
Read the returned markdown and follow the instructions it contains.
|
||||||
|
Use list_kaizen_agents() to discover available agent names.
|
||||||
|
|
||||||
|
Args:
|
||||||
|
name: Agent name without 'agent-' prefix (e.g. 'tdd-workflow', 'code-refactoring').
|
||||||
|
|
||||||
|
Returns:
|
||||||
|
Full markdown content of the agent definition file.
|
||||||
|
"""
|
||||||
|
agents_dir = _kaizen_agents_dir()
|
||||||
|
agent_file = agents_dir / f"agent-{name}.md"
|
||||||
|
if not agent_file.exists():
|
||||||
|
available = [f.stem.removeprefix("agent-") for f in sorted(agents_dir.glob("agent-*.md"))]
|
||||||
|
return json.dumps({"error": f"Agent '{name}' not found.", "available": available})
|
||||||
|
return agent_file.read_text(encoding="utf-8")
|
||||||
|
|
||||||
|
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
# ADR-001 compliance validation
|
# ADR-001 compliance validation
|
||||||
# ---------------------------------------------------------------------------
|
# ---------------------------------------------------------------------------
|
||||||
|
|||||||
20
scripts/project_rules/agents.template
Normal file
20
scripts/project_rules/agents.template
Normal file
@@ -0,0 +1,20 @@
|
|||||||
|
## Kaizen Agents
|
||||||
|
|
||||||
|
Specialized agent personas available on demand via the state-hub MCP.
|
||||||
|
|
||||||
|
**Discover:** `list_kaizen_agents()` — returns all agents with name, description, category
|
||||||
|
**Load:** `get_kaizen_agent("tdd-workflow")` — returns full instructions; read and follow them
|
||||||
|
|
||||||
|
Common agents:
|
||||||
|
|
||||||
|
| Agent | Category | When to use |
|
||||||
|
|-------|----------|-------------|
|
||||||
|
| `tdd-workflow` | testing | Step-by-step TDD8 workflow for any feature |
|
||||||
|
| `code-refactoring` | quality | Code quality analysis and safe refactoring |
|
||||||
|
| `test-maintenance` | testing | Diagnose and fix failing tests |
|
||||||
|
| `requirements-engineering` | process | Prevent interface/mock mismatches upfront |
|
||||||
|
| `keepaTodofile` | process | Maintain TODO.md during work |
|
||||||
|
| `project-management` | process | Track status, determine next steps |
|
||||||
|
| `datamodel-optimization` | quality | Optimize dataclasses and data structures |
|
||||||
|
|
||||||
|
All 17 agents: call `list_kaizen_agents()` for the full list.
|
||||||
@@ -7,3 +7,4 @@
|
|||||||
@.claude/rules/stack-and-commands.md
|
@.claude/rules/stack-and-commands.md
|
||||||
@.claude/rules/architecture.md
|
@.claude/rules/architecture.md
|
||||||
@.claude/rules/repo-boundary.md
|
@.claude/rules/repo-boundary.md
|
||||||
|
@.claude/rules/agents.md
|
||||||
|
|||||||
@@ -131,7 +131,7 @@ if [[ "$ADDITIONAL" != "--additional" ]]; then
|
|||||||
mkdir -p "$RULES_DIR"
|
mkdir -p "$RULES_DIR"
|
||||||
|
|
||||||
for rule in repo-identity session-protocol first-session workplan-convention \
|
for rule in repo-identity session-protocol first-session workplan-convention \
|
||||||
stack-and-commands architecture repo-boundary; do
|
stack-and-commands architecture repo-boundary agents; do
|
||||||
tmpl="$RULES_TEMPLATES_DIR/${rule}.template"
|
tmpl="$RULES_TEMPLATES_DIR/${rule}.template"
|
||||||
out="$RULES_DIR/${rule}.md"
|
out="$RULES_DIR/${rule}.md"
|
||||||
if [[ -f "$tmpl" ]]; then
|
if [[ -f "$tmpl" ]]; then
|
||||||
|
|||||||
Reference in New Issue
Block a user