claude-code-arcane 2.9.8 → 2.10.0

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 (147) hide show
  1. package/CHANGELOG.md +26 -0
  2. package/README.md +40 -38
  3. package/agents/business/business-ops-lead.md +1 -14
  4. package/agents/game/gameplay-programmer.md +3 -4
  5. package/agents/game/technical-artist.md +3 -4
  6. package/dist/cli.js +105 -39
  7. package/docs/USER-GUIDE.md +24 -22
  8. package/docs/coordination-rules.md +1 -1
  9. package/docs/directory-structure.md +93 -122
  10. package/package.json +1 -1
  11. package/profiles/ai.yaml +3 -0
  12. package/profiles/android-native.yaml +2 -0
  13. package/profiles/backend-go.yaml +1 -8
  14. package/profiles/backend-ts.yaml +2 -8
  15. package/profiles/backend-typescript.yaml +51 -0
  16. package/profiles/flutter.yaml +2 -0
  17. package/profiles/frontend-react-vite.yaml +39 -0
  18. package/profiles/frontend.yaml +2 -0
  19. package/profiles/integrations.yaml +6 -1
  20. package/profiles/ios-native.yaml +2 -0
  21. package/profiles/mobile-android-kotlin.yaml +36 -0
  22. package/profiles/mobile-flutter.yaml +37 -0
  23. package/profiles/mobile-ios-swift.yaml +37 -0
  24. package/profiles/mobile-react-native.yaml +39 -0
  25. package/profiles/mobile.yaml +2 -0
  26. package/rules/gamedev/engine-code.md +1 -1
  27. package/rules/gamedev/shader-code.md +1 -2
  28. package/rules/gamedev/vn-code.md +3 -2
  29. package/rules/implementation-workflow.md +1 -1
  30. package/rules/{ai-code.md → llm-code.md} +5 -5
  31. package/skills/agent-designer/README.md +2 -1
  32. package/skills/agent-designer/agent_evaluator.py +0 -5
  33. package/skills/ai-sdk-setup/SKILL.md +4 -4
  34. package/skills/arcane-add/SKILL.md +1 -1
  35. package/skills/arcane-list/SKILL.md +3 -3
  36. package/skills/arcane-status/SKILL.md +1 -1
  37. package/skills/architecture-decision/SKILL.md +3 -4
  38. package/skills/architecture-review/SKILL.md +1 -1
  39. package/skills/asset-audit/SKILL.md +0 -1
  40. package/skills/balance-check/SKILL.md +1 -1
  41. package/skills/brainstorm/SKILL.md +3 -3
  42. package/skills/brainstorm/references/next-steps-pipeline.md +8 -9
  43. package/skills/consistency-check/SKILL.md +2 -2
  44. package/skills/design-system/SKILL.md +1 -1
  45. package/skills/design-system/references/post-design-validation.md +2 -3
  46. package/skills/freelance-kickoff/SKILL.md +1 -1
  47. package/skills/frontend-dev/SKILL.md +27 -28
  48. package/skills/frontend-dev/references/asset-prompt-guide.md +1 -1
  49. package/skills/frontend-dev/references/motion-recipes.md +1 -1
  50. package/skills/help/SKILL.md +1 -2
  51. package/skills/hotfix/SKILL.md +2 -2
  52. package/skills/milestone-review/SKILL.md +1 -1
  53. package/skills/patch-notes/SKILL.md +1 -1
  54. package/skills/playtest-report/SKILL.md +2 -3
  55. package/skills/playwright-pro/CLAUDE.md +2 -2
  56. package/skills/playwright-pro/SKILL.md +13 -9
  57. package/skills/playwright-pro/agents/migration-planner.md +2 -2
  58. package/skills/playwright-pro/agents/test-architect.md +1 -2
  59. package/skills/playwright-pro/agents/test-debugger.md +1 -1
  60. package/skills/playwright-pro/hooks/detect-playwright.sh +1 -1
  61. package/skills/playwright-pro/skills/browserstack/SKILL.md +5 -5
  62. package/skills/playwright-pro/skills/migrate/SKILL.md +1 -1
  63. package/skills/playwright-pro/skills/report/SKILL.md +2 -2
  64. package/skills/playwright-pro/skills/testrail/SKILL.md +5 -5
  65. package/skills/playwright-pro/templates/README.md +2 -2
  66. package/skills/prototype/SKILL.md +1 -1
  67. package/skills/quick-design/SKILL.md +1 -1
  68. package/skills/release-checklist/SKILL.md +0 -1
  69. package/skills/security-audit/SKILL.md +1 -1
  70. package/skills/self-improving-agent/CLAUDE.md +12 -12
  71. package/skills/self-improving-agent/SKILL.md +16 -12
  72. package/skills/self-improving-agent/agents/memory-analyst.md +1 -1
  73. package/skills/self-improving-agent/hooks/error-capture.sh +2 -2
  74. package/skills/self-improving-agent/reference/memory-architecture.md +2 -2
  75. package/skills/self-improving-agent/reference/promotion-rules.md +3 -3
  76. package/skills/self-improving-agent/reference/rules-directory-patterns.md +1 -1
  77. package/skills/self-improving-agent/settings.json +5 -5
  78. package/skills/self-improving-agent/skills/extract/SKILL.md +7 -7
  79. package/skills/self-improving-agent/skills/promote/SKILL.md +5 -5
  80. package/skills/self-improving-agent/skills/remember/SKILL.md +9 -9
  81. package/skills/self-improving-agent/skills/review/SKILL.md +7 -7
  82. package/skills/self-improving-agent/skills/status/SKILL.md +8 -8
  83. package/skills/senior-ml-engineer/references/llm_integration_guide.md +14 -31
  84. package/skills/senior-prompt-engineer/SKILL.md +10 -10
  85. package/skills/senior-prompt-engineer/references/prompt_engineering_patterns.md +1 -1
  86. package/skills/senior-prompt-engineer/scripts/agent_orchestrator.py +43 -40
  87. package/skills/senior-prompt-engineer/scripts/prompt_optimizer.py +23 -66
  88. package/skills/shader-dev/reference/fluid-simulation.md +4 -4
  89. package/skills/shader-dev/reference/simulation-physics.md +6 -6
  90. package/skills/shader-dev/reference/voxel-rendering.md +1 -1
  91. package/skills/shader-dev/techniques/ambient-occlusion.md +1 -1
  92. package/skills/shader-dev/techniques/analytic-ray-tracing.md +2 -2
  93. package/skills/shader-dev/techniques/domain-warping.md +2 -2
  94. package/skills/shader-dev/techniques/fluid-simulation.md +45 -45
  95. package/skills/shader-dev/techniques/multipass-buffer.md +24 -24
  96. package/skills/shader-dev/techniques/normal-estimation.md +1 -1
  97. package/skills/shader-dev/techniques/particle-system.md +16 -16
  98. package/skills/shader-dev/techniques/polar-uv-manipulation.md +1 -1
  99. package/skills/shader-dev/techniques/post-processing.md +7 -7
  100. package/skills/shader-dev/techniques/sdf-3d.md +1 -1
  101. package/skills/shader-dev/techniques/simulation-physics.md +24 -24
  102. package/skills/shader-dev/techniques/sound-synthesis.md +2 -2
  103. package/skills/shader-dev/techniques/voronoi-cellular-noise.md +1 -1
  104. package/skills/shader-dev/techniques/voxel-rendering.md +60 -60
  105. package/skills/smoke-check/SKILL.md +1 -1
  106. package/skills/sprint-plan/SKILL.md +1 -2
  107. package/skills/start/SKILL.md +7 -7
  108. package/skills/story-done/SKILL.md +1 -1
  109. package/skills/test-helpers/SKILL.md +7 -2
  110. package/skills/test-setup/SKILL.md +1 -1
  111. package/skills/ue-actor-component-architecture/SKILL.md +0 -1
  112. package/skills/ue-ai-navigation/SKILL.md +0 -1
  113. package/skills/ue-animation-system/SKILL.md +0 -1
  114. package/skills/ue-async-threading/SKILL.md +0 -1
  115. package/skills/ue-audio-system/SKILL.md +0 -1
  116. package/skills/ue-blueprints/SKILL.md +0 -1
  117. package/skills/ue-character-movement/SKILL.md +0 -1
  118. package/skills/ue-cpp-foundations/SKILL.md +0 -1
  119. package/skills/ue-data-assets-tables/SKILL.md +0 -1
  120. package/skills/ue-editor-tools/SKILL.md +0 -1
  121. package/skills/ue-game-features/SKILL.md +0 -1
  122. package/skills/ue-gameplay-abilities/SKILL.md +0 -1
  123. package/skills/ue-gameplay-framework/SKILL.md +0 -1
  124. package/skills/ue-input-system/SKILL.md +0 -1
  125. package/skills/ue-mass-entity/SKILL.md +0 -1
  126. package/skills/ue-materials-rendering/SKILL.md +0 -1
  127. package/skills/ue-module-build-system/SKILL.md +0 -1
  128. package/skills/ue-naming-conventions/SKILL.md +0 -1
  129. package/skills/ue-networking-replication/SKILL.md +0 -1
  130. package/skills/ue-niagara-effects/SKILL.md +0 -1
  131. package/skills/ue-packaging/SKILL.md +0 -1
  132. package/skills/ue-physics-collision/SKILL.md +0 -1
  133. package/skills/ue-procedural-generation/SKILL.md +0 -1
  134. package/skills/ue-project-context/SKILL.md +0 -1
  135. package/skills/ue-sequencer-cinematics/SKILL.md +0 -1
  136. package/skills/ue-serialization-savegames/SKILL.md +0 -1
  137. package/skills/ue-state-trees/SKILL.md +0 -1
  138. package/skills/ue-testing-debugging/SKILL.md +0 -1
  139. package/skills/ue-ui-umg-slate/SKILL.md +0 -1
  140. package/skills/ue-world-level-streaming/SKILL.md +0 -1
  141. package/skills/ux-review/SKILL.md +1 -1
  142. package/docs/RELEASE-SETUP.md +0 -99
  143. package/docs/presentations/arcane-overview-12.pptx +0 -0
  144. package/docs/presentations/arcane-overview.pptx +0 -0
  145. package/docs/presentations/build_arcane_deck.py +0 -310
  146. package/docs/presentations/build_arcane_deck_12.py +0 -399
  147. package/docs/trusted-publishing-setup.md +0 -163
