@prateek_ai/agents-maker 1.0.0 → 1.0.2

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 (68) hide show
  1. package/PROMPT_TEMPLATE.md +143 -0
  2. package/README.md +92 -25
  3. package/agents/brain.md +90 -0
  4. package/agents/orchestrator.md +24 -3
  5. package/agents/planpro.md +91 -0
  6. package/bin/cli.js +40 -4
  7. package/claude/agents/architect.md +182 -0
  8. package/claude/agents/brain.md +97 -0
  9. package/claude/agents/code.md +185 -0
  10. package/claude/agents/compress.md +233 -0
  11. package/claude/agents/execute.md +164 -0
  12. package/claude/agents/orchestrate.md +434 -0
  13. package/claude/agents/planpro.md +98 -0
  14. package/claude/agents/review.md +141 -0
  15. package/claude/agents/ui.md +154 -0
  16. package/claude/agents/ux.md +151 -0
  17. package/claude/commands/architect.md +15 -0
  18. package/claude/commands/brain.md +15 -0
  19. package/claude/commands/code.md +15 -0
  20. package/claude/commands/compress.md +15 -0
  21. package/claude/commands/execute.md +15 -0
  22. package/claude/commands/orchestrate.md +15 -0
  23. package/claude/commands/planpro.md +15 -0
  24. package/claude/commands/review.md +15 -0
  25. package/claude/commands/ui.md +15 -0
  26. package/claude/commands/ux.md +15 -0
  27. package/config/agents.yaml +56 -0
  28. package/context_loaders/project_summary.py +5 -0
  29. package/docs/architecture.md +318 -0
  30. package/docs/domains.md +154 -0
  31. package/docs/workflows.md +548 -0
  32. package/examples/generic_project_lifecycle.md +518 -0
  33. package/examples/proof/README.md +138 -0
  34. package/examples/proof/implement-a-python-function-that-parses-an-iso-8/grade.md +14 -0
  35. package/examples/proof/implement-a-python-function-that-parses-an-iso-8/naive_output.md +211 -0
  36. package/examples/proof/implement-a-python-function-that-parses-an-iso-8/naive_prompt.txt +1 -0
  37. package/examples/proof/implement-a-python-function-that-parses-an-iso-8/structured_output.md +210 -0
  38. package/examples/proof/implement-a-python-function-that-parses-an-iso-8/structured_user.txt +35 -0
  39. package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/grade.md +14 -0
  40. package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/naive_output.md +274 -0
  41. package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/naive_prompt.txt +1 -0
  42. package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/structured_output.md +127 -0
  43. package/examples/proof/write-a-runbook-for-recovering-from-a-redis-prim/structured_user.txt +35 -0
  44. package/package.json +10 -2
  45. package/platforms/antigravity.md +195 -0
  46. package/platforms/claude.md +305 -0
  47. package/platforms/openai.md +333 -0
  48. package/skills/analyze_repo.md +86 -86
  49. package/token_optimization/compressor.py +4 -7
  50. package/tools/_core.py +102 -0
  51. package/tools/compare_prompts.py +196 -0
  52. package/tools/generate_claude_agents.py +162 -0
  53. package/tools/generate_claude_md.py +14 -80
  54. package/tools/generate_platform_configs.py +26 -36
  55. package/tools/generate_prompt.py +79 -79
  56. package/tools/grade_proof.py +118 -0
  57. package/tools/init_project.py +11 -58
  58. package/tools/routing.py +103 -0
  59. package/tools/test_kit.py +392 -363
  60. package/tools/validate_kit.py +15 -43
  61. package/context_loaders/__pycache__/__init__.cpython-314.pyc +0 -0
  62. package/context_loaders/__pycache__/file_chunker.cpython-314.pyc +0 -0
  63. package/context_loaders/__pycache__/project_summary.cpython-314.pyc +0 -0
  64. package/context_loaders/__pycache__/repo_tree.cpython-314.pyc +0 -0
  65. package/token_optimization/__pycache__/compressor.cpython-314.pyc +0 -0
  66. package/tools/__pycache__/domain_utils.cpython-314.pyc +0 -0
  67. package/tools/__pycache__/generate_claude_md.cpython-314.pyc +0 -0
  68. package/tools/__pycache__/validate_kit.cpython-314.pyc +0 -0
