fips-agents-cli 0.1.8__tar.gz → 0.2.0__tar.gz

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (53) hide show
  1. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/.github/workflows/test.yml +2 -0
  2. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/.github/workflows/workflow.yaml +1 -1
  3. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/PKG-INFO +24 -1
  4. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/README.md +23 -0
  5. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/pyproject.toml +1 -1
  6. fips_agents_cli-0.2.0/src/fips_agents_cli/commands/create.py +447 -0
  7. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/model_car.py +74 -5
  8. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/patch.py +15 -0
  9. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/git.py +60 -0
  10. fips_agents_cli-0.2.0/src/fips_agents_cli/tools/github.py +193 -0
  11. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/project.py +12 -0
  12. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/version.py +1 -1
  13. fips_agents_cli-0.2.0/tests/test_create.py +559 -0
  14. fips_agents_cli-0.2.0/tests/test_github.py +274 -0
  15. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/test_model_car.py +26 -8
  16. fips_agents_cli-0.1.8/src/fips_agents_cli/commands/create.py +0 -192
  17. fips_agents_cli-0.1.8/tests/test_create.py +0 -193
  18. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/.claude/commands/create-release.md +0 -0
  19. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/.github/agents/README.md +0 -0
  20. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/.github/agents/create-release.agent.md +0 -0
  21. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/.gitignore +0 -0
  22. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/AGENT_FRAMEWORK_PLAN.md +0 -0
  23. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/BAML_RESEARCH_REPORT.md +0 -0
  24. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/CLAUDE.md +0 -0
  25. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/GENERATOR_IMPLEMENTATION_PLAN.md +0 -0
  26. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/IMPLEMENTATION_SUMMARY.md +0 -0
  27. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/Ignite-CLI-Architecture-Analysis.md +0 -0
  28. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/LICENSE +0 -0
  29. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/MVP-PLAN.md +0 -0
  30. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/PLAN.md +0 -0
  31. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/PROMPT_ISSUE.md +0 -0
  32. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/PUBLISHING.md +0 -0
  33. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/QUICK_START_PUBLISHING.md +0 -0
  34. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/RELEASE_CHECKLIST.md +0 -0
  35. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/scripts/README.md +0 -0
  36. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/scripts/release.sh +0 -0
  37. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/__init__.py +0 -0
  38. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/__main__.py +0 -0
  39. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/cli.py +0 -0
  40. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/__init__.py +0 -0
  41. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/commands/generate.py +0 -0
  42. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/__init__.py +0 -0
  43. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/filesystem.py +0 -0
  44. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/generators.py +0 -0
  45. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/patching.py +0 -0
  46. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/src/fips_agents_cli/tools/validation.py +0 -0
  47. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/__init__.py +0 -0
  48. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/conftest.py +0 -0
  49. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/test_filesystem.py +0 -0
  50. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/test_generate.py +0 -0
  51. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/test_generators.py +0 -0
  52. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/test_project.py +0 -0
  53. {fips_agents_cli-0.1.8 → fips_agents_cli-0.2.0}/tests/test_validation.py +0 -0
@@ -3,6 +3,8 @@ name: Tests
3
3
  on:
4
4
  push:
5
5
  branches: [ main ]
6
+ tags:
7
+ - 'v*.*.*'
6
8
  pull_request:
7
9
  branches: [ main ]
8
10
 
@@ -21,7 +21,7 @@ jobs:
21
21
  uses: lewagon/wait-on-check-action@v1.3.1
22
22
  with:
23
23
  ref: ${{ github.ref }}
24
- check-name: 'Tests Status'
24
+ check-regexp: 'Test on Python'
25
25
  repo-token: ${{ secrets.GITHUB_TOKEN }}
26
26
  wait-interval: 10
27
27
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: fips-agents-cli
3
- Version: 0.1.8
3
+ Version: 0.2.0
4
4
  Summary: CLI tool for creating and managing FIPS-compliant AI agent projects
5
5
  Project-URL: Homepage, https://github.com/rdwj/fips-agents-cli
6
6
  Project-URL: Repository, https://github.com/rdwj/fips-agents-cli
@@ -528,6 +528,29 @@ MIT License - see LICENSE file for details
528
528
 
529
529
  ## Changelog
530
530
 