@@ -7,17 +7,17 @@ user-invocable: false
7
7
  allowed-tools: Read, Glob, Grep, Bash
8
8
  ---
9
9
 
10
- # /si:review — Analyze Auto-Memory
10
+ # /self-improving-agent review — Analyze Auto-Memory
11
11
 
12
12
  Performs a comprehensive audit of Claude Code's auto-memory and produces actionable recommendations.
13
13
 
14
14
  ## Usage
15
15
 
16
16
  ```
17
- /si:review # Full review
18
- /si:review --quick # Summary only (counts + top 3 candidates)
19
- /si:review --stale # Focus on stale/outdated entries
20
- /si:review --candidates # Show only promotion candidates
17
+ /self-improving-agent review # Full review
18
+ /self-improving-agent review --quick # Summary only (counts + top 3 candidates)
19
+ /self-improving-agent review --stale # Focus on stale/outdated entries
20
+ /self-improving-agent review --candidates # Show only promotion candidates
21
21
  ```
22
22
 
23
23
  ## What It Does
@@ -117,14 +117,14 @@ Memory Health:
117
117
  ## When to Use
118
118
 
119
119
  - After completing a major feature or debugging session
120
- - When `/si:status` shows MEMORY.md is over 150 lines
120
+ - When `/self-improving-agent status` shows MEMORY.md is over 150 lines
121
121
  - Weekly during active development
