Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion CLAUDE.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ This file provides guidance to Claude Code (claude.ai/code) when working with co
**Current Status:** Scaffolding commands implemented: `create mcp-server`, `create agent`, `create gateway`, `create ui`, `create sandbox`, `create model-car`. Post-scaffolding commands: `generate` (tool, resource, prompt, middleware), `patch` (check, all + type-specific category subcommands — see below), `add` (code-executor, files, vision), `vendor`. Note: `create workflow` exists in code but is not yet working.

The `patch` command is type-aware via `template.type` in `.template-info`:
- **MCP server** projects expose `patch generators | core | docs | build`.
- **MCP server** projects expose `patch generators | core | docs | build | claude`.
- **Agent / workflow** projects expose `patch chart | docs | build | claude`.
Running an MCP-only subcommand inside an agent project (or vice versa) exits with a clear "available categories" error. `patch check` and `patch all` work for any supported type.

Expand Down
3 changes: 2 additions & 1 deletion src/fips_agents_cli/commands/patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -149,9 +149,10 @@ def chart(dry_run: bool):
)
def claude(dry_run: bool):
"""
Update Claude Code slash commands (agent / workflow projects only).
Update Claude Code slash commands and rules.

Patches files under .claude/commands/ that ship with the template.
For agent / workflow projects also patches .claude/rules/.
"""
_patch_category("claude", dry_run)

Expand Down
26 changes: 24 additions & 2 deletions src/fips_agents_cli/tools/patching.py
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,10 @@
"core": {
"description": "Core infrastructure (server, auth, etc)",
"patterns": [
"src/main.py",
"src/core/server.py",
"src/core/auth.py",
"src/*/__ init__.py", # Package __init__ files
"src/*/__init__.py", # Package __init__ files
"conftest.py",
],
"ask_before_patch": True, # May be customized
Expand All @@ -39,8 +40,12 @@
"patterns": [
"docs/**/*",
"*/examples/**/*", # Examples in any directory
"AGENTS.md",
"CLAUDE.md",
"ARCHITECTURE.md",
"CONTRIBUTING.md",
"DEVELOPMENT_PROCESS.md",
"OPENSHIFT_DEPLOYMENT.md",
"TESTING.md",
],
"ask_before_patch": False, # Usually safe to update
Expand All @@ -53,9 +58,19 @@
"openshift.yaml",
"deploy.sh",
"remove_examples.sh",
".dockerignore",
".gitignore",
".gitleaks.toml",
],
"ask_before_patch": True, # May be customized
},
"claude": {
"description": "Claude Code slash commands shipped with the template",
"patterns": [
".claude/commands/**/*",
],
"ask_before_patch": False, # Safe to overwrite
},
}

# Files to NEVER patch in MCP server projects (user code)
Expand Down Expand Up @@ -105,9 +120,10 @@
"ask_before_patch": True, # May be customized
},
"claude": {
"description": "Claude Code slash commands shipped with the template",
"description": "Claude Code slash commands and rules shipped with the template",
"patterns": [
".claude/commands/**/*",
".claude/rules/**/*",
],
"ask_before_patch": False, # Safe to overwrite
},
Expand All @@ -119,8 +135,14 @@
"agent.yaml", # User's agent config
"chart/values.yaml", # User's deploy values
"src/fipsagents/**", # Vendored — managed by `fips-agents vendor --update`
"tools/**", # User-authored tools (target of `fips-agents add code-executor`)
"examples/**", # User-authored examples (target of `fips-agents add vision`)
"prompts/**", # User-customized agent prompts
"rules/**", # User-customized agent rules
"skills/**", # User-customized agent skills
"tests/**/*.py",
".env*",
".memoryhub.yaml", # User-customized memory hub config
"README.md",
"pyproject.toml", # User may have added dependencies
]
Expand Down
77 changes: 77 additions & 0 deletions tests/test_patch.py
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,83 @@ def test_agent_categories_have_no_framework_language(self):
assert "framework" not in config["description"].lower()


class TestMcpCategoryPatterns:
"""Patterns for MCP categories must match the files the template ships.

Regression tests for issue #42: the original `core` patterns had a literal
space in `src/*/__ init__.py`, and `claude` was missing entirely.
"""

def test_core_init_pattern_has_no_space_typo(self):
# `src/*/__init__.py` must NOT have a space — that pattern matched nothing
patterns = MCP_FILE_CATEGORIES["core"]["patterns"]
assert "src/*/__init__.py" in patterns
assert not any(" " in p for p in patterns), patterns

def test_core_init_pattern_matches_real_init_files(self):
# Path.match validates the fix — a real package __init__.py matches now
assert Path("src/core/__init__.py").match("src/*/__init__.py")
assert Path("src/middleware/__init__.py").match("src/*/__init__.py")

def test_core_includes_main_entry_point(self):
# src/main.py is the MCP server entry point and ships with the template
assert "src/main.py" in MCP_FILE_CATEGORIES["core"]["patterns"]

def test_claude_category_exists_for_mcp(self):
# MCP template ships .claude/commands/*.md — must be patchable
assert "claude" in MCP_FILE_CATEGORIES
patterns = MCP_FILE_CATEGORIES["claude"]["patterns"]
assert ".claude/commands/**/*" in patterns
assert MCP_FILE_CATEGORIES["claude"]["ask_before_patch"] is False

def test_docs_includes_recently_added_files(self):
# AGENTS.md, CONTRIBUTING.md and friends ship in the MCP template root
patterns = MCP_FILE_CATEGORIES["docs"]["patterns"]
for expected in [
"AGENTS.md",
"CONTRIBUTING.md",
"DEVELOPMENT_PROCESS.md",
"OPENSHIFT_DEPLOYMENT.md",
]:
assert expected in patterns, f"{expected} missing from MCP docs patterns"

def test_build_includes_root_dotfiles(self):
patterns = MCP_FILE_CATEGORIES["build"]["patterns"]
for expected in [".dockerignore", ".gitignore", ".gitleaks.toml"]:
assert expected in patterns, f"{expected} missing from MCP build patterns"


class TestAgentCategoryPatterns:
"""Regression tests for issue #42: agent template gaps."""

def test_claude_category_includes_rules(self):
# Agent template ships .claude/rules/agent-development.md
patterns = AGENT_FILE_CATEGORIES["claude"]["patterns"]
assert ".claude/commands/**/*" in patterns
assert ".claude/rules/**/*" in patterns


class TestAgentNeverPatchExtensions:
"""`add` writes user-customized files into well-known directories.
Those paths must be in NEVER_PATCH so a future pattern broadening
cannot clobber them.
"""

@pytest.mark.parametrize(
"expected",
[
"tools/**",
"examples/**",
"prompts/**",
"rules/**",
"skills/**",
".memoryhub.yaml",
],
)
def test_user_directory_is_never_patched(self, expected):
assert expected in AGENT_NEVER_PATCH


# ---------------------------------------------------------------------------
# Unit tests — find_fips_project_root walks up to .template-info
# ---------------------------------------------------------------------------
Expand Down
Loading