god-code 0.4.1__tar.gz → 0.5.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 (162) hide show
  1. god_code-0.5.0/AGENTS.md +215 -0
  2. {god_code-0.4.1 → god_code-0.5.0}/CHANGELOG.md +12 -0
  3. {god_code-0.4.1 → god_code-0.5.0}/PKG-INFO +1 -1
  4. {god_code-0.4.1 → god_code-0.5.0}/README.md +21 -0
  5. god_code-0.5.0/godot_agent/agents/__init__.py +12 -0
  6. god_code-0.5.0/godot_agent/agents/configs.py +80 -0
  7. god_code-0.5.0/godot_agent/agents/dispatcher.py +152 -0
  8. god_code-0.5.0/godot_agent/agents/results.py +15 -0
  9. god_code-0.5.0/godot_agent/cli.py +1068 -0
  10. god_code-0.5.0/godot_agent/godot/impact_analysis.py +148 -0
  11. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/scene_writer.py +3 -0
  12. god_code-0.5.0/godot_agent/llm/adapters/__init__.py +21 -0
  13. god_code-0.5.0/godot_agent/llm/adapters/anthropic.py +22 -0
  14. god_code-0.5.0/godot_agent/llm/adapters/base.py +31 -0
  15. god_code-0.5.0/godot_agent/llm/adapters/openai.py +32 -0
  16. god_code-0.5.0/godot_agent/llm/client.py +98 -0
  17. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/llm/streaming.py +2 -2
  18. god_code-0.5.0/godot_agent/llm/types.py +175 -0
  19. god_code-0.5.0/godot_agent/prompts/assembler.py +184 -0
  20. god_code-0.5.0/godot_agent/prompts/image_templates.py +102 -0
  21. god_code-0.5.0/godot_agent/prompts/system.py +59 -0
  22. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/runtime/config.py +15 -2
  23. god_code-0.5.0/godot_agent/runtime/context_manager.py +231 -0
  24. god_code-0.5.0/godot_agent/runtime/design_memory.py +140 -0
  25. god_code-0.5.0/godot_agent/runtime/engine.py +710 -0
  26. god_code-0.5.0/godot_agent/runtime/events.py +11 -0
  27. god_code-0.5.0/godot_agent/runtime/gameplay_reviewer.py +132 -0
  28. god_code-0.5.0/godot_agent/runtime/modes.py +132 -0
  29. god_code-0.5.0/godot_agent/runtime/playtest_harness.py +142 -0
  30. god_code-0.5.0/godot_agent/runtime/providers.py +165 -0
  31. god_code-0.5.0/godot_agent/runtime/quality_gate.py +316 -0
  32. god_code-0.5.0/godot_agent/runtime/reviewer.py +228 -0
  33. god_code-0.5.0/godot_agent/runtime/runtime_bridge.py +74 -0
  34. god_code-0.5.0/godot_agent/runtime/scenario_specs/hud_feedback.json +7 -0
  35. god_code-0.5.0/godot_agent/runtime/scenario_specs/player_movement.json +8 -0
  36. god_code-0.5.0/godot_agent/runtime/scenario_specs/scene_transition.json +7 -0
  37. god_code-0.5.0/godot_agent/runtime/session.py +132 -0
  38. god_code-0.5.0/godot_agent/security/__init__.py +1 -0
  39. god_code-0.5.0/godot_agent/security/classifier.py +87 -0
  40. god_code-0.5.0/godot_agent/security/hooks.py +140 -0
  41. god_code-0.5.0/godot_agent/security/policies.py +89 -0
  42. god_code-0.5.0/godot_agent/security/protected_paths.py +47 -0
  43. god_code-0.5.0/godot_agent/security/tool_pipeline.py +89 -0
  44. god_code-0.5.0/godot_agent/testing/__init__.py +1 -0
  45. god_code-0.5.0/godot_agent/testing/scenario_runner.py +41 -0
  46. god_code-0.5.0/godot_agent/tools/analysis_tools.py +157 -0
  47. god_code-0.5.0/godot_agent/tools/base.py +54 -0
  48. god_code-0.5.0/godot_agent/tools/editor_bridge.py +79 -0
  49. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/file_ops.py +18 -0
  50. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/git.py +10 -1
  51. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/godot_cli.py +12 -1
  52. god_code-0.5.0/godot_agent/tools/image_gen.py +180 -0
  53. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/list_dir.py +10 -3
  54. god_code-0.5.0/godot_agent/tools/memory_tool.py +78 -0
  55. god_code-0.5.0/godot_agent/tools/registry.py +61 -0
  56. god_code-0.5.0/godot_agent/tools/scene_tools.py +271 -0
  57. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/screenshot.py +11 -1
  58. god_code-0.5.0/godot_agent/tools/script_tools.py +136 -0
  59. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/search.py +19 -2
  60. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/shell.py +6 -1
  61. god_code-0.5.0/godot_agent/tools/web_search.py +89 -0
  62. god_code-0.5.0/godot_agent/tui/display.py +426 -0
  63. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tui/input_handler.py +65 -11
  64. {god_code-0.4.1 → god_code-0.5.0}/pyproject.toml +1 -1
  65. god_code-0.5.0/tests/agents/test_dispatcher.py +97 -0
  66. god_code-0.5.0/tests/agents/test_playtest_analyst.py +37 -0
  67. god_code-0.5.0/tests/e2e/test_planner_worker_reviewer_flow.py +136 -0
  68. god_code-0.5.0/tests/e2e/test_policy_enforcement.py +112 -0
  69. god_code-0.5.0/tests/e2e/test_scenario_runner.py +16 -0
  70. god_code-0.5.0/tests/godot/test_impact_analysis.py +39 -0
  71. god_code-0.5.0/tests/llm/test_adapters.py +37 -0
  72. {god_code-0.4.1 → god_code-0.5.0}/tests/llm/test_client.py +67 -2
  73. god_code-0.5.0/tests/prompts/test_prompt_assembler.py +66 -0
  74. {god_code-0.4.1 → god_code-0.5.0}/tests/prompts/test_system_prompt.py +5 -0
  75. {god_code-0.4.1 → god_code-0.5.0}/tests/runtime/test_config.py +26 -4
  76. {god_code-0.4.1 → god_code-0.5.0}/tests/runtime/test_context_manager.py +6 -3
  77. god_code-0.5.0/tests/runtime/test_design_memory.py +48 -0
  78. {god_code-0.4.1 → god_code-0.5.0}/tests/runtime/test_engine.py +44 -0
  79. god_code-0.5.0/tests/runtime/test_gameplay_reviewer.py +32 -0
  80. god_code-0.5.0/tests/runtime/test_mode_restrictions.py +105 -0
  81. god_code-0.5.0/tests/runtime/test_multi_agent_flow.py +152 -0
  82. god_code-0.5.0/tests/runtime/test_playtest_harness.py +28 -0
  83. god_code-0.5.0/tests/runtime/test_quality_gate.py +37 -0
  84. god_code-0.5.0/tests/runtime/test_reviewer.py +50 -0
  85. god_code-0.5.0/tests/runtime/test_runtime_bridge.py +30 -0
  86. god_code-0.5.0/tests/runtime/test_session.py +63 -0
  87. god_code-0.5.0/tests/security/test_classifier.py +42 -0
  88. god_code-0.5.0/tests/security/test_hooks.py +122 -0
  89. god_code-0.5.0/tests/security/test_permissions.py +104 -0
  90. god_code-0.5.0/tests/security/test_tool_pipeline.py +121 -0
  91. {god_code-0.4.1 → god_code-0.5.0}/tests/test_e2e.py +2 -0
  92. god_code-0.5.0/tests/test_runtime_switch_commands.py +26 -0
  93. god_code-0.5.0/tests/tools/test_analysis_tools.py +47 -0
  94. god_code-0.5.0/tests/tools/test_editor_bridge.py +46 -0
  95. god_code-0.5.0/tests/tools/test_memory_tool.py +19 -0
  96. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/test_registry.py +5 -0
  97. god_code-0.5.0/tests/tools/test_scene_tools.py +66 -0
  98. god_code-0.5.0/tests/tools/test_script_tools.py +47 -0
  99. god_code-0.5.0/tests/tui/test_input_handler.py +19 -0
  100. god_code-0.4.1/godot_agent/cli.py +0 -602
  101. god_code-0.4.1/godot_agent/llm/client.py +0 -189
  102. god_code-0.4.1/godot_agent/prompts/system.py +0 -114
  103. god_code-0.4.1/godot_agent/runtime/context_manager.py +0 -135
  104. god_code-0.4.1/godot_agent/runtime/engine.py +0 -234
  105. god_code-0.4.1/godot_agent/runtime/session.py +0 -58
  106. god_code-0.4.1/godot_agent/tools/base.py +0 -30
  107. god_code-0.4.1/godot_agent/tools/registry.py +0 -29
  108. god_code-0.4.1/godot_agent/tui/display.py +0 -190
  109. {god_code-0.4.1 → god_code-0.5.0}/.github/workflows/publish.yml +0 -0
  110. {god_code-0.4.1 → god_code-0.5.0}/.gitignore +0 -0
  111. {god_code-0.4.1 → god_code-0.5.0}/CLAUDE.md +0 -0
  112. {god_code-0.4.1 → god_code-0.5.0}/CONTRIBUTING.md +0 -0
  113. {god_code-0.4.1 → god_code-0.5.0}/LICENSE +0 -0
  114. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/__init__.py +0 -0
  115. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/__init__.py +0 -0
  116. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/collision_planner.py +0 -0
  117. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/consistency_checker.py +0 -0
  118. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/dependency_graph.py +0 -0
  119. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/gdscript_linter.py +0 -0
  120. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/pattern_advisor.py +0 -0
  121. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/project.py +0 -0
  122. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/resource_validator.py +0 -0
  123. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/scene_parser.py +0 -0
  124. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/godot/tscn_validator.py +0 -0
  125. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/llm/__init__.py +0 -0
  126. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/llm/vision.py +0 -0
  127. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/prompts/__init__.py +0 -0
  128. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/prompts/build_discipline.py +0 -0
  129. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/prompts/godot_playbook.py +0 -0
  130. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/prompts/knowledge_selector.py +0 -0
  131. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/py.typed +0 -0
  132. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/runtime/__init__.py +0 -0
  133. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/runtime/auth.py +0 -0
  134. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/runtime/error_loop.py +0 -0
  135. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/runtime/oauth.py +0 -0
  136. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tools/__init__.py +0 -0
  137. {god_code-0.4.1 → god_code-0.5.0}/godot_agent/tui/__init__.py +0 -0
  138. {god_code-0.4.1 → god_code-0.5.0}/tests/__init__.py +0 -0
  139. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/__init__.py +0 -0
  140. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_collision_planner.py +0 -0
  141. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_consistency.py +0 -0
  142. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_dependency_graph.py +0 -0
  143. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_linter.py +0 -0
  144. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_pattern_advisor.py +0 -0
  145. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_project.py +0 -0
  146. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_resource_validator.py +0 -0
  147. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_scene_parser.py +0 -0
  148. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_scene_writer.py +0 -0
  149. {god_code-0.4.1 → god_code-0.5.0}/tests/godot/test_tscn_validator.py +0 -0
  150. {god_code-0.4.1 → god_code-0.5.0}/tests/llm/__init__.py +0 -0
  151. {god_code-0.4.1 → god_code-0.5.0}/tests/llm/test_vision.py +0 -0
  152. {god_code-0.4.1 → god_code-0.5.0}/tests/prompts/__init__.py +0 -0
  153. {god_code-0.4.1 → god_code-0.5.0}/tests/prompts/test_knowledge_selector.py +0 -0
  154. {god_code-0.4.1 → god_code-0.5.0}/tests/runtime/__init__.py +0 -0
  155. {god_code-0.4.1 → god_code-0.5.0}/tests/runtime/test_error_loop.py +0 -0
  156. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/__init__.py +0 -0
  157. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/test_file_ops.py +0 -0
  158. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/test_git.py +0 -0
  159. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/test_godot_cli.py +0 -0
  160. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/test_list_dir.py +0 -0
  161. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/test_search.py +0 -0
  162. {god_code-0.4.1 → god_code-0.5.0}/tests/tools/test_shell.py +0 -0