122
122
  - Before starting a new project phase
123
123
  - After onboarding a new team member (review what Claude learned)
124
124
 
125
125
  ## Tips
126
126
 
127
- - Run `/si:review --quick` frequently (low overhead)
127
+ - Run `/self-improving-agent review --quick` frequently (low overhead)
128
128
  - Full review is most valuable when MEMORY.md is getting crowded
129
129
  - Act on promotion candidates promptly — they're proven patterns
130
130
  - Don't hesitate to delete stale entries — auto-memory will re-learn if needed
@@ -7,15 +7,15 @@ user-invocable: false
7
7
  allowed-tools: Read, Glob, Grep, Bash
8
8
  ---
9
9
 
10
- # /si:status — Memory Health Dashboard
10
+ # /self-improving-agent status — Memory Health Dashboard
11
11
 
12
12
  Quick overview of your project's memory state across all memory systems.
13
13
 
14
14
  ## Usage
15
15
 
16
16
  ```
17
- /si:status # Full dashboard
18
- /si:status --brief # One-line summary
17
+ /self-improving-agent status # Full dashboard
18
+ /self-improving-agent status --brief # One-line summary
19
19
  ```
20
20
 
21
21
  ## What It Reports
@@ -88,7 +88,7 @@ done
88
88
  ### Brief mode
89
89
 
90
90
  ```
91
- /si:status --brief
91
+ /self-improving-agent status --brief
92
92
  ```
93
93
 
94
94
  Output: `📊 Memory: {{n}}/200 lines | {{count}} rules | {{status_emoji}} {{status_word}}`
@@ -96,12 +96,12 @@ Output: `📊 Memory: {{n}}/200 lines | {{count}} rules | {{status_emoji}} {{sta
96
96
  ## Interpretation
97
97
 
98
98
  - **Green (< 60%)**: Plenty of room. Auto-memory is working well.
99
- - **Yellow (60-90%)**: Getting full. Consider running `/si:review` to promote or clean up.
100
- - **Red (> 90%)**: Near capacity. Auto-memory may start dropping older entries. Run `/si:review` now.
99
+ - **Yellow (60-90%)**: Getting full. Consider running `/self-improving-agent review` to promote or clean up.
100
+ - **Red (> 90%)**: Near capacity. Auto-memory may start dropping older entries. Run `/self-improving-agent review` now.
101
101
 
102
102
  ## Tips
103
103
 
104
- - Run `/si:status --brief` as a quick check anytime
105
- - If capacity is yellow+, run `/si:review` to identify promotion candidates
104
+ - Run `/self-improving-agent status --brief` as a quick check anytime
105
+ - If capacity is yellow+, run `/self-improving-agent review` to identify promotion candidates
106
106
  - Stale entries waste space — delete references to files that no longer exist
107
107
  - Topic files are fine — Claude creates them to keep MEMORY.md under 200 lines
@@ -47,13 +47,14 @@ class OpenAIProvider(LLMProvider):
47
47
  return response.choices[0].text
48
48
 
49
49
  class AnthropicProvider(LLMProvider):
50
- def __init__(self, api_key: str, model: str = "claude-3-opus"):
50
+ def __init__(self, api_key: str, model: str = "claude-opus-5-5"):
51
51
  self.client = Anthropic(api_key=api_key)
52
52
  self.model = model
53
53
 
54
54
  def chat(self, messages: List[Dict], **kwargs) -> str:
55
55
  response = self.client.messages.create(
56
56
  model=self.model,
57
+ max_tokens=kwargs.pop("max_tokens", 16000),
57
58
  messages=messages,
58
59
  **kwargs
59
60
  )
@@ -97,7 +98,7 @@ def call_with_fallback(
97
98
  |---------|----------|-----------|
98
99
  | Zero-shot | Simple tasks | Task description + input |
99
100
  | Few-shot | Complex tasks | Examples + task + input |
100
- | Chain-of-thought | Reasoning | "Think step by step" + task |
101
+ | Reasoning | Multi-step problems | On models with adaptive thinking, raise `effort` instead of asking for step-by-step text |
101
102
  | Role-based | Specialized output | System role + task |
102
103
 
103
104
  ### Few-Shot Template
@@ -178,10 +179,8 @@ def truncate_to_token_limit(text: str, max_tokens: int, model: str = "gpt-4") ->
178
179
 
179
180
  | Model | Context Window | Effective Limit |
180
181
  |-------|----------------|-----------------|
181
- | GPT-4 | 8,192 | ~6,000 (leave room for response) |
182
- | GPT-4-32k | 32,768 | ~28,000 |
183
- | Claude 3 | 200,000 | ~180,000 |
184
- | Llama 3 | 8,192 | ~6,000 |
182
+ | Claude Opus 5.5 / Sonnet 5.5 / Haiku 5.5 | 1,000,000 | leave room for `max_tokens` |
183
+ | Other providers | check the provider's model docs | context windows change every release |
185
184
 
186
185
  ### Chunking Strategy
187
186
 
@@ -206,12 +205,7 @@ def chunk_text(text: str, chunk_size: int = 1000, overlap: int = 100) -> List[st
206
205
 
207
206
  ### Cost Calculation
208
207
 
209
- | Provider | Input Cost | Output Cost | Example (1K tokens) |
210
- |----------|------------|-------------|---------------------|
211
- | GPT-4 | $0.03/1K | $0.06/1K | $0.09 |
212
- | GPT-3.5 | $0.0005/1K | $0.0015/1K | $0.002 |
213
- | Claude 3 Opus | $0.015/1K | $0.075/1K | $0.09 |
214
- | Claude 3 Haiku | $0.00025/1K | $0.00125/1K | $0.0015 |
208
+ Prices change with every model release, so keep them out of code: read them from config, and take the numbers from each provider's pricing page. Count tokens with the provider's response metadata (`usage`), not with a character estimate.
215
209
 
216
210
  ### Cost Tracking
217
211
 
@@ -229,30 +223,19 @@ class LLMUsage:
229
223
  def calculate_cost(
230
224
  input_tokens: int,
231
225
  output_tokens: int,
232
- model: str
226
+ prices: dict,
233
227
  ) -> float:
234
- """Calculate cost based on token usage."""
235
- PRICING = {
236
- "gpt-4": {"input": 0.03, "output": 0.06},
237
- "gpt-3.5-turbo": {"input": 0.0005, "output": 0.0015},
238
- "claude-3-opus": {"input": 0.015, "output": 0.075},
239
- }
240
-
241
- prices = PRICING.get(model, {"input": 0.01, "output": 0.03})
242
-
243
- input_cost = (input_tokens / 1000) * prices["input"]
244
- output_cost = (output_tokens / 1000) * prices["output"]
245
-
246
- return input_cost + output_cost
228
+ """Cost in USD. `prices` comes from config: {"input": usd_per_mtok, "output": usd_per_mtok}."""
229
+ return (input_tokens * prices["input"] + output_tokens * prices["output"]) / 1_000_000
247
230
  ```
