mapify-cli 3.8.0__tar.gz → 3.9.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 (103) hide show
  1. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/PKG-INFO +1 -1
  2. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/pyproject.toml +1 -1
  3. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/__init__.py +270 -200
  4. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/cli_ui.py +1 -1
  5. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/delivery/__init__.py +4 -0
  6. mapify_cli-3.9.0/src/mapify_cli/delivery/codex_copier.py +167 -0
  7. mapify_cli-3.9.0/src/mapify_cli/delivery/providers.py +89 -0
  8. mapify_cli-3.9.0/src/mapify_cli/templates/codex/AGENTS.md +38 -0
  9. mapify_cli-3.9.0/src/mapify_cli/templates/codex/agents/decomposer.toml +832 -0
  10. mapify_cli-3.9.0/src/mapify_cli/templates/codex/agents/monitor.toml +1135 -0
  11. mapify_cli-3.9.0/src/mapify_cli/templates/codex/agents/researcher.toml +74 -0
  12. mapify_cli-3.9.0/src/mapify_cli/templates/codex/config.toml +17 -0
  13. {mapify_cli-3.8.0/src/mapify_cli/templates → mapify_cli-3.9.0/src/mapify_cli/templates/codex}/hooks/workflow-gate.py +21 -3
  14. mapify_cli-3.9.0/src/mapify_cli/templates/codex/hooks.json +16 -0
  15. mapify_cli-3.9.0/src/mapify_cli/templates/codex/skills/map-check/SKILL.md +21 -0
  16. mapify_cli-3.9.0/src/mapify_cli/templates/codex/skills/map-fast/SKILL.md +22 -0
  17. mapify_cli-3.9.0/src/mapify_cli/templates/codex/skills/map-plan/SKILL.md +624 -0
  18. mapify_cli-3.9.0/src/mapify_cli/templates/hooks/workflow-gate.py +291 -0
  19. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/.claude/skills/README.md +0 -0
  20. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/.gitignore +0 -0
  21. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/README.md +0 -0
  22. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/config/__init__.py +0 -0
  23. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/config/mcp.py +0 -0
  24. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/config/project_config.py +0 -0
  25. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/config/settings.py +0 -0
  26. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/delivery/agent_generator.py +0 -0
  27. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/delivery/file_copier.py +0 -0
  28. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/delivery/managed_file_copier.py +0 -0
  29. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/dependency_graph.py +0 -0
  30. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/intent_detector.py +0 -0
  31. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/ralph_state.py +0 -0
  32. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/repo_insight.py +0 -0
  33. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/schemas.py +0 -0
  34. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/CLAUDE.md +0 -0
  35. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/actor.md +0 -0
  36. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/debate-arbiter.md +0 -0
  37. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/documentation-reviewer.md +0 -0
  38. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/evaluator.md +0 -0
  39. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/final-verifier.md +0 -0
  40. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/monitor.md +0 -0
  41. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/predictor.md +0 -0
  42. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/reflector.md +0 -0
  43. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/research-agent.md +0 -0
  44. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/synthesizer.md +0 -0
  45. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/agents/task-decomposer.md +0 -0
  46. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-check.md +0 -0
  47. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-debug.md +0 -0
  48. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-efficient.md +0 -0
  49. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-fast.md +0 -0
  50. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-plan.md +0 -0
  51. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-release.md +0 -0
  52. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-resume.md +0 -0
  53. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-review.md +0 -0
  54. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-task.md +0 -0
  55. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/commands/map-tdd.md +0 -0
  56. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/hooks/end-of-turn.sh +0 -0
  57. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/hooks/post-compact-context.py +0 -0
  58. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/hooks/pre-compact-save-transcript.py +0 -0
  59. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/hooks/ralph-context-pruner.py +0 -0
  60. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/hooks/ralph-iteration-logger.py +0 -0
  61. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/hooks/safety-guardrails.py +0 -0
  62. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/hooks/workflow-context-injector.py +0 -0
  63. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/scripts/diagnostics.py +0 -0
  64. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/scripts/map_orchestrator.py +0 -0
  65. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/scripts/map_step_runner.py +0 -0
  66. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/scripts/map_utils.py +0 -0
  67. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/static-analysis/analyze.sh +0 -0
  68. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/static-analysis/handlers/common.sh +0 -0
  69. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/static-analysis/handlers/go.sh +0 -0
  70. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/static-analysis/handlers/python.sh +0 -0
  71. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/static-analysis/handlers/rust.sh +0 -0
  72. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/map/static-analysis/handlers/typescript.sh +0 -0
  73. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/ralph-loop-config.json +0 -0
  74. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/references/bash-guidelines.md +0 -0
  75. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/references/decomposition-examples.md +0 -0
  76. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/references/escalation-matrix.md +0 -0
  77. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/references/mcp-usage-examples.md +0 -0
  78. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/references/step-state-schema.md +0 -0
  79. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/references/workflow-state-schema.md +0 -0
  80. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/rules/learned/README.md +0 -0
  81. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/settings.json +0 -0
  82. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/README.md +0 -0
  83. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-learn/SKILL.md +0 -0
  84. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-learn/templates/example-rules.md +0 -0
  85. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-learn/templates/rules-unconditional.md +0 -0
  86. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-learn/templates/rules-with-paths.md +0 -0
  87. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/SKILL.md +0 -0
  88. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/scripts/check-complete.sh +0 -0
  89. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/scripts/get-plan-path.sh +0 -0
  90. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/scripts/init-session.sh +0 -0
  91. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/scripts/show-focus.sh +0 -0
  92. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/templates/findings.md +0 -0
  93. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/templates/iteration_history.md +0 -0
  94. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/templates/progress.md +0 -0
  95. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/map-planning/templates/task_plan.md +0 -0
  96. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/skills/skill-rules.json +0 -0
  97. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/templates/workflow-rules.json +0 -0
  98. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/tools/__init__.py +0 -0
  99. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/tools/validate_dependencies.py +0 -0
  100. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/verification_recorder.py +0 -0
  101. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/workflow_finalizer.py +0 -0
  102. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/workflow_logger.py +0 -0
  103. {mapify_cli-3.8.0 → mapify_cli-3.9.0}/src/mapify_cli/workflow_state.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: mapify-cli