@@ -0,0 +1,215 @@
1
+ # AGENTS.md — God Code Development Guide
2
+
3
+ > AI coding agent specialized for Godot 4.4 game development. This file guides Codex when working on the god-code codebase itself.
4
+
5
+ ## Project Identity
6
+
7
+ **god-code** — a Python CLI agent that understands GDScript, .tscn scenes, collision layers, and Godot architecture patterns. It calls LLM APIs with Godot-specific tools and enforces incremental build-and-verify discipline.
8
+
9
+ **PyPI**: `pip install god-code`
10
+ **GitHub**: https://github.com/888wing/god-code
11
+ **License**: GPL-3.0
12
+
13
+ ## Tech Stack
14
+
15
+ - **Language**: Python 3.12+
16
+ - **CLI**: click
17
+ - **HTTP**: httpx (async)
18
+ - **Models**: pydantic v2 (tool schemas, config)
19
+ - **Image**: Pillow (screenshot encoding)
20
+ - **Test**: pytest + pytest-asyncio
21
+ - **Build**: hatchling
22
+ - **CI**: GitHub Actions (auto-publish to PyPI on tag)
23
+
24
+ ## Current Version: 0.1.0
25
+
26
+ **Completed**: CLI (ask/chat/info/setup/login/logout/status), 10 tools, LLM client with OpenAI-compatible API, Godot Playbook knowledge system (17 sections), .tscn parser/writer/validator, GDScript linter, collision planner, dependency graph, pattern advisor, consistency checker, error loop, context manager, first-run setup wizard, PyPI published.
27
+
28
+ **157 tests**, ~4,000 lines production code.
29
+
30
+ ## Architecture
31
+
32
+ ```
33
+ godot_agent/
34
+ ├── cli.py # Click CLI entry point + setup wizard
35
+ ├── runtime/
36
+ │ ├── engine.py # Conversation loop (tool calling + context compaction + error loop)
37
+ │ ├── config.py # AgentConfig (pydantic) + load from file/env
38
+ │ ├── session.py # Session persistence (.agent_sessions/*.json)
39
+ │ ├── oauth.py # Codex refresh token flow
40
+ │ ├── error_loop.py # Godot output parsing + fix suggestions
41
+ │ ├── context_manager.py # Message compaction + file relevance scoring
42
+ │ └── auth.py # AuthContext dataclass
43
+ ├── llm/
44
+ │ ├── client.py # LLMClient (OpenAI-compatible, retry, content filter handling)
45
+ │ ├── streaming.py # SSE streaming
46
+ │ └── vision.py # Image → base64 encoding
47
+ ├── tools/ # 10 function-calling tools
48
+ │ ├── base.py # BaseTool ABC + ToolResult
49
+ │ ├── registry.py # ToolRegistry (register, execute, to_openai_tools)
50
+ │ ├── file_ops.py # read_file, write_file, edit_file (path-contained)
51
+ │ ├── search.py # grep, glob
52
+ │ ├── list_dir.py # list_dir
53
+ │ ├── git.py # git (shlex-parsed)
54
+ │ ├── shell.py # run_shell (blocked patterns)
55
+ │ ├── godot_cli.py # run_godot (GUT, validate, output parser)
56
+ │ └── screenshot.py # screenshot_scene (headless)
57
+ ├── godot/ # Godot-specific analysis
58
+ │ ├── project.py # project.godot parser → GodotProject
59
+ │ ├── scene_parser.py # .tscn → TscnScene (nodes, resources, connections)
60
+ │ ├── scene_writer.py # add_node, set_property, remove_node, add_connection
61
+ │ ├── tscn_validator.py # Format validation + auto-fix ordering
62
+ │ ├── gdscript_linter.py # Naming, ordering, type annotations, anti-patterns
63
+ │ ├── collision_planner.py # Standard 8-layer scheme
64
+ │ ├── consistency_checker.py # Cross-file collision/signal/resource/group checks
65
+ │ ├── dependency_graph.py # Project-wide scene→script→resource graph
66
+ │ ├── pattern_advisor.py # Object pool, component, state machine suggestions
67
+ │ └── resource_validator.py # res:// path existence check
68
+ └── prompts/
69
+ ├── system.py # Builds system prompt (identity + knowledge + discipline + context)
70
+ ├── godot_playbook.py # 17 indexed knowledge sections
71
+ ├── knowledge_selector.py # Context-aware section scoring + injection
72
+ └── build_discipline.py # Incremental build-and-verify rules
73
+ ```
74
+
75
+ ## Key Patterns
76
+
77
+ ### Tool System
78
+ Every tool inherits `BaseTool` with pydantic `Input`/`Output` models. The registry auto-generates OpenAI function calling schemas.
79
+
80
+ ```python
81
+ class MyTool(BaseTool):
82
+ name = "my_tool"
83
+ description = "Does something"
84
+ class Input(BaseModel):
85
+ param: str = Field(description="...")
86
+ class Output(BaseModel):
87
+ result: str
88
+ async def execute(self, input: Input) -> ToolResult:
89
+ return ToolResult(output=self.Output(result="done"))
90
+ ```
91
+
92
+ Register in `cli.py:build_registry()`.
93
+
94
+ ### Path Containment
95
+ `file_ops.py` has a module-level `_project_root` set by CLI on startup. All read/write/edit operations validate paths are within project root. `set_project_root()` is called in `build_engine()`.
96
+
97
+ ### Engine Flow
98
+ ```
99
+ user message → _maybe_compact() → client.chat() → tool_calls?
100
+ → yes: execute tools → _post_tool_validate() → loop
101
+ → no: return content
102
+ ```
103
+ - Compaction triggers at ~80K estimated tokens
104
+ - Post-tool validation runs `godot --headless --quit` after write_file/edit_file
105
+ - Max tool rounds default: 20
106
+
107
+ ### Knowledge Injection
108
+ `knowledge_selector.py` scores Playbook sections by keyword overlap with user prompt + file extensions. Top 4 sections injected (~2K tokens instead of full ~15K).
109
+
110
+ ### Error Loop Integration
111
+ After any file-mutating tool call, engine runs Godot headless validation. If errors found, injects a system message telling the LLM to fix them before proceeding.
112
+
113
+ ## Development Rules
114
+
115
+ ### CRITICAL: Read Before Modify
116
+ Never modify files without reading them first. This applies to both god-code source AND Godot project files the agent operates on.
117
+
118
+ ### Adding a New Tool
119
+ 1. Create `godot_agent/tools/your_tool.py` inheriting `BaseTool`
120
+ 2. Define `Input` and `Output` as pydantic `BaseModel`
121
+ 3. Implement `async execute()`
122
+ 4. Register in `cli.py:build_registry()`
123
+ 5. Add tests in `tests/tools/test_your_tool.py`
124
+ 6. Update README tool list
125
+
126
+ ### Adding Godot Knowledge
127
+ Edit `godot_agent/prompts/godot_playbook.py`:
128
+ - Each section: `(title, [keywords], content_string)`
129
+ - Keywords drive auto-selection in `knowledge_selector.py`
130
+ - Keep sections concise (~200 tokens each)
131
+
132
+ ### Adding Godot Analysis
133
+ New analyzers go in `godot_agent/godot/`. Follow existing patterns:
134
+ - Pure functions, no side effects
135
+ - Return structured dataclasses
136
+ - Include `format_*()` for LLM-readable output
137
+
138
+ ### Config
139
+ `~/.config/god-code/config.json` with `GODOT_AGENT_*` env overrides:
140
+
141
+ | Field | Default | Env Var |
142
+ |-------|---------|---------|
143
+ | api_key | "" | GODOT_AGENT_API_KEY |
144
+ | base_url | https://api.openai.com/v1 | GODOT_AGENT_BASE_URL |
145
+ | model | gpt-5.4 | GODOT_AGENT_MODEL |
146
+ | godot_path | godot | GODOT_AGENT_GODOT_PATH |
147
+ | oauth_token | null | GODOT_AGENT_OAUTH_TOKEN |
148
+
149
+ OAuth client_id configurable via `GODOT_AGENT_OAUTH_CLIENT_ID`.
150
+
151
+ ## Testing
152
+
153
+ ```bash
154
+ # Full suite (157 tests)
155
+ python -m pytest tests/ -v
156
+
157
+ # Specific module
158
+ python -m pytest tests/godot/test_tscn_validator.py -v
159
+
160
+ # E2E with mocked LLM
161
+ python -m pytest tests/test_e2e.py -v
162
+ ```
163
+
164
+ All tests use `tmp_path` fixture for isolation. LLM tests mock `httpx` responses. No real API calls in tests.
165
+
166
+ ## Release Process
167
+
168
+ Automated via GitHub Actions:
169
+
170
+ ```bash
171
+ # 1. Bump version in pyproject.toml
172
+ # 2. Commit + tag
173
+ git commit -am "release: v0.2.0"
174
+ git tag v0.2.0
175
+ git push && git push --tags
176
+ # → GitHub Actions runs tests → publishes to PyPI
177
+ ```
178
+
179
+ Requires `PYPI_API_TOKEN` in GitHub repo secrets.
180
+
181
+ ## Security Model
182
+
183
+ - **File ops**: Restricted to project root (symlink-aware)
184
+ - **Shell**: Blocked patterns (rm -rf /, sudo, curl|sh, etc.)
185
+ - **Git**: shlex.split() for proper argument parsing
186
+ - **API keys**: Stored with 600 permissions, masked in CLI output
187
+ - **Content filter**: 400 errors retried, graceful fallback message
188
+
189
+ ## Roadmap
190
+
191
+ ### Phase 2: Editor Plugin Bridge
192
+ - Godot EditorPlugin with WebSocket server
193
+ - `editor_bridge.py` Python WebSocket client
194
+ - Tier 1 operations: scene tree, properties, signals, run/stop game
195
+ - Live viewport screenshots from editor
196
+
197
+ ### Phase 3: Hosted API
198
+ - Cloudflare Worker proxy with Google OAuth
199
+ - Free tier (50 req/day, gpt-4o-mini)
200
+ - Pro tier ($12/mo, gpt-5.4 + vision)
201
+ - Small model routing for simple tasks
202
+ - Prompt caching for session continuity
203
+
204
+ ## Key Files
205
+
206
+ | File | Purpose |
207
+ |------|---------|
208
+ | `pyproject.toml` | Package metadata, version, dependencies |
209
+ | `CHANGELOG.md` | Version history |
210
+ | `README.md` | User-facing documentation |
211
+ | `CONTRIBUTING.md` | Contributor guide |
212
+ | `.github/workflows/publish.yml` | Auto-publish to PyPI on tag |
213
+ | `godot_agent/cli.py` | CLI commands + setup wizard |
214
+ | `godot_agent/runtime/engine.py` | Core conversation loop |
215
+ | `godot_agent/prompts/godot_playbook.py` | Godot knowledge base |
@@ -2,6 +2,18 @@
2
2
 
