From 8619cd2218ad87cc32ae8f5a8d928f561cfecf7e Mon Sep 17 00:00:00 2001 From: tegwick Date: Tue, 17 Mar 2026 22:24:30 +0100 Subject: [PATCH] =?UTF-8?q?feat(CUST-WP-0016):=20kaizen-agentic=20integrat?= =?UTF-8?q?ion=20=E2=80=94=20MCP=20tools,=20templates,=20direct=20install?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - 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 --- api/routers/domains.py | 19 +----- mcp_server/TOOLS.md | 24 +++++++ mcp_server/server.py | 83 ++++++++++++++++++++++++ scripts/project_rules/agents.template | 20 ++++++ scripts/project_rules/claude-md.template | 1 + scripts/register_project.sh | 2 +- 6 files changed, 132 insertions(+), 17 deletions(-) create mode 100644 scripts/project_rules/agents.template diff --git a/api/routers/domains.py b/api/routers/domains.py index 37b4636..d7d376b 100644 --- a/api/routers/domains.py +++ b/api/routers/domains.py @@ -73,16 +73,16 @@ async def get_domain( ) 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( select(func.count()).select_from(ExtensionPoint) - .where(ExtensionPoint.domain == slug) + .where(ExtensionPoint.domain_id == domain.id) ) ep_count = ep_count_row.scalar_one() td_count_row = await session.execute( select(func.count()).select_from(TechnicalDebt) - .where(TechnicalDebt.domain == slug) + .where(TechnicalDebt.domain_id == domain.id) ) td_count = td_count_row.scalar_one() @@ -127,19 +127,6 @@ async def rename_domain( domain.slug = body.new_slug 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.refresh(domain) return domain diff --git a/mcp_server/TOOLS.md b/mcp_server/TOOLS.md index dd794f5..7d42f0e 100644 --- a/mcp_server/TOOLS.md +++ b/mcp_server/TOOLS.md @@ -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 Run `list_domains()` to get the live list. Default 6: `custodian` · `railiance` · `markitect` · `coulomb_social` · `personhood` · `foerster_capabilities` diff --git a/mcp_server/server.py b/mcp_server/server.py index 49225dc..bd87fa3 100644 --- a/mcp_server/server.py +++ b/mcp_server/server.py @@ -992,6 +992,89 @@ def update_repo_path(repo_slug: str, path: str, host: str | None = None) -> str: 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 # --------------------------------------------------------------------------- diff --git a/scripts/project_rules/agents.template b/scripts/project_rules/agents.template new file mode 100644 index 0000000..0e8a5d9 --- /dev/null +++ b/scripts/project_rules/agents.template @@ -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. diff --git a/scripts/project_rules/claude-md.template b/scripts/project_rules/claude-md.template index b80cf0d..5d4c8c6 100644 --- a/scripts/project_rules/claude-md.template +++ b/scripts/project_rules/claude-md.template @@ -7,3 +7,4 @@ @.claude/rules/stack-and-commands.md @.claude/rules/architecture.md @.claude/rules/repo-boundary.md +@.claude/rules/agents.md diff --git a/scripts/register_project.sh b/scripts/register_project.sh index 0f7fe21..d257790 100755 --- a/scripts/register_project.sh +++ b/scripts/register_project.sh @@ -131,7 +131,7 @@ if [[ "$ADDITIONAL" != "--additional" ]]; then mkdir -p "$RULES_DIR" 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" out="$RULES_DIR/${rule}.md" if [[ -f "$tmpl" ]]; then