3
- Version: 3.8.0
3
+ Version: 3.9.0
4
4
  Summary: MAP Framework installer - Modular Agentic Planner for Claude Code
5
5
  Project-URL: Homepage, https://github.com/azalio/map-framework
6
6
  Project-URL: Repository, https://github.com/azalio/map-framework.git
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "mapify-cli"
3
- version = "3.8.0"
3
+ version = "3.9.0"
4
4
  description = "MAP Framework installer - Modular Agentic Planner for Claude Code"
5
5
  authors = [{ name = "MAP Framework Contributors" }]
6
6
  readme = "README.md"
@@ -23,7 +23,7 @@ Or install globally:
23
23
  mapify check
24
24
  """
25
25
 
26
- __version__ = "3.8.0"
26
+ __version__ = "3.9.0"
27
27
 
28
28
  import os
29
29
  import subprocess
@@ -76,8 +76,6 @@ from mapify_cli.delivery import (
76
76
  create_hook_files,
77
77
  create_config_files,
78
78
  create_commands_dir as create_commands_dir,
79
- create_map_tools,
80
- create_rules_dir,
81
79
  )
82
80
  from mapify_cli.config import (
83
81
  configure_global_permissions,
@@ -265,14 +263,28 @@ def count_project_markdown_files(
265
263
 
266
264
 
267
265
  def is_map_initialized(project_path: Path) -> bool:
268
- """Return True when the current directory looks like a MAP project."""
269
- required_paths = [
266
+ """Return True when the current directory looks like a MAP project.
267
+
268
+ Recognises both Claude Code layout (.claude/) and Codex layout (.codex/).
269
+ """
270
+ claude_paths = [
270
271
  project_path / ".claude" / "agents",
271
272
  project_path / ".claude" / "commands",
272
273
  project_path / ".claude" / "settings.json",
273
274
  project_path / ".claude" / "workflow-rules.json",
274
275
  ]
275
- return all(path.exists() for path in required_paths)
276
+ codex_paths = [
277
+ project_path / ".codex" / "config.toml",
278
+ project_path / ".codex" / "skills",
279
+ ]
280
+ return all(p.exists() for p in claude_paths) or all(p.exists() for p in codex_paths)
281
+
282
+
283
+ def _detect_provider(project_path: Path) -> str:
284
+ """Detect which provider was used to initialise this project."""
285
+ if (project_path / ".codex" / "config.toml").exists():
286
+ return "codex"
287
+ return "claude"
276
288
 
277
289
 
278
290
  def get_project_health(project_path: Path) -> Dict[str, Any]:
@@ -280,13 +292,25 @@ def get_project_health(project_path: Path) -> Dict[str, Any]:
280
292
  agent_exclude = {"README.md", "CHANGELOG.md", "MCP-PATTERNS.md"}
281
293
  current_branch = sanitize_identifier(get_current_branch_name())
282
294
  branch_dir = project_path / ".map" / current_branch
283
- required_paths = {
284
- ".claude/agents": project_path / ".claude" / "agents",
285
- ".claude/commands": project_path / ".claude" / "commands",
286
- ".claude/settings.json": project_path / ".claude" / "settings.json",
287
- ".claude/workflow-rules.json": project_path / ".claude" / "workflow-rules.json",
288
- ".map/scripts": project_path / ".map" / "scripts",
289
- }
295
+ detected = _detect_provider(project_path)
296
+
297
+ if detected == "codex":
298
+ required_paths = {
299
+ ".codex/config.toml": project_path / ".codex" / "config.toml",
300
+ ".codex/skills": project_path / ".codex" / "skills",
301
+ ".codex/agents": project_path / ".codex" / "agents",
302
+ ".map/scripts": project_path / ".map" / "scripts",
303
+ }
304
+ else:
305
+ required_paths = {
306
+ ".claude/agents": project_path / ".claude" / "agents",
307
+ ".claude/commands": project_path / ".claude" / "commands",
308
+ ".claude/settings.json": project_path / ".claude" / "settings.json",
309
+ ".claude/workflow-rules.json": project_path
310
+ / ".claude"
311
+ / "workflow-rules.json",
312
+ ".map/scripts": project_path / ".map" / "scripts",
313
+ }
290
314
  missing_paths = [name for name, path in required_paths.items() if not path.exists()]
291
315
 
292
316
  agents_dir = project_path / ".claude" / "agents"
@@ -617,6 +641,11 @@ def init(
617
641
  debug: bool = typer.Option(
618
642
  False, "--debug", help="Enable debug logging (creates .map/logs/workflow_*.log)"
619
643
  ),
644
+ provider: str = typer.Option(
645
+ "claude",
646
+ "--provider",
647
+ help="Delivery provider: claude (default) or codex",
648
+ ),
620
649
  ):
621
650
  """