3
3
  All notable changes to God Code will be documented in this file.
4
4
 
5
+ ## [Unreleased]
6
+
7
+ ### Added
8
+ - Workspace-style chat TUI with session snapshot, recent activity, and live streaming panels
9
+ - Interaction modes (`apply`, `plan`, `explain`, `review`, `fix`) with mode-aware tool availability
10
+ - Autosaved session metadata with `/sessions`, `/resume`, `/new`, and project-aware restore flow
11
+
12
+ ### Changed
13
+ - Unified `ask` and `chat` rendering pipeline, including tool progress and validation feedback
14
+ - Improved post-tool validation visibility and tool result summaries in interactive sessions
15
+ - Session persistence now preserves assistant tool calls and richer metadata for restore
16
+
5
17
  ## [0.1.0] - 2026-04-02
6
18
 
7
19
  ### Added
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: god-code
3
- Version: 0.4.1
3
+ Version: 0.5.0
4
4
  Summary: AI coding agent specialized for Godot game development
5
5
  Project-URL: Homepage, https://github.com/chuisiufai/god-code
6
6
  Project-URL: Repository, https://github.com/chuisiufai/god-code
@@ -5,6 +5,9 @@ AI coding agent specialized for Godot 4.4 game development. Unlike generic codin
5
5
  ## Features