@@ -11,10 +11,7 @@ Usage:
11
11
  from __future__ import annotations
12
12
 
13
13
  import argparse
14
- import hashlib
15
- import os
16
14
  import sys
17
- import tempfile
18
15
  from datetime import date
19
16
  from pathlib import Path
20
17
 
@@ -28,12 +25,6 @@ SCRIPT_DIR = Path(__file__).resolve().parent # agents-maker/tools/
28
25
  KIT_DIR = SCRIPT_DIR.parent # agents-maker/
29
26
  sys.path.insert(0, str(KIT_DIR))
30
27
 
31
- try:
32
- import yaml
33
- except ImportError:
34
- print("[ERROR] pyyaml is required: pip install pyyaml", file=sys.stderr)
35
- sys.exit(1)
36
-
37
28
  try:
38
29
  from context_loaders.project_summary import build_summary
39
30
  from context_loaders.repo_tree import walk_tree
@@ -43,10 +34,10 @@ except ImportError as e:
43
34
  sys.exit(1)
44
35
 
45
36
  try:
46
- from tools.domain_utils import _load_yaml
37
+ from tools._core import atomic_write, atomic_write_yaml, load_yaml, source_hash
47
38
  from tools.domain_utils import detect_domain as _detect_domain
48
39
  except ImportError:
49
- from domain_utils import _load_yaml
40
+ from _core import atomic_write, atomic_write_yaml, load_yaml, source_hash
50
41
  from domain_utils import detect_domain as _detect_domain
51
42
 
52
43
 
@@ -82,46 +73,6 @@ def _sanitize_yaml_str(value: str, field: str) -> str:
82
73
  return value
83
74
 
84
75
 
85
- # ---------------------------------------------------------------------------
86
- # Source hash — lets validate_kit.py detect stale system_prompt.md
87
- # ---------------------------------------------------------------------------
88
-
89
- def _compute_source_hash(kit_dir: Path) -> str:
90
- h = hashlib.sha256()
91
- agent_files = sorted((kit_dir / "agents").glob("*.md")) if (kit_dir / "agents").is_dir() else []
92
- skill_files = sorted((kit_dir / "skills").glob("*.md")) if (kit_dir / "skills").is_dir() else []
93
- for path in agent_files + skill_files:
94
- try:
95
- h.update(path.read_bytes().replace(b"\r\n", b"\n"))
96
- except (OSError, PermissionError):
97
- pass
98
- return h.hexdigest()[:16]
99
-
100
-
101
- # ---------------------------------------------------------------------------
102
- # Atomic write helpers (write to temp then os.replace — crash-safe)
103
- # ---------------------------------------------------------------------------
104
-
105
- def _atomic_write_text(path: Path, content: str) -> None:
106
- path.parent.mkdir(parents=True, exist_ok=True)
107
- with tempfile.NamedTemporaryFile(
108
- "w", dir=path.parent, delete=False, suffix=".tmp", encoding="utf-8"
109
- ) as f:
110
- f.write(content)
111
- tmp = f.name
112
- os.replace(tmp, path)
113
-
114
-
115
- def _atomic_write_yaml(path: Path, data: dict) -> None:
116
- path.parent.mkdir(parents=True, exist_ok=True)
117
- with tempfile.NamedTemporaryFile(
118
- "w", dir=path.parent, delete=False, suffix=".tmp", encoding="utf-8"
119
- ) as f:
120
- yaml.dump(data, f, default_flow_style=False, allow_unicode=True, sort_keys=False)
121
- tmp = f.name
122
- os.replace(tmp, path)
123
-
124
-
125
76
  # ---------------------------------------------------------------------------
126
77
  # system_prompt.md builder
127
78
  # ---------------------------------------------------------------------------
@@ -130,6 +81,8 @@ def build_system_prompt(project_name: str, domain: str, stack: list[str]) -> str
130
81
  agents_dir = KIT_DIR / "agents"