622
651
  Initialize a new MAP Framework project.
@@ -656,6 +685,15 @@ def init(
656
685
  metadata={"debug": debug, "mcp": mcp},
657
686
  )
658
687
 
688
+ # Validate provider
689
+ valid_providers = ("claude", "codex")
690
+ if provider not in valid_providers:
691
+ console.print(
692
+ f"[red]Error:[/red] Invalid provider '{provider}'. "
693
+ f"Valid providers: {', '.join(valid_providers)}"
694
+ )
695
+ raise typer.Exit(1)
696
+
659
697
  # Handle '.' as shorthand for current directory
660
698
  use_current_dir = project_name == "."
661
699
 
@@ -707,122 +745,110 @@ def init(
707
745
  tracker.start("check-tools")
708
746
 
709
747
  git_available = check_tool("git")
710
- claude_available = check_tool("claude")
711
748
 
712
- if claude_available:
713
- tracker.complete("check-tools", "git, claude")
714
- elif git_available:
715
- tracker.complete("check-tools", "git")
749
+ if provider == "codex":
750
+ codex_available = check_tool("codex")
751
+ if codex_available:
752
+ tracker.complete("check-tools", "git, codex" if git_available else "codex")
753
+ elif git_available:
754
+ tracker.complete("check-tools", "git")
755
+ else:
756
+ tracker.complete("check-tools", "minimal")
716
757
  else:
717
- tracker.complete("check-tools", "minimal")
758
+ claude_available = check_tool("claude")
759
+ if claude_available:
760
+ tracker.complete("check-tools", "git, claude")
761
+ elif git_available:
762
+ tracker.complete("check-tools", "git")
763
+ else:
764
+ tracker.complete("check-tools", "minimal")
718
765
 
719
- # Use Claude Code (the only supported AI assistant)
720
- tracker.add("ai-select", "Select AI assistant")
721
- selected_ai = "claude"
766
+ # Select provider
767
+ tracker.add("ai-select", "Select provider")
768
+ selected_ai = provider
722
769
  tracker.complete("ai-select", selected_ai)
723
770
 
724
- # Select MCP servers
725
- tracker.add("mcp-select", "Select MCP servers")
726
- tracker.start("mcp-select")
727
-
771
+ # Select MCP servers (Claude only — Codex uses TOML agent config)
728
772
  selected_mcp_servers = []
729
773
 
730
- if mcp == "all":
731
- selected_mcp_servers = list(INDIVIDUAL_MCP_SERVERS.keys())
732
- elif mcp == "essential":
733
- selected_mcp_servers = ["sequential-thinking", "deepwiki"]
734
- elif mcp == "none":
735
- selected_mcp_servers = []
736
- else:
737
- # Parse comma-separated list
738
- requested = [s.strip() for s in mcp.split(",") if s.strip()]
739
- invalid = [s for s in requested if s not in INDIVIDUAL_MCP_SERVERS]
740
- if invalid:
741
- console.print(
742
- f"[yellow]Warning:[/yellow] Unrecognized MCP servers ignored: {', '.join(invalid)}"
743
- )
744
- console.print(f"Valid servers: {', '.join(INDIVIDUAL_MCP_SERVERS.keys())}")
745
- selected_mcp_servers = [s for s in requested if s in INDIVIDUAL_MCP_SERVERS]
746
-
747
- tracker.complete("mcp-select", f"{len(selected_mcp_servers)} servers")
748
-
749
- # Create MAP files
750
- tracker.add("create-agents", "Create MAP agents")
751
- tracker.start("create-agents")
752
- agent_count = create_agent_files(project_path, selected_mcp_servers)
753
- agent_word = "agent" if agent_count == 1 else "agents"
754
- tracker.complete("create-agents", f"{agent_count} {agent_word}")
755
-
756
- tracker.add("create-commands", "Create slash commands")
757
- tracker.start("create-commands")
758
- command_count = create_command_files(project_path)
759
- command_word = "command" if command_count == 1 else "commands"
760
- tracker.complete("create-commands", f"{command_count} {command_word}")
761
-
762
- tracker.add("create-skills", "Create skills")
763
- tracker.start("create-skills")
764
- skill_count = create_skill_files(project_path)
765
- skill_word = "skill" if skill_count == 1 else "skills"
766
- tracker.complete("create-skills", f"{skill_count} {skill_word}")
767
-
768
- tracker.add("create-references", "Create reference files")
769
- tracker.start("create-references")
770
- ref_count = create_reference_files(project_path)
771
- ref_word = "file" if ref_count == 1 else "files"
772
- tracker.complete("create-references", f"{ref_count} {ref_word}")
773
-
774
- tracker.add("create-map-tools", "Create MAP tools")
775
- tracker.start("create-map-tools")
776
- tool_count = create_map_tools(project_path)
777
- tool_word = "script" if tool_count == 1 else "scripts"
778
- tracker.complete("create-map-tools", f"{tool_count} {tool_word}")
779
-
780
- tracker.add("create-hooks", "Create MAP hooks")
781
- tracker.start("create-hooks")
782
- hook_count = create_hook_files(project_path)
783
- hook_word = "hook" if hook_count == 1 else "hooks"
784
- tracker.complete("create-hooks", f"{hook_count} {hook_word}")
785
-
786
- tracker.add("create-configs", "Create config files")
787
- tracker.start("create-configs")
788
- config_count = create_config_files(project_path)
789
- config_word = "file" if config_count == 1 else "files"
790
- tracker.complete("create-configs", f"{config_count} {config_word}")
791
-
792
- # Create default .map/config.yaml (project-level settings)
793
- tracker.add("map-config", "Create .map/config.yaml")
794
- tracker.start("map-config")
795
- try:
796
- from mapify_cli.config.project_config import write_default_config
797
-
798
- config_path = write_default_config(project_path)
799
- tracker.complete("map-config", str(config_path.relative_to(project_path)))
800
- except Exception as e:
801
- tracker.error("map-config", f"skipped: {e}")
802
-
803
- # Create .claude/rules/learned/ directory for /map-learn persistence
804
- tracker.add("rules-dir", "Create learned rules directory")
805
- tracker.start("rules-dir")
806
- rules_count = create_rules_dir(project_path)
807
- tracker.complete(
808
- "rules-dir",
809
- f"{rules_count} file" if rules_count <= 1 else f"{rules_count} files",
810
- )
774
+ if provider != "codex":
775
+ tracker.add("mcp-select", "Select MCP servers")
776
+ tracker.start("mcp-select")
777
+
778
+ if mcp == "all":
779
+ selected_mcp_servers = list(INDIVIDUAL_MCP_SERVERS.keys())
780
+ elif mcp == "essential":
781
+ selected_mcp_servers = ["sequential-thinking", "deepwiki"]
782
+ elif mcp == "none":
783
+ selected_mcp_servers = []
784
+ else:
785
+ # Parse comma-separated list
786
+ requested = [s.strip() for s in mcp.split(",") if s.strip()]
787
+ invalid = [s for s in requested if s not in INDIVIDUAL_MCP_SERVERS]
788
+ if invalid:
789
+ console.print(
790
+ f"[yellow]Warning:[/yellow] Unrecognized MCP servers ignored: {', '.join(invalid)}"
791
+ )
792
+ console.print(
793
+ f"Valid servers: {', '.join(INDIVIDUAL_MCP_SERVERS.keys())}"
794
+ )
795
+ selected_mcp_servers = [s for s in requested if s in INDIVIDUAL_MCP_SERVERS]
811
796
 
812
- if selected_mcp_servers:
813
- # Create internal MCP config (for MAP Framework agent mappings)
814
- tracker.add("mcp-config", "Create internal MCP config")
815
- tracker.start("mcp-config")
816
- create_mcp_config(project_path, selected_mcp_servers)
817
- tracker.complete("mcp-config", f"{len(selected_mcp_servers)} servers")
797
+ tracker.complete("mcp-select", f"{len(selected_mcp_servers)} servers")
818
798
 
819
- # Create/merge project .mcp.json (for Claude Code MCP server registration)
820
- tracker.add("mcp-project", "Create/merge .mcp.json")
821
- tracker.start("mcp-project")
822
- create_or_merge_project_mcp_json(project_path, selected_mcp_servers)
823
- tracker.complete("mcp-project", "Claude Code MCP config")
799
+ if provider == "codex":
800
+ # Codex provider: install .codex/ files + .map/scripts/ (skip-if-exists)
801
+ from mapify_cli.delivery.providers import CodexProvider
824
802
 
825
- # Initialize git
803
+ tracker.add("create-codex", "Create Codex files")
804
+ tracker.start("create-codex")
805
+ codex_provider = CodexProvider()
806
+ counts = codex_provider.install(project_path)
807
+ total = sum(counts.values())
808
+ tracker.complete("create-codex", f"{total} files")
809
+ else:
810
+ # Claude provider: use ClaudeProvider abstraction
811
+ from mapify_cli.delivery.providers import ClaudeProvider
812
+
813
+ tracker.add("create-claude", "Create Claude Code files")
814
+ tracker.start("create-claude")
815
+ claude_provider = ClaudeProvider()
816
+ claude_counts = claude_provider.install(
817
+ project_path, mcp_servers=selected_mcp_servers
818
+ )
819
+ total_claude = sum(claude_counts.values())
820
+ tracker.complete("create-claude", f"{total_claude} files")
821
+
822
+ # Create default .map/config.yaml (project-level settings)
823
+ tracker.add("map-config", "Create .map/config.yaml")
824
+ tracker.start("map-config")
825
+ try:
826
+ from mapify_cli.config.project_config import write_default_config
827
+
828
+ config_path = write_default_config(project_path)
829
+ tracker.complete("map-config", str(config_path.relative_to(project_path)))
830
+ except Exception as e:
831
+ tracker.error("map-config", f"skipped: {e}")
832
+
833
+ if selected_mcp_servers:
834
+ # Create internal MCP config (for MAP Framework agent mappings)
835
+ tracker.add("mcp-config", "Create internal MCP config")
836
+ tracker.start("mcp-config")
837
+ create_mcp_config(project_path, selected_mcp_servers)
838
+ tracker.complete("mcp-config", f"{len(selected_mcp_servers)} servers")
839
+
840
+ # Create/merge project .mcp.json (for Claude Code MCP server registration)
841
+ tracker.add("mcp-project", "Create/merge .mcp.json")
842
+ tracker.start("mcp-project")
843
+ create_or_merge_project_mcp_json(project_path, selected_mcp_servers)
844
+ tracker.complete("mcp-project", "Claude Code MCP config")
845
+
846
+ tracker.add("project-permissions", "Configure project approvals")
847
+ tracker.start("project-permissions")
848
+ create_or_merge_project_settings_local(project_path)
849
+ tracker.complete("project-permissions", ".claude/settings.local.json")
850
+
851
+ # Initialize git (shared, provider-agnostic)
826
852
  if not no_git and git_available:
827
853
  tracker.add("git", "Initialize git repository")
828
854
  tracker.start("git")
@@ -834,17 +860,13 @@ def init(
834
860
  else:
835
861
  tracker.error("git", "failed")
836
862
 
837
- tracker.add("project-permissions", "Configure project approvals")
838
- tracker.start("project-permissions")
839
- create_or_merge_project_settings_local(project_path)
840
- tracker.complete("project-permissions", ".claude/settings.local.json")
841
-
842
863
  tracker.add("finalize", "Finalize")
843
864
  tracker.complete("finalize", "project ready")
844
865
 
845
- # Configure global permissions for read-only commands
846
- console.print() # Add spacing
847
- configure_global_permissions()
866
+ # Configure global permissions for read-only commands (Claude only)
867
+ if provider != "codex":
868
+ console.print() # Add spacing
869
+ configure_global_permissions()
848
870
 
849
871
  # Show final tree
850
872
  with Live(tracker.render(), console=console, transient=True) as live:
@@ -864,20 +886,31 @@ def init(
864
886
  steps_lines.append("1. You're already in the project directory!")
865
887
  step_num = 2
866
888
 
867
- steps_lines.append(f"{step_num}. Start using MAP commands with Claude Code:")
868
- steps_lines.append(
869
- " • [cyan]/map-efficient[/] - Implement features with optimized workflow (recommended)"
870
- )
871
- steps_lines.append(" • [cyan]/map-debug[/] - Debug issue using MAP analysis")
872
- steps_lines.append(
873
- " • [cyan]/map-fast[/] - Quick implementation with minimal validation"
874
- )
875
- steps_lines.append(
876
- " • [cyan]/map-learn[/] - Extract lessons from completed workflows"
877
- )
878
- steps_lines.append(
879
- f"{step_num + 1}. Run [cyan]/map-plan[/cyan] first when you want branch-scoped research, spec, and plan artifacts in `.map/<branch>/`"
880
- )
889
+ if provider == "codex":
890
+ steps_lines.append(f"{step_num}. Start using MAP skills with Codex:")
891
+ steps_lines.append(" • [cyan]$map-plan[/] - Plan and decompose complex tasks")
892
+ steps_lines.append(
893
+ " • [cyan]$map-fast[/] - Quick implementation with minimal validation"
894
+ )
895
+ steps_lines.append(" • [cyan]$map-check[/] - Quality gates and verification")
896
+ steps_lines.append(
897
+ f"{step_num + 1}. Trust this project in Codex settings for .codex/ config to take effect"
898
+ )
899
+ else:
900
+ steps_lines.append(f"{step_num}. Start using MAP commands with Claude Code:")
901
+ steps_lines.append(
902
+ " • [cyan]/map-efficient[/] - Implement features with optimized workflow (recommended)"
903
+ )
904
+ steps_lines.append(" • [cyan]/map-debug[/] - Debug issue using MAP analysis")
905
+ steps_lines.append(
906
+ " • [cyan]/map-fast[/] - Quick implementation with minimal validation"
907
+ )
908
+ steps_lines.append(
909
+ " • [cyan]/map-learn[/] - Extract lessons from completed workflows"
910
+ )
911
+ steps_lines.append(
912
+ f"{step_num + 1}. Run [cyan]/map-plan[/cyan] first when you want branch-scoped research, spec, and plan artifacts in `.map/<branch>/`"
913
+ )
881
914
 
882
915
  steps_panel = Panel(
883
916
  "\n".join(steps_lines), title="Next Steps", border_style="cyan", padding=(1, 2)
@@ -906,10 +939,17 @@ def check(debug: bool = typer.Option(False, "--debug", help="Enable debug loggin
906
939
 
907
940
  tracker = StepTracker("Check Available Tools")
908
941
 
909
- tools = [
910
- ("git", "Git version control"),
911
- ("claude", "Claude Code CLI"),
912
- ]
942
+ detected = _detect_provider(Path.cwd())
943
+ if detected == "codex":
944
+ tools = [
945
+ ("git", "Git version control"),
946
+ ("codex", "Codex CLI"),
947
+ ]
948
+ else:
949
+ tools = [
950
+ ("git", "Git version control"),
951
+ ("claude", "Claude Code CLI"),
952
+ ]
913
953
 
914
954
  # Add tools to tracker
915
955
  for tool, description in tools:
@@ -929,7 +969,7 @@ def check(debug: bool = typer.Option(False, "--debug", help="Enable debug loggin
929
969
 
930
970
  tracker.add("project", "Detect MAP project")
931
971
  if health["initialized"]:
932
- tracker.complete("project", "initialized")
972
+ tracker.complete("project", f"initialized ({detected} provider)")
933
973
  else:
934
974
  tracker.error("project", "not initialized")
935
975
 
@@ -942,9 +982,10 @@ def check(debug: bool = typer.Option(False, "--debug", help="Enable debug loggin
942
982
  else:
943
983
  tracker.error("templates", "missing bundled templates")
944
984
 
945
- tracker.add("mcp", "Check supported MCP servers")
946
- supported_servers = sorted(build_standard_mcp_servers().keys())
947
- tracker.complete("mcp", ", ".join(supported_servers) or "none")
985
+ if detected != "codex":
986
+ tracker.add("mcp", "Check supported MCP servers")
987
+ supported_servers = sorted(build_standard_mcp_servers().keys())
988
+ tracker.complete("mcp", ", ".join(supported_servers) or "none")
948
989
 
949
990
  console.print(tracker.render())
950
991
  console.print()
@@ -957,7 +998,9 @@ def check(debug: bool = typer.Option(False, "--debug", help="Enable debug loggin
957
998
  console.print("[yellow]MAP environment needs attention:[/yellow]")
958
999
  if not results.get("git"):
959
1000
  console.print(" • Install git: https://git-scm.com/downloads")
960
- if not results.get("claude"):
1001
+ if detected == "codex" and not results.get("codex"):
1002
+ console.print(" • Install Codex CLI: https://github.com/openai/codex")
1003
+ elif not results.get("claude"):
961
1004
  console.print(
962
1005
  " • Install Claude Code: https://docs.anthropic.com/en/docs/claude-code/setup"
963
1006
  )
@@ -984,13 +1027,16 @@ def doctor(debug: bool = typer.Option(False, "--debug", help="Enable debug loggi
984
1027
  console.print("[bold]Running MAP doctor...[/bold]\n")
985
1028
 
986
1029
  project_path = Path.cwd()
1030
+ detected = _detect_provider(project_path)
987
1031
  health = get_project_health(project_path)
988
1032
  tracker = StepTracker("MAP Doctor")
989
1033
 
990
- for tool_name, description in [
991
- ("git", "Git version control"),
992
- ("claude", "Claude Code CLI"),
993
- ]:
1034
+ if detected == "codex":
1035
+ tool_list = [("git", "Git version control"), ("codex", "Codex CLI")]
1036
+ else:
1037
+ tool_list = [("git", "Git version control"), ("claude", "Claude Code CLI")]
1038
+
1039
+ for tool_name, description in tool_list:
994
1040
  tracker.add(tool_name, description)
995
1041
  if check_tool(tool_name):
996
1042
  tracker.complete(tool_name, "available")
@@ -998,27 +1044,41 @@ def doctor(debug: bool = typer.Option(False, "--debug", help="Enable debug loggi
998
1044
  tracker.error(tool_name, "not found")
999
1045
 
1000
1046
  tracker.add("project", "MAP project structure")
1001
- if not health["missing_paths"]:
1047
+ if detected == "codex":
1048
+ codex_dir = project_path / ".codex"
1049
+ codex_checks = {
1050
+ ".codex/config.toml": codex_dir / "config.toml",
1051
+ ".codex/skills": codex_dir / "skills",
1052
+ ".codex/agents": codex_dir / "agents",
1053
+ ".map/scripts": project_path / ".map" / "scripts",
1054
+ }
1055
+ codex_missing = [n for n, p in codex_checks.items() if not p.exists()]
1056
+ if not codex_missing:
1057
+ tracker.complete("project", "all core paths present (codex)")
1058
+ else:
1059
+ tracker.error("project", f"missing {len(codex_missing)} path(s)")
1060
+ elif not health["missing_paths"]:
1002
1061
  tracker.complete("project", "all core paths present")
1003
1062
  else:
1004
1063
  tracker.error("project", f"missing {len(health['missing_paths'])} path(s)")
1005
1064
 
1006
- tracker.add("templates", "Installed template counts")
1007
- if (
1008
- health["installed_agents"] == health["expected_agents"]
1009
- and health["installed_commands"] == health["expected_commands"]
1010
- ):
1011
- tracker.complete(
1012
- "templates",
1013
- f"{health['installed_agents']}/{health['expected_agents']} agents, "
1014
- f"{health['installed_commands']}/{health['expected_commands']} commands",
1015
- )
1016
- else:
1017
- tracker.error(
1018
- "templates",
1019
- f"agents {health['installed_agents']}/{health['expected_agents']}, "
1020
- f"commands {health['installed_commands']}/{health['expected_commands']}",
1021
- )
1065
+ if detected != "codex":
1066
+ tracker.add("templates", "Installed template counts")
1067
+ if (
1068
+ health["installed_agents"] == health["expected_agents"]
1069
+ and health["installed_commands"] == health["expected_commands"]
1070
+ ):
1071
+ tracker.complete(
1072
+ "templates",
1073
+ f"{health['installed_agents']}/{health['expected_agents']} agents, "
1074
+ f"{health['installed_commands']}/{health['expected_commands']} commands",
1075
+ )
1076
+ else:
1077
+ tracker.error(
1078
+ "templates",
1079
+ f"agents {health['installed_agents']}/{health['expected_agents']}, "
1080
+ f"commands {health['installed_commands']}/{health['expected_commands']}",
1081
+ )
1022
1082
 
1023
1083
  tracker.add("planning", "Branch workspace artifacts")
1024
1084
  if health["branch_workspace_exists"]:
@@ -1029,16 +1089,17 @@ def doctor(debug: bool = typer.Option(False, "--debug", help="Enable debug loggi
1029
1089
  else:
1030
1090
  tracker.error("planning", f"missing .map/{health['current_branch']}")
1031
1091
 
1032
- tracker.add("mcp", "Project MCP configuration")
1033
- if health["has_project_mcp"]:
1034
- if health["project_mcp_valid"]:
1035
- tracker.complete("mcp", ".mcp.json valid")
1092
+ if detected != "codex":
1093
+ tracker.add("mcp", "Project MCP configuration")
1094
+ if health["has_project_mcp"]:
1095
+ if health["project_mcp_valid"]:
1096
+ tracker.complete("mcp", ".mcp.json valid")
1097
+ else:
1098
+ tracker.error("mcp", ".mcp.json unreadable")
1099
+ elif health["has_internal_mcp"]:
1100
+ tracker.complete("mcp", "internal config only")
1036
1101
  else:
1037
- tracker.error("mcp", ".mcp.json unreadable")
1038
- elif health["has_internal_mcp"]:
1039
- tracker.complete("mcp", "internal config only")
1040
- else:
1041
- tracker.complete("mcp", "no MCP config")
1102
+ tracker.complete("mcp", "no MCP config")
1042
1103
 
1043
1104
  console.print(tracker.render())
1044
1105
  console.print()
@@ -1051,21 +1112,22 @@ def doctor(debug: bool = typer.Option(False, "--debug", help="Enable debug loggi
1051
1112
  "Project",
1052
1113
  "OK" if health["initialized"] else "Needs init",
1053
1114
  (
1054
- ".claude + workflow configs detected"
1115
+ f".{detected} + workflow configs detected"
1055
1116
  if health["initialized"]
1056
1117
  else "Run `mapify init .`"
1057
1118
  ),
1058
1119
  )
1059
- details.add_row(
1060
- "Agents",
1061
- f"{health['installed_agents']}/{health['expected_agents']}",
1062
- "Installed vs bundled agent templates",
1063
- )
1064
- details.add_row(
1065
- "Commands",
1066
- f"{health['installed_commands']}/{health['expected_commands']}",
1067
- "Installed vs bundled slash commands",
1068
- )
1120
+ if detected != "codex":
1121
+ details.add_row(
1122
+ "Agents",
1123
+ f"{health['installed_agents']}/{health['expected_agents']}",
1124
+ "Installed vs bundled agent templates",
1125
+ )
1126
+ details.add_row(
1127
+ "Commands",
1128
+ f"{health['installed_commands']}/{health['expected_commands']}",
1129
+ "Installed vs bundled slash commands",
1130
+ )
1069
1131
  details.add_row(
1070
1132
  "Planning",
1071
1133
  (
@@ -1075,15 +1137,16 @@ def doctor(debug: bool = typer.Option(False, "--debug", help="Enable debug loggi
1075
1137
  ),
1076
1138
  f"Current branch workspace: .map/{health['current_branch']}/",
1077
1139
  )
1078
- details.add_row(
1079
- "MCP",
1080
- (
1081
- "valid"
1082
- if health["project_mcp_valid"]
1083
- else ("present" if health["has_project_mcp"] else "not configured")
1084
- ),
1085
- ".mcp.json status",
1086
- )
1140
+ if detected != "codex":
1141
+ details.add_row(
1142
+ "MCP",
1143
+ (
1144
+ "valid"
1145
+ if health["project_mcp_valid"]
1146
+ else ("present" if health["has_project_mcp"] else "not configured")
1147
+ ),
1148
+ ".mcp.json status",
1149
+ )
1087
1150
  console.print(details)
1088
1151
 
1089
1152
  if health["missing_paths"]:
@@ -1106,6 +1169,13 @@ def upgrade():
1106
1169
  console.print("Run: [cyan]mapify init .[/cyan]")
1107
1170
  raise typer.Exit(0)
1108
1171
 
1172
+ if _detect_provider(project_path) == "codex":
1173
+ console.print(
1174
+ "[yellow]Codex projects: re-run "
1175
+ "[cyan]mapify init . --provider codex --force[/cyan] to refresh.[/yellow]"
1176
+ )
1177
+ raise typer.Exit(0)
1178
+
1109
1179
  console.print("[cyan]Checking for updates...[/cyan]")
1110
1180
  latest_release = get_latest_release("azalio", "map-framework")
1111
1181
  latest_version = None
@@ -26,7 +26,7 @@ BANNER = """
26
26
  ╩ ╩╩ ╩╩ ╩ ╩╩ ╩
27
27
  """
28
28
 
29
- TAGLINE = "MAP Kit - Modular Agentic Planner Framework for Claude Code"
29
+ TAGLINE = "MAP Kit - Modular Agentic Planner Framework"
30
30
 
31
31
  console = Console()
32
32