6
6
 
7
7
  - **10 tools**: read/write/edit files, grep/glob search, git, shell, Godot headless runner, screenshot capture
8
+ - **Workspace-style chat TUI**: session snapshot, recent activity timeline, live tool feedback, and validation visibility
9
+ - **Interaction modes**: `apply`, `plan`, `explain`, `review`, and `fix` with mode-aware prompts and tool access
10
+ - **Session recovery**: autosave, `/sessions`, `/resume`, and project-aware session metadata
8
11
  - **Godot-native understanding**: project.godot parser, .tscn scene parser/writer/validator, collision layer planner
9
12
  - **Code quality**: GDScript linter (naming, ordering, type annotations), cross-file consistency checker, design pattern advisor
10
13
  - **Smart knowledge injection**: 17 Godot Playbook sections auto-selected by task context
@@ -52,6 +55,9 @@ EOF
52
55
  # Single prompt
53
56
  god-code ask "Add a health bar to the player scene" --project ./my-game
54
57
 
58
+ # Script-friendly plain output
59
+ god-code ask "Summarize this project" --project ./my-game --plain
60
+
55
61
  # Interactive chat
56
62
  god-code chat --project ./my-game
57
63
 
@@ -108,9 +114,14 @@ god-code logout # Removes stored credentials
108
114
  "base_url": "https://api.openai.com/v1",