531
+ ### Version 0.2.0
532
+
533
+ - Feature: GitHub integration for `create mcp-server` command
534
+ - Feature: New `--github` flag to create GitHub repository and push code
535
+ - Feature: New `--local` flag to skip GitHub and create local-only project
536
+ - Feature: Non-interactive mode (`--yes`) for agent/CI workflows
537
+ - Feature: New `--private` flag to create private GitHub repositories
538
+ - Feature: New `--org` option to create repositories in GitHub organizations
539
+ - Feature: New `--description` option for GitHub repository descriptions
540
+ - Feature: New `--remote-only` flag to create GitHub repo without local clone
541
+ - Feature: Added missing `patch build` subcommand for updating build/deployment files
542
+ - Feature: GitHub metadata tracking in `.template-info` file
543
+ - Feature: New git utilities for remote management (`add_remote`, `push_to_remote`)
544
+ - Improvement: Auto-detects `gh` CLI and prompts user when available
545
+ - Improvement: Clean git history - customizes project before initial push
546
+
547
+ ### Version 0.1.9
548
+
549
+ - Feature: Added `.fips-agents-cli` directory to ModelCar projects with generation metadata
550
+ - Feature: ModelCar projects now include `info.json` with source, destination, and generator info
551
+ - Feature: ModelCar projects now include `CLAUDE.md` with project-specific Claude Code instructions
552
+ - Improvement: Consistent project metadata structure between MCP server and ModelCar projects
553
+
531
554
  ### Version 0.1.8
532
555
 
533
556
  - Feature: Added GitHub Copilot agent template support
@@ -495,6 +495,29 @@ MIT License - see LICENSE file for details
495
495
 
496
496
  ## Changelog
497
497
 
498
+ ### Version 0.2.0
499
+
500
+ - Feature: GitHub integration for `create mcp-server` command
501
+ - Feature: New `--github` flag to create GitHub repository and push code
502
+ - Feature: New `--local` flag to skip GitHub and create local-only project
503
+ - Feature: Non-interactive mode (`--yes`) for agent/CI workflows
504
+ - Feature: New `--private` flag to create private GitHub repositories
505
+ - Feature: New `--org` option to create repositories in GitHub organizations
506
+ - Feature: New `--description` option for GitHub repository descriptions
507
+ - Feature: New `--remote-only` flag to create GitHub repo without local clone
508
+ - Feature: Added missing `patch build` subcommand for updating build/deployment files
509
+ - Feature: GitHub metadata tracking in `.template-info` file
510
+ - Feature: New git utilities for remote management (`add_remote`, `push_to_remote`)
511
+ - Improvement: Auto-detects `gh` CLI and prompts user when available
512
+ - Improvement: Clean git history - customizes project before initial push
513
+
514
+ ### Version 0.1.9
515
+
516
+ - Feature: Added `.fips-agents-cli` directory to ModelCar projects with generation metadata
517
+ - Feature: ModelCar projects now include `info.json` with source, destination, and generator info
518
+ - Feature: ModelCar projects now include `CLAUDE.md` with project-specific Claude Code instructions
519
+ - Improvement: Consistent project metadata structure between MCP server and ModelCar projects
520
+
498
521
  ### Version 0.1.8
499
522
 
500
523
  - Feature: Added GitHub Copilot agent template support
@@ -4,7 +4,7 @@ build-backend = "hatchling.build"
4
4
 
5
5
  [project]
6
6
  name = "fips-agents-cli"
7
- version = "0.1.8"
7
+ version = "0.2.0"
8
8
  description = "CLI tool for creating and managing FIPS-compliant AI agent projects"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.10"