248
231
 
249
232
  ### Cost Optimization Strategies
250
233
 
251
- 1. **Use smaller models for simple tasks** - GPT-3.5 for classification, GPT-4 for reasoning
252
- 2. **Cache common responses** - Store results for repeated queries
253
- 3. **Batch requests** - Combine multiple items in single prompt
254
- 4. **Truncate context** - Only include relevant information
255
- 5. **Set max_tokens limit** - Prevent runaway responses
234
+ 1. **Use a smaller model where it holds quality** - measure on real requests before routing a task to it
235
+ 2. **Cache repeated context** - provider prompt caching makes a stable system prompt or document far cheaper on repeat calls
236
+ 3. **Batch non-urgent work** - batch APIs trade latency for a lower price
237
+ 4. **Cache common responses** - store results for repeated queries
238
+ 5. **Set max_tokens deliberately** - high enough not to cut answers off, as a ceiling on runaway output
256
239
 
257
240
  ---
258
241
 
@@ -23,12 +23,12 @@ python scripts/agent_orchestrator.py agent_config.yaml --visualize # Visua
23
23
 
24
24
  ### 1. Prompt Optimizer
25
25
 
26
- Analyzes prompts for token efficiency, clarity, and structure. Generates optimized versions.
26
+ Static checks for clarity and structure, with an approximate token count (characters / 4). `--optimize` only normalizes whitespace; the real rewrite is yours.
27
27
 
28
28
  ```bash
29
29
  python scripts/prompt_optimizer.py prompt.txt --analyze # Full analysis
30
- python scripts/prompt_optimizer.py prompt.txt --optimize # Generate optimized version
31
- python scripts/prompt_optimizer.py prompt.txt --tokens --model gpt-4 # Token count
30
+ python scripts/prompt_optimizer.py prompt.txt --optimize # Normalize whitespace
31
+ python scripts/prompt_optimizer.py prompt.txt --tokens # Approximate token count
32
32
  python scripts/prompt_optimizer.py prompt.txt --extract-examples --output examples.json
33
33
  ```
34
34
 
@@ -50,7 +50,7 @@ Parses agent definitions and visualizes execution flows. Validates tool configur
50
50
  python scripts/agent_orchestrator.py agent.yaml --validate # Validate config
51
51
  python scripts/agent_orchestrator.py agent.yaml --visualize # Show workflow (ASCII)
52
52
  python scripts/agent_orchestrator.py agent.yaml --visualize --format mermaid # Mermaid