109
115
  "model": "gpt-5.4",
110
116
  "oauth_token": null,
117
+ "mode": "apply",
111
118
  "max_turns": 20,
112
119
  "max_tokens": 4096,
113
120
  "temperature": 0.0,
121
+ "auto_validate": true,
122
+ "auto_commit": false,
123
+ "streaming": true,
124
+ "autosave_session": true,
114
125
  "screenshot_max_iterations": 5,
115
126
  "godot_path": "godot",
116
127
  "session_dir": ".agent_sessions"
@@ -119,6 +130,16 @@ god-code logout # Removes stored credentials
119
130
 
120
131
  All fields can be overridden with `GODOT_AGENT_` prefixed environment variables.
121
132
 
133
+ ## Chat Commands
134
+
135
+ Interactive chat supports:
136
+
137
+ - `/mode [apply|plan|explain|review|fix]`
138
+ - `/sessions` and `/resume [session-id]`
139
+ - `/new` to start a fresh session
140
+ - `/workspace` to re-render the session snapshot
141
+ - `/set <key> <value>` for live configuration changes
142
+
122
143
  ## System Prompt & Output Quality
123
144
 
124
145
  God Code's system prompt is dynamically assembled from:
@@ -0,0 +1,12 @@
1
+ """Multi-agent orchestration primitives for God Code."""
2
+
3
+ from godot_agent.agents.configs import AGENT_CONFIGS, AgentConfig
4
+ from godot_agent.agents.dispatcher import AgentDispatcher
5
+ from godot_agent.agents.results import AgentTaskResult
6
+
7
+ __all__ = [
8
+ "AGENT_CONFIGS",
9
+ "AgentConfig",
10
+ "AgentDispatcher",
11
+ "AgentTaskResult",
12
+ ]
@@ -0,0 +1,80 @@
1
+ """Built-in role configurations for multi-agent orchestration."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass
6
+
7
+ from godot_agent.runtime.modes import allowed_tools_for_mode
8
+
9
+
10
+ @dataclass(frozen=True)
11
+ class AgentConfig:
12
+ name: str
13
+ mode: str
14
+ prompt: str
15
+ allowed_tools: set[str]
16
+ auto_validate: bool = False
17
+ max_tool_rounds: int = 8
18
+
19
+
20
+ _READ_ONLY_TOOLS = allowed_tools_for_mode("plan")
21
+ _WORKER_TOOLS = allowed_tools_for_mode("apply")
22
+
23
+
24
+ AGENT_CONFIGS: dict[str, AgentConfig] = {
25
+ "planner": AgentConfig(
26
+ name="planner",
27
+ mode="plan",
28
+ prompt=(
29
+ "You are the Planner agent. Inspect the project and produce a concrete implementation plan, "
30
+ "risks, and validation strategy. Do not edit files."
31
+ ),
32
+ allowed_tools=set(_READ_ONLY_TOOLS),
33
+ auto_validate=False,
34
+ max_tool_rounds=6,
35
+ ),
36
+ "explorer": AgentConfig(
37
+ name="explorer",
38
+ mode="review",
39
+ prompt=(
40
+ "You are the Explorer agent. Read the project, map the relevant scripts/scenes/resources, "
41
+ "and return concise findings. Do not edit files."
42
+ ),
43
+ allowed_tools=set(_READ_ONLY_TOOLS),
44
+ auto_validate=False,
45
+ max_tool_rounds=6,
46
+ ),
47
+ "worker": AgentConfig(
48
+ name="worker",
49
+ mode="apply",
50
+ prompt=(
51
+ "You are the Worker agent. Implement the requested change with the smallest viable edit, "
52
+ "then rely on validation and reviewer feedback to converge."
53
+ ),
54
+ allowed_tools=set(_WORKER_TOOLS),
55
+ auto_validate=True,
56
+ max_tool_rounds=12,
57
+ ),
58
+ "reviewer": AgentConfig(
59
+ name="reviewer",
60
+ mode="review",
61
+ prompt=(
62
+ "You are the Reviewer agent. Validate the changes adversarially and report concrete findings. "
63
+ "Do not edit files."
64
+ ),
65
+ allowed_tools=set(_READ_ONLY_TOOLS),
66
+ auto_validate=False,
67
+ max_tool_rounds=4,
68
+ ),
69
+ "playtest_analyst": AgentConfig(
70
+ name="playtest_analyst",
71
+ mode="review",
72
+ prompt=(
73
+ "You are the Playtest Analyst agent. Evaluate runtime evidence and scenario-based playtest output, "
74
+ "then explain whether the gameplay intent still holds."
75
+ ),
76
+ allowed_tools=set(_READ_ONLY_TOOLS),
77
+ auto_validate=False,
78
+ max_tool_rounds=4,
79
+ ),
80
+ }
@@ -0,0 +1,152 @@
1
+ """Synchronous multi-agent dispatcher."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import replace
6
+ from pathlib import Path
7
+
8
+ from godot_agent.godot.impact_analysis import format_impact_report, infer_request_impact
9
+ from godot_agent.agents.configs import AGENT_CONFIGS, AgentConfig
10
+ from godot_agent.agents.results import AgentTaskResult
11
+ from godot_agent.llm.client import LLMClient
12
+ from godot_agent.prompts.assembler import PromptAssembler, PromptContext
13
+ from godot_agent.runtime.engine import ConversationEngine
14
+ from godot_agent.runtime.playtest_harness import format_playtest_report, run_playtest_harness
15
+ from godot_agent.runtime.quality_gate import QualityGateReport
16
+ from godot_agent.runtime.runtime_bridge import get_runtime_snapshot
17
+ from godot_agent.runtime.reviewer import format_review_report, review_changes
18
+ from godot_agent.tools.registry import ToolRegistry
19
+
20
+
21
+ class AgentDispatcher:
22
+ """Creates role-scoped engines and deterministic review passes."""
23
+
24
+ def __init__(
25
+ self,
26
+ *,
27
+ client: LLMClient,
28
+ registry: ToolRegistry,
29
+ prompt_context: PromptContext | None,
30
+ project_path: str | None,
31
+ godot_path: str = "godot",
32
+ base_allowed_tools: set[str] | None = None,
33
+ ) -> None:
34
+ self.client = client
35
+ self.registry = registry
36
+ self.prompt_context = prompt_context
37
+ self.project_path = project_path
38
+ self.godot_path = godot_path
39
+ self.base_allowed_tools = set(base_allowed_tools) if base_allowed_tools is not None else None
40
+
41
+ def _clone_registry(self) -> ToolRegistry:
42
+ cloned = ToolRegistry()
43
+ for tool in self.registry.list_tools():
44
+ cloned.register(tool)
45
+ return cloned
46
+
47
+ def resolve_allowed_tools(self, role: str) -> set[str]:
48
+ config = AGENT_CONFIGS[role]
49
+ if self.base_allowed_tools is None:
50
+ return set(config.allowed_tools)
51
+ return set(config.allowed_tools & self.base_allowed_tools)
52
+
53
+ def _build_prompt_assembler(self, config: AgentConfig) -> PromptAssembler | None:
54
+ if self.prompt_context is None:
55
+ return None
56
+ context = replace(
57
+ self.prompt_context,
58
+ mode=config.mode,
59
+ extra_prompt="\n\n".join(
60
+ section for section in [self.prompt_context.extra_prompt, config.prompt] if section
61
+ ),
62
+ )
63
+ return PromptAssembler(context)
64
+
65
+ def _build_engine(self, config: AgentConfig, *, user_hint: str) -> ConversationEngine:
66
+ registry = self._clone_registry()
67
+ prompt_assembler = self._build_prompt_assembler(config)
68
+ allowed_tools = self.resolve_allowed_tools(config.name)
69
+ if prompt_assembler is not None:
70
+ system_prompt = prompt_assembler.build(
71
+ user_hint=user_hint,
72
+ active_tools=[tool.name for tool in registry.list_tools() if tool.name in allowed_tools],
73
+ )
74
+ else:
75
+ system_prompt = config.prompt
76
+
77
+ engine = ConversationEngine(
78
+ client=self.client,
79
+ registry=registry,
80
+ system_prompt=system_prompt,
81
+ max_tool_rounds=config.max_tool_rounds,
82
+ project_path=self.project_path,
83
+ godot_path=self.godot_path,
84
+ auto_validate=config.auto_validate,
85
+ prompt_assembler=prompt_assembler,
86
+ mode=config.mode,
87
+ )
88
+ engine.allowed_tools = allowed_tools
89
+ return engine
90
+
91
+ async def run_planner(self, task: str) -> AgentTaskResult:
92
+ config = AGENT_CONFIGS["planner"]
93
+ engine = self._build_engine(config, user_hint=task)
94
+ planning_prompt = task
95
+ if self.project_path:
96
+ impact_report = infer_request_impact(Path(self.project_path), task)
97
+ planning_prompt = f"{task}\n\nLikely impact before implementation:\n{format_impact_report(impact_report)}"
98
+ content = await engine.submit(planning_prompt)
99
+ return AgentTaskResult(
100
+ role=config.name,
101
+ content=content,
102
+ used_tools=engine.last_turn.tools_called if engine.last_turn else [],
103
+ )
104
+
105
+ async def run_worker(self, task: str, *, plan: str = "") -> AgentTaskResult:
106
+ config = AGENT_CONFIGS["worker"]
107
+ prompt = task if not plan else f"{task}\n\nApproved plan:\n{plan}"
108
+ engine = self._build_engine(config, user_hint=task)
109
+ content = await engine.submit(prompt)
110
+ verdict = "FAIL" if engine.last_review_report and engine.last_review_report.requires_fix else "PASS"
111
+ return AgentTaskResult(
112
+ role=config.name,
113
+ content=content,
114
+ verdict=verdict,
115
+ used_tools=engine.last_turn.tools_called if engine.last_turn else [],
116
+ )
117
+
118
+ async def run_reviewer(
119
+ self,
120
+ *,
121
+ changed_files: set[str],
122
+ quality_report: QualityGateReport | None = None,
123
+ ) -> AgentTaskResult:
124
+ if not self.project_path:
125
+ return AgentTaskResult(role="reviewer", verdict="PASS", content="No project path configured.")
126
+ report = await review_changes(
127
+ project_root=Path(self.project_path),
128
+ changed_files=changed_files,
129
+ godot_path=self.godot_path,
130
+ quality_report=quality_report,
131
+ )
132
+ return AgentTaskResult(
133
+ role="reviewer",
134
+ content=format_review_report(report),
135
+ verdict=report.verdict,
136
+ raw=report,
137
+ )
138
+
139
+ async def run_playtest_analyst(self, *, changed_files: set[str]) -> AgentTaskResult:
140
+ if not self.project_path:
141
+ return AgentTaskResult(role="playtest_analyst", verdict="PASS", content="No project path configured.")
142
+ report = run_playtest_harness(
143
+ project_root=Path(self.project_path),
144
+ changed_files=changed_files,
145
+ runtime_snapshot=get_runtime_snapshot(),
146
+ )
147
+ return AgentTaskResult(
148
+ role="playtest_analyst",
149
+ content=format_playtest_report(report),
150
+ verdict=report.verdict,
151
+ raw=report,
152
+ )
@@ -0,0 +1,15 @@
1
+ """Structured results for sub-agent execution."""
2
+
3
+ from __future__ import annotations
4
+
5
+ from dataclasses import dataclass, field
6
+
7
+
8
+ @dataclass
9
+ class AgentTaskResult:
10
+ role: str
11
+ content: str = ""
12
+ verdict: str = "PASS"
13
+ notes: list[str] = field(default_factory=list)
14
+ used_tools: list[str] = field(default_factory=list)
15
+ raw: object | None = None