131
82
  agent_order = [
132
83
  "orchestrator.md",
84
+ "brain.md",
85
+ "planpro.md",
133
86
  "architect_agent.md",
134
87
  "code_agent.md",
135
88
  "execution_agent.md",
@@ -139,10 +92,10 @@ def build_system_prompt(project_name: str, domain: str, stack: list[str]) -> str
139
92
  "compression_agent.md",
140
93
  ]
141
94
  skill_count = len(list((KIT_DIR / "skills").glob("*.md"))) if (KIT_DIR / "skills").exists() else 0
142
- source_hash = _compute_source_hash(KIT_DIR)
95
+ src_hash = source_hash(KIT_DIR)
143
96
  version_header = (
144
97
  f"# agents-maker system_prompt.md\n"
145
- f"# Version: 1.0 | Generated: {date.today().isoformat()} | Source hash: {source_hash}\n"
98
+ f"# Version: 1.0 | Generated: {date.today().isoformat()} | Source hash: {src_hash}\n"
146
99
  f"# Regenerate: python agents-maker/tools/init_project.py --update\n"
147
100
  f"# Contains: {len(agent_order)} agents + {skill_count} skills\n"
148
101
  f"#\n"
@@ -332,7 +285,7 @@ def main() -> None:
332
285
  project_yaml_path = config_dir / "project.yaml"
333
286
 
334
287
  # Preserve session_count if updating
335
- existing_cfg = _load_yaml(project_yaml_path)
288
+ existing_cfg = load_yaml(project_yaml_path)
336
289
  session_count = existing_cfg.get("session_count", 0) if args.update else 0
337
290
  created_at = existing_cfg.get("created_at", date.today().isoformat()) if args.update else date.today().isoformat()
338
291
 
@@ -349,7 +302,7 @@ def main() -> None:
349
302
  "last_session": existing_cfg.get("last_session") if args.update else None,
350
303
  }
351
304
  try:
352
- _atomic_write_yaml(project_yaml_path, project_cfg)
305
+ atomic_write_yaml(project_yaml_path, project_cfg)
353
306
  except OSError as e:
354
307
  print(f"[ERROR] Could not write project.yaml: {e}", file=sys.stderr)
355
308
  sys.exit(1)
@@ -359,7 +312,7 @@ def main() -> None:
359
312
  if not system_prompt_path.exists() or args.update:
360
313
  system_prompt_text = build_system_prompt(project_name, final_domain, stack)
361
314
  try:
362
- _atomic_write_text(system_prompt_path, system_prompt_text)
315
+ atomic_write(system_prompt_path, system_prompt_text)
363
316
  except OSError as e:
364
317
  print(f"[ERROR] Could not write system_prompt.md: {e}", file=sys.stderr)
365
318
  sys.exit(1)
@@ -375,7 +328,7 @@ def main() -> None:
375
328
  state_path = KIT_DIR / "project_state.md"
376
329
  if not state_path.exists():
377
330
  try:
378
- _atomic_write_text(state_path, STATE_TEMPLATE)
331
+ atomic_write(state_path, STATE_TEMPLATE)
379
332
  state_created = True
380
333
  except OSError as e:
381
334
  print(f"[ERROR] Could not write project_state.md: {e}", file=sys.stderr)
@@ -437,7 +390,7 @@ def main() -> None:
437
390
  )
438
391
  claude_md_path = project_root / "CLAUDE.md"
439
392
  try:
440
- _atomic_write_text(claude_md_path, claude_md_content)
393
+ atomic_write(claude_md_path, claude_md_content)
441
394
  print(f" [DONE] CLAUDE.md written to {claude_md_path}")
442
395
  print(" Claude Code will auto-load domain/phase/stack on every session.")
443
396
  print(" Commit CLAUDE.md to git — it is project config, not private state.")