@@ -0,0 +1,447 @@
1
+ """Create command for generating new projects from templates."""
2
+
3
+ import sys
4
+
5
+ import click
6
+ from rich.console import Console
7
+ from rich.panel import Panel
8
+ from rich.progress import Progress, SpinnerColumn, TextColumn
9
+
10
+ from fips_agents_cli.commands.model_car import model_car
11
+ from fips_agents_cli.tools.filesystem import resolve_target_path, validate_target_directory
12
+ from fips_agents_cli.tools.git import (
13
+ add_remote,
14
+ clone_template,
15
+ init_repository,
16
+ is_git_installed,
17
+ push_to_remote,
18
+ )
19
+ from fips_agents_cli.tools.github import (
20
+ check_gh_prerequisites,
21
+ create_github_repo,
22
+ get_github_username,
23
+ is_gh_authenticated,
24
+ is_gh_installed,
25
+ )
26
+ from fips_agents_cli.tools.project import (
27
+ cleanup_template_files,
28
+ to_module_name,
29
+ update_project_name,
30
+ validate_project_name,
31
+ write_template_info,
32
+ )
33
+
34
+ console = Console()
35
+
36
+ # Template URL for MCP server projects
37
+ MCP_SERVER_TEMPLATE_URL = "https://github.com/rdwj/mcp-server-template"
38
+
39
+
40
+ @click.group()
41
+ def create():
42
+ """Create new projects from templates."""
43
+ pass
44
+
45
+
46
+ # Register subcommands
47
+ create.add_command(model_car)
48
+
49
+
50
+ @create.command("mcp-server")
51
+ @click.argument("project_name")
52
+ @click.option(
53
+ "--target-dir",
54
+ "-t",
55
+ default=None,
56
+ help="Target directory for the project (default: current directory)",
57
+ )
58
+ @click.option(
59
+ "--no-git",
60
+ is_flag=True,
61
+ default=False,
62
+ help="Skip git repository initialization",
63
+ )
64
+ @click.option(
65
+ "--github",
66
+ "use_github",
67
+ is_flag=True,
68
+ default=False,
69
+ help="Create GitHub repository and push code",
70
+ )
71
+ @click.option(
72
+ "--local",
73
+ "use_local",
74
+ is_flag=True,
75
+ default=False,
76
+ help="Create local project only (skip GitHub)",
77
+ )
78
+ @click.option(
79
+ "--yes",
80
+ "-y",
81
+ is_flag=True,
82
+ default=False,
83
+ help="Non-interactive mode (use defaults, skip prompts)",
84
+ )
85
+ @click.option(
86
+ "--private",
87
+ is_flag=True,
88
+ default=False,
89
+ help="Make GitHub repository private (default: public)",
90
+ )
91
+ @click.option(
92
+ "--org",
93
+ default=None,
94
+ help="GitHub organization to create repository in",
95
+ )
96
+ @click.option(
97
+ "--description",
98
+ "-d",
99
+ "repo_description",
100
+ default=None,
101
+ help="GitHub repository description",
102
+ )
103
+ @click.option(
104
+ "--remote-only",
105
+ is_flag=True,
106
+ default=False,
107
+ help="Create GitHub repo only, don't clone locally",
108
+ )
109
+ def mcp_server(
110
+ project_name: str,
111
+ target_dir: str | None,
112
+ no_git: bool,
113
+ use_github: bool,
114
+ use_local: bool,
115
+ yes: bool,
116
+ private: bool,
117
+ org: str | None,
118
+ repo_description: str | None,
119
+ remote_only: bool,
120
+ ):
121
+ """
122
+ Create a new MCP server project from template.
123
+
124
+ PROJECT_NAME must start with a lowercase letter and contain only
125
+ lowercase letters, numbers, hyphens, and underscores.
126
+
127
+ By default, if GitHub CLI (gh) is installed and authenticated, prompts
128
+ to create a GitHub repository. Use --local to skip this, or --github
129
+ to require it. Use --yes for non-interactive mode (agents/CI).
130
+
131
+ Examples:
132
+
133
+ fips-agents create mcp-server my-mcp-server
134
+
135
+ fips-agents create mcp-server my-mcp-server --github --private
136
+
137
+ fips-agents create mcp-server my-mcp-server --local
138
+
139
+ fips-agents create mcp-server my-mcp-server --yes # Non-interactive
140
+ """
141
+ try:
142
+ # Step 1: Validate options
143
+ if use_github and use_local:
144
+ console.print("[red]✗[/red] Cannot use --github and --local together")
145
+ sys.exit(1)
146
+
147
+ if remote_only and use_local:
148
+ console.print("[red]✗[/red] Cannot use --remote-only with --local")
149
+ sys.exit(1)
150
+
151
+ # Step 2: Validate project name
152
+ console.print("\n[bold cyan]Creating MCP Server Project[/bold cyan]\n")
153
+
154
+ is_valid, error_msg = validate_project_name(project_name)
155
+ if not is_valid:
156
+ console.print(f"[red]✗[/red] Invalid project name: {error_msg}")
157
+ sys.exit(1)
158
+
159
+ console.print(f"[green]✓[/green] Project name '{project_name}' is valid")
160
+
161
+ # Step 3: Determine mode (GitHub or local)
162
+ create_github = _determine_github_mode(use_github, use_local, yes)
163
+
164
+ # Step 4: Check prerequisites
165
+ if not is_git_installed():
166
+ console.print(
167
+ "[yellow]⚠[/yellow] Git is not installed. This is required for cloning templates."
168
+ )
169
+ console.print("[yellow]Hint:[/yellow] Install git from https://git-scm.com/downloads")
170
+ sys.exit(1)
171
+
172
+ if create_github:
173
+ ready, error_msg = check_gh_prerequisites()
174
+ if not ready:
175
+ console.print(f"[red]✗[/red] {error_msg}")
176
+ sys.exit(1)
177
+
178
+ # Step 5: Resolve and validate target directory (skip for remote-only)
179
+ target_path = None
180
+ if not remote_only:
181
+ target_path = resolve_target_path(project_name, target_dir)
182
+
183
+ is_valid, error_msg = validate_target_directory(target_path, allow_existing=False)
184
+ if not is_valid:
185
+ console.print(f"[red]✗[/red] {error_msg}")
186
+ console.print(
187
+ "\n[yellow]Hint:[/yellow] Choose a different name or remove the existing "
188
+ "directory"
189
+ )
190
+ sys.exit(1)
191
+
192
+ console.print(f"[green]✓[/green] Target directory: {target_path}")
193
+
194
+ # Step 6: Create GitHub repo first (if GitHub mode)
195
+ github_repo = None
196
+ github_url = None
197
+ if create_github:
198
+ success, github_url, error_msg = create_github_repo(
199
+ name=project_name,
200
+ private=private,
201
+ org=org,
202
+ description=repo_description,
203
+ )
204
+ if not success:
205
+ console.print(f"[red]✗[/red] {error_msg}")
206
+ sys.exit(1)
207
+
208
+ # Construct repo identifier
209
+ owner = org if org else get_github_username()
210
+ github_repo = f"{owner}/{project_name}"
211
+
212
+ # Step 7: Handle remote-only mode
213
+ if remote_only:
214
+ _show_remote_only_success(project_name, github_url, github_repo)
215
+ return
216
+
217
+ # Step 8: Clone template repository
218
+ template_commit = None
219
+ with Progress(
220
+ SpinnerColumn(),
221
+ TextColumn("[progress.description]{task.description}"),
222
+ console=console,
223
+ ) as progress:
224
+ progress.add_task(description="Cloning template repository...", total=None)
225
+ try:
226
+ template_commit = clone_template(MCP_SERVER_TEMPLATE_URL, target_path)
227
+ except Exception as e:
228
+ console.print("\n[red]✗[/red] Failed to clone template repository")
229
+ console.print(f"[red]Error:[/red] {e}")
230
+ console.print(
231
+ f"\n[yellow]Hint:[/yellow] Check your internet connection and verify "
232
+ f"the template URL is accessible:\n{MCP_SERVER_TEMPLATE_URL}"
233
+ )
234
+ sys.exit(1)
235
+
236
+ # Step 9: Customize project
237
+ with Progress(
238
+ SpinnerColumn(),
239
+ TextColumn("[progress.description]{task.description}"),
240
+ console=console,
241
+ ) as progress:
242
+ progress.add_task(description="Customizing project...", total=None)
243
+ try:
244
+ update_project_name(target_path, project_name)
245
+ cleanup_template_files(target_path)
246
+ if template_commit:
247
+ write_template_info(
248
+ target_path,
249
+ project_name,
250
+ MCP_SERVER_TEMPLATE_URL,
251
+ template_commit,
252
+ github_repo=github_repo,
253
+ github_url=github_url,
254
+ )
255
+ except Exception as e:
256
+ console.print("\n[red]✗[/red] Failed to customize project")
257
+ console.print(f"[red]Error:[/red] {e}")
258
+ sys.exit(1)
259
+
260
+ # Step 10: Initialize git repository
261
+ if not no_git:
262
+ with Progress(
263
+ SpinnerColumn(),
264
+ TextColumn("[progress.description]{task.description}"),
265
+ console=console,
266
+ ) as progress:
267
+ progress.add_task(description="Initializing git repository...", total=None)
268
+ try:
269
+ init_repository(target_path, initial_commit=True)
270
+ except Exception as e:
271
+ console.print("\n[yellow]⚠[/yellow] Failed to initialize git repository")
272
+ console.print(f"[yellow]Warning:[/yellow] {e}")
273
+ console.print(
274
+ "[yellow]You can initialize git manually later with:[/yellow] git init"
275
+ )
276
+
277
+ # Step 11: Push to GitHub (if GitHub mode)
278
+ if create_github and not no_git:
279
+ try:
280
+ add_remote(target_path, "origin", github_url)
281
+ push_success = push_to_remote(target_path, "origin", "main")
282
+ if not push_success:
283
+ console.print(
284
+ "\n[yellow]⚠[/yellow] Failed to push to GitHub. "
285
+ "You can push manually with: git push -u origin main"
286
+ )
287
+ except Exception as e:
288
+ console.print(f"\n[yellow]⚠[/yellow] Failed to set up GitHub remote: {e}")
289
+ console.print("[yellow]You can add the remote manually with:[/yellow]")
290
+ console.print(f" git remote add origin {github_url}")
291
+ console.print(" git push -u origin main")
292
+
293
+ # Step 12: Success message
294
+ _show_success_message(
295
+ project_name=project_name,
296
+ target_path=target_path,
297
+ github_url=github_url,
298
+ github_repo=github_repo,
299
+ )
300
+
301
+ except KeyboardInterrupt:
302
+ console.print("\n[yellow]⚠[/yellow] Operation cancelled by user")
303
+ sys.exit(130)
304
+ except Exception as e:
305
+ console.print(f"\n[red]✗[/red] Unexpected error: {e}")
306
+ sys.exit(1)
307
+
308
+
309
+ def _determine_github_mode(use_github: bool, use_local: bool, yes: bool) -> bool:
310
+ """
311
+ Determine whether to create a GitHub repository.
312
+
313
+ Args:
314
+ use_github: --github flag was set
315
+ use_local: --local flag was set
316
+ yes: --yes flag was set (non-interactive mode)
317
+
318
+ Returns:
319
+ bool: True if GitHub repository should be created
320
+ """
321
+ # Explicit flags take precedence
322
+ if use_local:
323
+ console.print("[dim]Mode: Local only (--local)[/dim]")
324
+ return False
325
+
326
+ if use_github:
327
+ console.print("[dim]Mode: GitHub (--github)[/dim]")
328
+ return True
329
+
330
+ # Check if gh is available
331
+ if not is_gh_installed():
332
+ console.print("[dim]Mode: Local only (GitHub CLI not installed)[/dim]")
333
+ return False
334
+
335
+ if not is_gh_authenticated():
336
+ console.print("[dim]Mode: Local only (GitHub CLI not authenticated)[/dim]")
337
+ return False
338
+
339
+ # gh is available - decide based on interactive mode
340
+ if yes:
341
+ # Non-interactive: default to GitHub
342
+ console.print("[dim]Mode: GitHub (--yes with gh available)[/dim]")
343
+ return True
344
+
345
+ # Interactive: prompt user
346
+ console.print("[cyan]GitHub CLI detected and authenticated.[/cyan]")
347
+ return click.confirm("Create GitHub repository?", default=True)
348
+
349
+
350
+ def _show_success_message(
351
+ project_name: str,
352
+ target_path,
353
+ github_url: str | None,
354
+ github_repo: str | None,
355
+ ) -> None:
356
+ """Display success message with next steps."""
357
+ module_name = to_module_name(project_name)
358
+
359
+ # Build project details section
360
+ details = f""" • Name: {project_name}
361
+ • Module: {module_name}
362
+ • Location: {target_path}"""
363
+
364
+ if github_url:
365
+ details += f"\n • GitHub: {github_url}"
366
+
367
+ # Build next steps based on mode
368
+ if github_url:
369
+ next_steps = f"""
370
+ 1. Navigate to your project:
371
+ [dim]cd {target_path.name}[/dim]
372
+
373
+ 2. Create and activate a virtual environment:
374
+ [dim]python -m venv venv[/dim]
375
+ [dim]source venv/bin/activate[/dim] # On Windows: venv\\Scripts\\activate
376
+
377
+ 3. Install the project in editable mode:
378
+ [dim]pip install -e .[dev][/dim]
379
+
380
+ 4. Start developing your MCP server!
381
+ [dim]Your code is already pushed to GitHub[/dim]
382
+
383
+ 5. Run tests:
384
+ [dim]pytest[/dim]"""
385
+ else:
386
+ next_steps = f"""
387
+ 1. Navigate to your project:
388
+ [dim]cd {target_path.name}[/dim]
389
+
390
+ 2. Create and activate a virtual environment:
391
+ [dim]python -m venv venv[/dim]
392
+ [dim]source venv/bin/activate[/dim] # On Windows: venv\\Scripts\\activate
393
+
394
+ 3. Install the project in editable mode:
395
+ [dim]pip install -e .[dev][/dim]
396
+
397
+ 4. Start developing your MCP server!
398
+ [dim]Edit src/ files to add your functionality[/dim]
399
+
400
+ 5. Run tests:
401
+ [dim]pytest[/dim]"""
402
+
403
+ success_message = f"""
404
+ [bold green]✓ Successfully created MCP server project![/bold green]
405
+
406
+ [bold cyan]Project Details:[/bold cyan]
407
+ {details}
408
+
409
+ [bold cyan]Next Steps:[/bold cyan]
410
+ {next_steps}
411
+
412
+ [bold cyan]Documentation:[/bold cyan]
413
+ • Check the README.md in your project for detailed instructions
414
+ • MCP Protocol docs: https://modelcontextprotocol.io/
415
+ """
416
+
417
+ console.print(Panel(success_message, border_style="green", padding=(1, 2)))
418
+
419
+
420
+ def _show_remote_only_success(
421
+ project_name: str,
422
+ github_url: str,
423
+ github_repo: str,
424
+ ) -> None:
425
+ """Display success message for remote-only mode."""
426
+ success_message = f"""
427
+ [bold green]✓ Successfully created GitHub repository![/bold green]
428
+
429
+ [bold cyan]Repository Details:[/bold cyan]
430
+ • Name: {project_name}
431
+ • GitHub: {github_url}
432
+
433
+ [bold cyan]Next Steps:[/bold cyan]
434
+
435
+ 1. Clone the repository:
436
+ [dim]git clone {github_url}[/dim]
437
+ [dim]cd {project_name}[/dim]
438
+
439
+ 2. The repository contains the MCP server template.
440
+ Customize it for your project.
441
+
442
+ [bold cyan]Note:[/bold cyan]
443
+ The repository contains the raw template.
444
+ You may want to customize project names and paths.
445
+ """
446
+
447
+ console.print(Panel(success_message, border_style="green", padding=(1, 2)))
@@ -536,22 +536,85 @@ serving.knative.dev/progress-deadline: 30m
536
536
  """
537
537
 
538
538
 
539
+ def generate_modelcar_claude_md(hf_repo_id: str, model_name: str, quay_uri: str) -> str:
540
+ """Generate CLAUDE.md content for ModelCar projects."""
541
+ return f"""# CLAUDE.md - ModelCar Project
542
+
543
+ This file provides guidance to Claude Code when working with this ModelCar project.
544
+
545
+ ## Project Overview
546
+
547
+ This is a **ModelCar** project for packaging the **{model_name}** model from HuggingFace
548
+ into a container image for deployment on OpenShift AI.
549
+
550
+ ## Source Information
551
+
552
+ - **HuggingFace Repository:** [{hf_repo_id}](https://huggingface.co/{hf_repo_id})
553
+ - **Container Registry:** `{quay_uri}`
554
+
555
+ ## Important Notes
556
+
557
+ 1. **This is a temporary workspace** - do NOT commit model files to git
558
+ 2. **Source of truth:** The HuggingFace repository
559
+ 3. **Delete after use:** This directory should be deleted after pushing to registry
560
+
561
+ ## Workflow
562
+
563
+ 1. **Download:** `./download.sh` - Downloads model from HuggingFace
564
+ 2. **Build & Push:** `./build-and-push.sh` - Creates and pushes container image
565
+ 3. **Cleanup:** Delete this directory after successful push
566
+
567
+ ## Files
568
+
569
+ | File | Purpose |
570
+ |------|---------|
571
+ | `download.sh` | Downloads model from HuggingFace |
572
+ | `build-and-push.sh` | Builds container and pushes to registry |
573
+ | `cleanup.sh` | Deletes local model files |
574
+ | `cleanup-old-images.sh` | Removes old ModelCar images from Podman |
575
+ | `Containerfile` | Container build instructions |
576
+
577
+ ## OpenShift AI Deployment
578
+
579
+ Deploy using:
580
+ - **Runtime:** vLLM ServingRuntime
581
+ - **Source type:** OCI - v1
582
+ - **URI:** `oci://{quay_uri}`
583
+
584
+ ## Generation Info
585
+
586
+ This project was generated using `fips-agents create model-car`.
587
+ See `.fips-agents-cli/info.json` for full generation metadata.
588
+ """
589
+
590
+
539
591
  def write_modelcar_info(
540
592
  project_path,
541
593
  hf_repo_id: str,
542
594
  quay_uri: str,
543
595
  project_name: str,
596
+ model_name: str,
544
597
  ) -> None:
545
598
  """
546
- Write ModelCar generation metadata to .template-info file.
599
+ Write ModelCar generation metadata to .fips-agents-cli directory.
600
+
601
+ Creates:
602
+ - .fips-agents-cli/info.json - Generation metadata
603
+ - .fips-agents-cli/CLAUDE.md - Claude Code instructions
547
604
 
548
605
  Args:
549
606
  project_path: Path to the project root directory
550
607
  hf_repo_id: HuggingFace repository ID (e.g., openai/gpt-oss-20b)
551
608
  quay_uri: Full Quay container registry URI with tag
552
609
  project_name: Name of the generated project directory
610
+ model_name: Display name of the model
553
611
  """
554
612
  try:
613
+ # Create .fips-agents-cli directory
614
+ fips_dir = project_path / ".fips-agents-cli"
615
+ fips_dir.mkdir(parents=True, exist_ok=True)
616
+
617
+ # Write info.json
555
618
  modelcar_info = {
556
619
  "generator": {
557
620
  "tool": "fips-agents-cli",
@@ -574,12 +637,18 @@ def write_modelcar_info(
574
637
  },
575
638
  }
576
639
 
577
- info_file = project_path / ".template-info"
640
+ info_file = fips_dir / "info.json"
578
641
  with open(info_file, "w") as f:
579
642
  json.dump(modelcar_info, f, indent=2)
580
643
  f.write("\n") # Add trailing newline
581
644
 
582
- console.print("[green]✓[/green] Created project metadata file")
645
+ # Write CLAUDE.md
646
+ claude_md_file = fips_dir / "CLAUDE.md"
647
+ claude_md_content = generate_modelcar_claude_md(hf_repo_id, model_name, quay_uri)
648
+ with open(claude_md_file, "w") as f:
649
+ f.write(claude_md_content)
650
+
651
+ console.print("[green]✓[/green] Created .fips-agents-cli/ with project metadata")
583
652
 
584
653
  except Exception as e:
585
654
  # Don't fail the entire operation if this fails
@@ -713,8 +782,8 @@ print("Next step: Run ./build-and-push.sh to build and push the container")
713
782
 
714
783
  console.print(f" [green]✓[/green] Created {filename}")
715
784
 
716
- # Write project metadata
717
- write_modelcar_info(target_path, hf_repo_id, quay_uri, project_name)
785
+ # Write project metadata to .fips-agents-cli directory
786
+ write_modelcar_info(target_path, hf_repo_id, quay_uri, project_name, model_name)
718
787
 
719
788
  # Step 8: Success message with instructions
720
789
  success_message = f"""
@@ -119,6 +119,21 @@ def docs(dry_run: bool):
119
119
  _patch_category("docs", dry_run)
120
120
 
121
121
 
122
+ @patch.command("build")
123
+ @click.option(
124
+ "--dry-run",
125
+ is_flag=True,
126
+ help="Show what would be updated without making changes",
127
+ )
128
+ def build(dry_run: bool):
129
+ """
130
+ Update build and deployment files (Makefile, Containerfile, etc).
131
+
132
+ Shows diffs and asks for confirmation before applying changes.
133
+ """
134
+ _patch_category("build", dry_run)
135
+
136
+
122
137
  @patch.command("all")
123
138
  @click.option(
124
139
  "--dry-run",