53
- python scripts/agent_orchestrator.py agent.yaml --estimate-cost # Token estimation
53
+ python scripts/agent_orchestrator.py agent.yaml --estimate-cost --price-in 4 --price-out 20 # Tokens; dollars with your current prices (USD/Mtok)
54
54
  ```
55
55
 
56
56
  ## Prompt Engineering Workflows
@@ -65,7 +65,7 @@ python scripts/agent_orchestrator.py agent.yaml --estimate-cost # Token estimat
65
65
  |-------|---------|
66
66
  | Ambiguous output | Add explicit format specification |
67
67
  | Too verbose | Extract to few-shot examples |
68
- | Inconsistent results | Add role/persona framing |
68
+ | Inconsistent results | Add 2-3 varied examples and state the success criteria |
69
69
  | Missing edge cases | Add constraint boundaries |
70
70
 
71
71
  4. **Optimize**: `python scripts/prompt_optimizer.py current_prompt.txt --optimize --output optimized.txt`
@@ -77,15 +77,15 @@ python scripts/agent_orchestrator.py agent.yaml --estimate-cost # Token estimat
77
77
  1. Define task clearly (input format, output format)
78
78
  2. Select 3-5 diverse examples: simple case, edge case, complex case, negative case
79
79
  3. Format consistently
80
- 4. Validate: `python scripts/prompt_optimizer.py prompt_with_examples.txt --validate-examples`
80
+ 4. Check what the prompt contains: `python scripts/prompt_optimizer.py prompt_with_examples.txt --extract-examples`
81
81
  5. Test with held-out cases
82
82
 
83
83
  ### Structured Output Design
84
84
 
85
85
  1. Define JSON/XML schema with types, constraints, enums
86
- 2. Include schema description in prompt
87
- 3. Add format enforcement: "Respond ONLY with valid JSON. Start with { and end with }"
88
- 4. Validate: `python scripts/prompt_optimizer.py structured_prompt.txt --validate-schema schema.json`
86
+ 2. Pass the schema through the API's structured outputs (`output_config.format` on Claude) so the response is guaranteed to match it; do not rely on "respond ONLY with valid JSON" in the prompt
87
+ 3. Describe in the prompt what each field means, not the JSON syntax
88
+ 4. Validate the parsed result against the schema in code before using it
89
89
 
90
90
  ## Reference Documentation
91
91
 
@@ -103,6 +103,6 @@ python scripts/agent_orchestrator.py agent.yaml --estimate-cost # Token estimat
103
103
  |---------|-------------|---------|
104
104
  | **Zero-shot** | Simple, well-defined tasks | "Classify this email as spam or not spam" |
105
105
  | **Few-shot** | Complex tasks, consistent format | Provide 3-5 examples before task |
106
- | **Chain-of-Thought** | Reasoning, math, multi-step | "Think step by step..." |
106
+ | **Reasoning depth** | Reasoning, math, multi-step | Models with adaptive thinking: raise `effort`. Models without it: "Think step by step..." |
107
107
  | **Role Prompting** | Expertise, specific perspective | "You are an expert tax accountant..." |
108
108
  | **Structured Output** | Need parseable JSON/XML | Include schema + format enforcement |
@@ -164,7 +164,7 @@ The 7 apples cost $11.20
164
164
  | Reasoning chain | "Explain your reasoning" | Justification needed |
165
165
 
166
166
  **Zero-shot CoT:**
167
- Simply append "Let's think step by step." to any prompt.
167
+ Append "Let's think step by step." only on models without built-in thinking. On models with adaptive thinking, control depth with `effort`; asking for the reasoning in the output can be declined as reasoning extraction.
168
168
 
169
169
  ---
170
170
 
@@ -55,7 +55,7 @@ class AgentConfig:
55
55
  max_iterations: int = 10
56
56
  system_prompt: str = ""
57
57
  temperature: float = 0.7
58
- model: str = "gpt-4"
58
+ model: str = ""
59
59
 
60
60
 
61
61
  @dataclass
@@ -177,7 +177,7 @@ def load_config(path: Path) -> AgentConfig:
177
177
  max_iterations=int(data.get('max_iterations', 10)),
178
178
  system_prompt=data.get('system_prompt', ''),
179
179
  temperature=float(data.get('temperature', 0.7)),
180
- model=data.get('model', 'gpt-4')
180
+ model=data.get('model', '')
181
181
  )
182
182
 
183
183
 
@@ -369,44 +369,39 @@ def generate_mermaid_diagram(config: AgentConfig) -> str:
369
369
  return '\n'.join(lines)
370
370
 
371
371
 
372
- def estimate_cost(config: AgentConfig, runs: int = 100) -> Dict[str, Any]:
373
- """Estimate token costs for agent runs"""
372
+ def estimate_cost(config: AgentConfig, runs: int = 100,
373
+ price_in: Optional[float] = None, price_out: Optional[float] = None) -> Dict[str, Any]:
374
+ """Estimate tokens per run; dollars only when the caller supplies current prices.
375
+
376
+ Prices are USD per million tokens. They are not built in because provider prices
377
+ change and a stale table gives confidently wrong numbers.
378
+ """
374
379
  validation = validate_agent(config)
375
380
  min_tokens, max_tokens = validation.estimated_tokens_per_run
376
381
 
377
- # Cost per 1K tokens
378
- costs = {
379
- 'gpt-4': {'input': 0.03, 'output': 0.06},
380
- 'gpt-4-turbo': {'input': 0.01, 'output': 0.03},
381
- 'gpt-3.5-turbo': {'input': 0.0005, 'output': 0.0015},
382
- 'claude-3-opus': {'input': 0.015, 'output': 0.075},
383
- 'claude-3-sonnet': {'input': 0.003, 'output': 0.015},
384
- }
385
-
386
- model_cost = costs.get(config.model, costs['gpt-4'])
387
-
388
- # Assume 60% input, 40% output
389
- input_tokens = min_tokens * 0.6
390
- output_tokens = min_tokens * 0.4
382
+ def dollars(tokens: float) -> Optional[float]:
383
+ if price_in is None or price_out is None:
384
+ return None
385
+ # Assume 60% input, 40% output
386
+ return (tokens * 0.6 * price_in + tokens * 0.4 * price_out) / 1_000_000
391
387
 
392
- cost_per_run_min = (input_tokens / 1000 * model_cost['input'] +
393
- output_tokens / 1000 * model_cost['output'])
388
+ per_run_min, per_run_max = dollars(min_tokens), dollars(max_tokens)
389
+ monthly_runs = runs * 30
394
390
 
395
- input_tokens_max = max_tokens * 0.6
396
- output_tokens_max = max_tokens * 0.4
397
- cost_per_run_max = (input_tokens_max / 1000 * model_cost['input'] +
398
- output_tokens_max / 1000 * model_cost['output'])
399
-
400
- return {
401
- 'model': config.model,
391
+ result = {
392
+ 'model': config.model or None,
402
393
  'tokens_per_run': {'min': min_tokens, 'max': max_tokens},
403
- 'cost_per_run': {'min': round(cost_per_run_min, 4), 'max': round(cost_per_run_max, 4)},
404
394
  'estimated_monthly': {
405
- 'runs': runs * 30,
406
- 'cost_min': round(cost_per_run_min * runs * 30, 2),
407
- 'cost_max': round(cost_per_run_max * runs * 30, 2)
408
- }
395
+ 'runs': monthly_runs,
396
+ 'tokens_min': min_tokens * monthly_runs,
397
+ 'tokens_max': max_tokens * monthly_runs,
398
+ },
409
399
  }
400
+ if per_run_min is not None:
401
+ result['cost_per_run'] = {'min': round(per_run_min, 4), 'max': round(per_run_max, 4)}
402
+ result['estimated_monthly']['cost_min'] = round(per_run_min * monthly_runs, 2)
403
+ result['estimated_monthly']['cost_max'] = round(per_run_max * monthly_runs, 2)
404
+ return result
410
405
 
411
406
 
412
407
  def format_validation_report(config: AgentConfig, result: ValidationResult) -> str:
@@ -461,6 +456,9 @@ def format_validation_report(config: AgentConfig, result: ValidationResult) -> s
461
456
 
462
457
 
463
458
  def main():
459
+ # The report uses emoji; a Windows console defaults to cp1252 and cannot print them.
460
+ if hasattr(sys.stdout, "reconfigure"):
461
+ sys.stdout.reconfigure(encoding="utf-8")
464
462
  parser = argparse.ArgumentParser(
465
463
  description="Agent Orchestrator - Design and validate agent workflows",
466
464
  formatter_class=argparse.RawDescriptionHelpFormatter,
@@ -469,13 +467,13 @@ Examples:
469
467
  %(prog)s agent.yaml --validate
470
468
  %(prog)s agent.yaml --visualize
471
469
  %(prog)s agent.yaml --visualize --format mermaid
472
- %(prog)s agent.yaml --estimate-cost --runs 100
470
+ %(prog)s agent.yaml --estimate-cost --runs 100 --price-in 4 --price-out 20
473
471
 
474
472
  Agent config format (YAML):
475
473
 
476
474
  name: research_assistant
477
475
  pattern: react
478
- model: gpt-4
476
+ model: claude-opus-5-5
479
477
  max_iterations: 10
480
478
  tools:
481
479
  - name: web_search
@@ -493,6 +491,8 @@ tools:
493
491
  help='Visualization format (default: ascii)')
494
492
  parser.add_argument('--estimate-cost', '-e', action='store_true', help='Estimate token costs')
495
493
  parser.add_argument('--runs', '-r', type=int, default=100, help='Daily runs for cost estimation')
494
+ parser.add_argument('--price-in', type=float, help='Current input price, USD per million tokens')
495
+ parser.add_argument('--price-out', type=float, help='Current output price, USD per million tokens')
496
496
  parser.add_argument('--output', '-o', help='Output file path')
497
497
  parser.add_argument('--json', '-j', action='store_true', help='Output as JSON')
498
498
 
@@ -534,18 +534,21 @@ tools:
534
534
 
535
535
  # Cost estimation
536
536
  if args.estimate_cost:
537
- costs = estimate_cost(config, args.runs)
537
+ costs = estimate_cost(config, args.runs, args.price_in, args.price_out)
538
538
  if args.json:
539
539
  output_parts.append(json.dumps(costs, indent=2))
540
540
  else:
541
541
  output_parts.append("")
542
542
  output_parts.append("💰 COST ESTIMATION")
543
- output_parts.append(f" Model: {costs['model']}")
543
+ output_parts.append(f" Model: {costs['model'] or '(not set)'}")
544
544
  output_parts.append(f" Tokens per run: {costs['tokens_per_run']['min']:,} - {costs['tokens_per_run']['max']:,}")
545
- output_parts.append(f" Cost per run: ${costs['cost_per_run']['min']:.4f} - ${costs['cost_per_run']['max']:.4f}")
546
- output_parts.append(f" Monthly ({costs['estimated_monthly']['runs']:,} runs):")
547
- output_parts.append(f" Min: ${costs['estimated_monthly']['cost_min']:.2f}")
548
- output_parts.append(f" Max: ${costs['estimated_monthly']['cost_max']:.2f}")
545
+ monthly = costs['estimated_monthly']
546
+ output_parts.append(f" Monthly ({monthly['runs']:,} runs): {monthly['tokens_min']:,} - {monthly['tokens_max']:,} tokens")
547
+ if 'cost_per_run' in costs:
548
+ output_parts.append(f" Cost per run: ${costs['cost_per_run']['min']:.4f} - ${costs['cost_per_run']['max']:.4f}")
549
+ output_parts.append(f" Monthly cost: ${monthly['cost_min']:.2f} - ${monthly['cost_max']:.2f}")
550
+ else:
551
+ output_parts.append(" Cost: pass --price-in and --price-out (USD per million tokens) to get dollars")
549
552
 
550
553
  # Output
551
554
  output = '\n'.join(output_parts)
@@ -3,7 +3,7 @@
3
3
  Prompt Optimizer - Static analysis tool for prompt engineering
4
4
 
5
5
  Features:
6
- - Token estimation (GPT-4/Claude approximation)
6
+ - Approximate token count (characters / 4, not a real tokenizer)
7
7
  - Prompt structure analysis
8
8
  - Clarity scoring
9
9
  - Few-shot example extraction and management
@@ -11,7 +11,7 @@ Features:
11
11
 
12
12
  Usage:
13
13
  python prompt_optimizer.py prompt.txt --analyze
14
- python prompt_optimizer.py prompt.txt --tokens --model gpt-4
14
+ python prompt_optimizer.py prompt.txt --tokens
15
15
  python prompt_optimizer.py prompt.txt --optimize --output optimized.txt
16
16
  python prompt_optimizer.py prompt.txt --extract-examples --output examples.json
17
17
  """
@@ -25,32 +25,15 @@ from typing import Dict, List, Optional, Tuple
25
25
  from dataclasses import dataclass, asdict
26
26
 
27
27
 
28
- # Token estimation ratios (chars per token approximation)
29
- TOKEN_RATIOS = {
30
- 'gpt-4': 4.0,
31
- 'gpt-3.5': 4.0,
32
- 'claude': 3.5,
33
- 'default': 4.0
34
- }
35
-
36
- # Cost per 1K tokens (input)
37
- COST_PER_1K = {
38
- 'gpt-4': 0.03,
39
- 'gpt-4-turbo': 0.01,
40
- 'gpt-3.5-turbo': 0.0005,
41
- 'claude-3-opus': 0.015,
42
- 'claude-3-sonnet': 0.003,
43
- 'claude-3-haiku': 0.00025,
44
- 'default': 0.01
45
- }
28
+ # Rough characters-per-token ratio. Real tokenizers differ by model and by text, so
29
+ # every count here is an estimate; use the provider's token-counting API for exact numbers.
30
+ CHARS_PER_TOKEN = 4.0
46
31
 
47
32
 
48
33
  @dataclass
49
34
  class PromptAnalysis:
50
35
  """Results of prompt analysis"""
51
36
  token_count: int
52
- estimated_cost: float
53
- model: str
54
37
  clarity_score: int
55
38
  structure_score: int
56
39
  issues: List[Dict[str, str]]
@@ -71,16 +54,9 @@ class FewShotExample:
71
54
  index: int
72
55
 
73
56
 
74
- def estimate_tokens(text: str, model: str = 'default') -> int:
75
- """Estimate token count based on character ratio"""
76
- ratio = TOKEN_RATIOS.get(model, TOKEN_RATIOS['default'])
77
- return int(len(text) / ratio)
78
-
79
-
80
- def estimate_cost(token_count: int, model: str = 'default') -> float:
81
- """Estimate cost based on token count"""
82
- cost_per_1k = COST_PER_1K.get(model, COST_PER_1K['default'])
83
- return round((token_count / 1000) * cost_per_1k, 6)
57
+ def estimate_tokens(text: str) -> int:
58
+ """Approximate token count from the character count"""
59
+ return int(len(text) / CHARS_PER_TOKEN)
84
60
 
85
61
 
86
62
  def find_ambiguous_instructions(text: str) -> List[Dict[str, str]]:
@@ -89,11 +65,9 @@ def find_ambiguous_instructions(text: str) -> List[Dict[str, str]]:
89
65
 
90
66
  # Vague verbs that need specificity
91
67
  vague_patterns = [
92
- (r'\b(analyze|process|handle|deal with)\b', 'Vague verb - specify the exact action'),
93
68
  (r'\b(good|nice|appropriate|suitable)\b', 'Subjective term - define specific criteria'),
94
69
  (r'\b(etc\.|and so on|and more)\b', 'Open-ended list - enumerate all items explicitly'),
95
70
  (r'\b(if needed|as necessary|when appropriate)\b', 'Conditional without criteria - specify when'),
96
- (r'\b(some|several|many|few|various)\b', 'Vague quantity - use specific numbers'),
97
71
  ]
98
72
 
99
73
  lines = text.split('\n')
@@ -155,7 +129,7 @@ def check_output_format(text: str) -> Tuple[bool, List[str]]:
155
129
  has_format = any(re.search(p, text, re.IGNORECASE) for p in format_indicators)
156
130
 
157
131
  if not has_format:
158
- suggestions.append('Add explicit output format specification (e.g., "Respond in JSON with keys: ...")')
132
+ suggestions.append('State the expected output format (structure, length, what to include)')
159
133
 
160
134
  return has_format, suggestions
161
135
 
@@ -277,7 +251,7 @@ def generate_suggestions(analysis: PromptAnalysis) -> List[str]:
277
251
  suggestions = []
278
252
 
279
253
  if not analysis.has_output_format:
280
- suggestions.append('Add explicit output format: "Respond in JSON with keys: ..."')
254
+ suggestions.append('State the output format. If code will parse the response as JSON, enforce it with structured outputs instead of describing it in the prompt')
281
255
 
282
256
  if analysis.example_count == 0:
283
257
  suggestions.append('Consider adding 2-3 few-shot examples for consistent outputs')
@@ -289,22 +263,14 @@ def generate_suggestions(analysis: PromptAnalysis) -> List[str]:
289
263
  if analysis.clarity_score < 70:
290
264
  suggestions.append('Improve clarity: replace vague terms with specific instructions')
291
265
 
292
- if analysis.token_count > 2000:
293
- suggestions.append(f'Prompt is {analysis.token_count} tokens - consider condensing for cost efficiency')
294
-
295
- # Check for role prompting
296
- if not re.search(r'you are|act as|as a\s+\w+', analysis.sections[0].get('content', [''])[0] if analysis.sections else '', re.IGNORECASE):
297
- suggestions.append('Consider adding role context: "You are an expert..."')
298
-
299
266
  return suggestions
300
267
 
301
268
 
302
- def analyze_prompt(text: str, model: str = 'gpt-4') -> PromptAnalysis:
269
+ def analyze_prompt(text: str) -> PromptAnalysis:
303
270
  """Perform comprehensive prompt analysis"""
304
271
 
305
272
  # Basic metrics
306
- token_count = estimate_tokens(text, model)
307
- cost = estimate_cost(token_count, model)
273
+ token_count = estimate_tokens(text)
308
274
  word_count = len(text.split())
309
275
  line_count = len(text.split('\n'))
310
276
 
@@ -324,8 +290,6 @@ def analyze_prompt(text: str, model: str = 'gpt-4') -> PromptAnalysis:
324
290
 
325
291
  analysis = PromptAnalysis(
326
292
  token_count=token_count,
327
- estimated_cost=cost,
328
- model=model,
329
293
  clarity_score=clarity_score,
330
294
  structure_score=structure_score,
331
295
  issues=all_issues,
@@ -367,8 +331,7 @@ def format_report(analysis: PromptAnalysis) -> str:
367
331
  report.append("")
368
332
 
369
333
  report.append("📊 METRICS")
370
- report.append(f" Token count: {analysis.token_count:,}")
371
- report.append(f" Estimated cost: ${analysis.estimated_cost:.4f} ({analysis.model})")
334
+ report.append(f" Tokens (approx): {analysis.token_count:,}")
372
335
  report.append(f" Word count: {analysis.word_count:,}")
373
336
  report.append(f" Line count: {analysis.line_count}")
374
337
  report.append("")
@@ -411,13 +374,16 @@ def format_report(analysis: PromptAnalysis) -> str:
411
374
 
412
375
 
413
376
  def main():
377
+ # The report uses emoji; a Windows console defaults to cp1252 and cannot print them.
378
+ if hasattr(sys.stdout, "reconfigure"):
379
+ sys.stdout.reconfigure(encoding="utf-8")
414
380
  parser = argparse.ArgumentParser(
415
381
  description="Prompt Optimizer - Analyze and optimize prompts",
416
382
  formatter_class=argparse.RawDescriptionHelpFormatter,
417
383
  epilog="""
418
384
  Examples:
419
385
  %(prog)s prompt.txt --analyze
420
- %(prog)s prompt.txt --tokens --model claude-3-sonnet
386
+ %(prog)s prompt.txt --tokens
421
387
  %(prog)s prompt.txt --optimize --output optimized.txt
422
388
  %(prog)s prompt.txt --extract-examples --output examples.json
423
389
  """
@@ -428,9 +394,6 @@ Examples:
428
394
  parser.add_argument('--tokens', '-t', action='store_true', help='Count tokens only')
429
395
  parser.add_argument('--optimize', '-O', action='store_true', help='Generate optimized version')
430
396
  parser.add_argument('--extract-examples', '-e', action='store_true', help='Extract few-shot examples')
431
- parser.add_argument('--model', '-m', default='gpt-4',
432
- choices=['gpt-4', 'gpt-4-turbo', 'gpt-3.5-turbo', 'claude-3-opus', 'claude-3-sonnet', 'claude-3-haiku'],
433
- help='Model for token/cost estimation')
434
397
  parser.add_argument('--output', '-o', help='Output file path')
435
398
  parser.add_argument('--json', '-j', action='store_true', help='Output as JSON')
436
399
  parser.add_argument('--compare', '-c', help='Compare with baseline analysis JSON')
@@ -447,17 +410,11 @@ Examples:
447
410
 
448
411
  # Tokens only
449
412
  if args.tokens:
450
- token_count = estimate_tokens(text, args.model)
451
- cost = estimate_cost(token_count, args.model)
413
+ token_count = estimate_tokens(text)
452
414
  if args.json:
453
- print(json.dumps({
454
- 'tokens': token_count,
455
- 'cost': cost,
456
- 'model': args.model
457
- }, indent=2))
415
+ print(json.dumps({'tokens_approx': token_count}, indent=2))
458
416
  else:
459
- print(f"Tokens: {token_count:,}")
460
- print(f"Estimated cost: ${cost:.4f} ({args.model})")
417
+ print(f"Tokens (approx): {token_count:,}")
461
418
  sys.exit(0)
462
419
 
463
420
  # Extract examples
@@ -481,8 +438,8 @@ Examples:
481
438
  print(f"Optimized prompt written to {args.output}")
482
439
 
483
440
  # Show comparison
484
- orig_tokens = estimate_tokens(text, args.model)
485
- new_tokens = estimate_tokens(optimized, args.model)
441
+ orig_tokens = estimate_tokens(text)
442
+ new_tokens = estimate_tokens(optimized)
486
443
  saved = orig_tokens - new_tokens
487
444
  print(f"Tokens: {orig_tokens:,} -> {new_tokens:,} (saved {saved:,})")
488
445
  else:
@@ -490,7 +447,7 @@ Examples:
490
447
  sys.exit(0)
491
448
 
492
449
  # Default: full analysis
493
- analysis = analyze_prompt(text, args.model)
450
+ analysis = analyze_prompt(text)
494
451
 
495
452
  # Compare with baseline
496
453
  if args.compare:
@@ -180,7 +180,7 @@ if (p.x < 1.0 || p.y < 1.0 ||
180
180
  c.xyw *= 0.0;
181
181
  }
182
182
 
183
- // IMPORTANT: Ink decay: must use multiplicative decay; subtractive decay causes saturation in high-concentration areas and overly fast decay in low-concentration areas
183
+ // Ink decay: must use multiplicative decay; subtractive decay causes saturation in high-concentration areas and overly fast decay in low-concentration areas
184
184
  c.w *= 0.995; // 0.5% decay per frame, adjustable [0.99=fast dissipation, 0.999=persistent]
185
185
 
186
186
  // Numerical clamping (prevent explosion)
@@ -199,14 +199,14 @@ void mainImage(out vec4 fragColor, in vec2 fragCoord) {
199
199
  vec2 uv = fragCoord / iResolution.xy;
200
200
  vec4 c = texture(iChannel0, uv);
201
201
 
202
- // IMPORTANT: Color base must be bright enough! 0.5+0.5*cos produces bright colors in [0,1] range
202
+ // Color base must be bright enough! 0.5+0.5*cos produces bright colors in [0,1] range
203
203
  // Never use extremely dark base colors like vec3(0.02, 0.01, 0.08) — multiplied by ink, they become invisible
204
204
  vec3 col = 0.5 + 0.5 * cos(atan(c.y, c.x) + vec3(0.0, 2.1, 4.2));
205
- // IMPORTANT: Use smoothstep instead of linear division to preserve gradient variation
205
+ // Use smoothstep instead of linear division to preserve gradient variation
206
206
  float ink = smoothstep(0.0, 2.0, c.w);
207
207
  col *= ink;
208
208
 
209
- // IMPORTANT: Background color must be visible to the eye (RGB at least > 5/255 ≈ 0.02), otherwise users think the page is all black
209
+ // Background color must be visible to the eye (RGB at least > 5/255 ≈ 0.02), otherwise users think the page is all black
210
210
  col = max(col, vec3(0.02, 0.012, 0.035));
211
211
 
212
212
  fragColor = vec4(col, 1.0);