@@ -0,0 +1,103 @@
1
+ """
2
+ tools/routing.py
3
+
4
+ Single source of truth for lifecycle routing metadata: which specialist
5
+ agents are active for a given (phase, domain), plus phase labels and agent
6
+ role labels used across the generators.
7
+
8
+ Previously this mapping was hardcoded independently in three places
9
+ (generate_prompt.py, generate_claude_md.py, generate_platform_configs.py),
10
+ and the three copies had drifted apart. Centralizing them here makes the
11
+ routing consistent across every generated artifact (the pasted prompt,
12
+ CLAUDE.md, Copilot/Cursor rules, and the agkit config).
13
+
14
+ Two views are exposed because the tools present routing differently:
15
+ * phase_agents(phase, domain) -> the phase's agent list as declared in the
16
+ table (used where the orchestrator is mentioned separately, e.g. CLAUDE.md).
17
+ * active_agents(phase, domain) -> orchestrator-first, deduplicated (used for
18
+ the "Active agents" line of a generated prompt).
19
+ """
20
+
21
+ from __future__ import annotations
22
+
23
+ # Phase -> domain -> agents. "_all" is the default for domains without an override.
24
+ PHASE_AGENTS: dict[str, dict[str, list[str]]] = {
25
+ "task_framing": {"_all": ["orchestrator"]},
26
+ "requirements": {"_all": ["orchestrator", "architect_agent"]},
27
+ "solution_design": {
28
+ "_all": ["architect_agent"],
29
+ "software": ["architect_agent", "ui_agent"],
30
+ "product_design": ["architect_agent", "ui_agent", "ux_agent"],
31
+ "marketing": ["architect_agent", "ux_agent"],
32
+ },
33
+ "implementation": {
34
+ "_all": ["execution_agent"],
35
+ "software": ["code_agent"],
36
+ "data_analytics": ["code_agent"],
37
+ },
38
+ "review_refinement": {
39
+ "_all": ["reviewer_agent"],
40
+ "software": ["reviewer_agent", "code_agent"],
41
+ "product_design": ["reviewer_agent", "ui_agent", "ux_agent"],
42
+ "marketing": ["reviewer_agent", "ux_agent"],
43
+ },
44
+ "handoff": {"_all": ["orchestrator", "execution_agent"]},
45
+ }
46
+
47
+ PHASE_LABELS: dict[str, str] = {
48
+ "task_framing": "Task Framing",
49
+ "requirements": "Requirements",
50
+ "solution_design": "Solution Design",
51
+ "implementation": "Implementation",
52
+ "review_refinement": "Review & Refinement",
53
+ "handoff": "Handoff",
54
+ # aliases accepted by generate_prompt.py
55
+ "framing": "Task Framing",
56
+ "design": "Solution Design",
57
+ "implement": "Implementation",
58
+ "review": "Review & Refinement",
59
+ }
60
+
61
+ AGENT_ROLES: dict[str, str] = {
62
+ "orchestrator": "routing",
63
+ "architect_agent": "design",
64
+ "code_agent": "implementation",
65
+ "execution_agent": "execution",
66
+ "ui_agent": "UI",
67
+ "ux_agent": "UX",
68
+ "reviewer_agent": "QA",
69
+ "compression_agent": "compression",
70
+ "brain": "brainstorm",
71
+ "planpro": "planning",
72
+ }
73
+
74
+
75
+ def phase_agents(phase: str, domain: str) -> list[str]:
76
+ """Agents declared for (phase, domain), falling back to the phase's `_all` list."""
77
+ phase_map = PHASE_AGENTS.get(phase, {"_all": ["orchestrator"]})
78
+ return list(phase_map.get(domain, phase_map["_all"]))
79
+
80
+
81
+ def active_agents(phase: str, domain: str) -> list[str]:
82
+ """Orchestrator-first, de-duplicated agent list for a generated prompt."""
83
+ agents = ["orchestrator"]
84
+ for a in phase_agents(phase, domain):
85
+ if a not in agents:
86
+ agents.append(a)
87
+ return agents
88
+
89
+
90
+ def domain_agents(domain: str) -> list[str]:
91
+ """Every agent this domain uses across all phases (union), orchestrator first.
92
+
93
+ Used to scope a self-contained/Direct-Task-Mode system prompt: it must carry
94
+ the domain's implementation + review specialists (and their skills), not just
95
+ the phase-0 orchestrator — otherwise the skills that add value get dropped.
96
+ Still excludes agents from other domains, so it stays smaller than the full kit.
97
+ """
98
+ seen: list[str] = ["orchestrator"]
99
+ for phase in PHASE_AGENTS:
100
+ for a in active_agents(phase, domain):
101
+ if a not in seen:
102
+ seen.append(a)
103
+ return seen