gemcode 0.3.105__tar.gz → 0.3.107__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 (164) hide show
  1. {gemcode-0.3.105/src/gemcode.egg-info → gemcode-0.3.107}/PKG-INFO +40 -1
  2. {gemcode-0.3.105 → gemcode-0.3.107}/README.md +39 -0
  3. {gemcode-0.3.105 → gemcode-0.3.107}/pyproject.toml +1 -1
  4. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/agent.py +9 -2
  5. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/cli.py +29 -4
  6. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/config.py +25 -0
  7. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/invoke.py +184 -4
  8. gemcode-0.3.107/src/gemcode/kaira_client.py +51 -0
  9. gemcode-0.3.107/src/gemcode/kaira_daemon.py +657 -0
  10. gemcode-0.3.107/src/gemcode/kaira_ipc.py +289 -0
  11. gemcode-0.3.107/src/gemcode/kaira_job_store.py +157 -0
  12. gemcode-0.3.107/src/gemcode/org.py +296 -0
  13. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/repl_commands.py +5 -0
  14. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/repl_slash.py +311 -0
  15. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tool_prompt_manifest.py +9 -1
  16. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/__init__.py +8 -1
  17. gemcode-0.3.107/src/gemcode/tools/org_tools.py +158 -0
  18. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/subtask.py +48 -2
  19. gemcode-0.3.107/src/gemcode/tools/user_choice.py +58 -0
  20. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tui/scrollback.py +327 -12
  21. {gemcode-0.3.105 → gemcode-0.3.107/src/gemcode.egg-info}/PKG-INFO +40 -1
  22. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode.egg-info/SOURCES.txt +6 -0
  23. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_multimodal_input.py +3 -1
  24. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_tools.py +5 -1
  25. gemcode-0.3.105/src/gemcode/kaira_daemon.py +0 -221
  26. {gemcode-0.3.105 → gemcode-0.3.107}/LICENSE +0 -0
  27. {gemcode-0.3.105 → gemcode-0.3.107}/MANIFEST.in +0 -0
  28. {gemcode-0.3.105 → gemcode-0.3.107}/setup.cfg +0 -0
  29. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/__init__.py +0 -0
  30. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/__main__.py +0 -0
  31. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/audit.py +0 -0
  32. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/autocompact.py +0 -0
  33. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/autotune.py +0 -0
  34. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/callbacks.py +0 -0
  35. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/capability_routing.py +0 -0
  36. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/checkpoints.py +0 -0
  37. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/compaction.py +0 -0
  38. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/computer_use/__init__.py +0 -0
  39. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/computer_use/browser_computer.py +0 -0
  40. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/context_budget.py +0 -0
  41. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/context_warning.py +0 -0
  42. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/credentials.py +0 -0
  43. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/curated_memory.py +0 -0
  44. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/dynamic_policy.py +0 -0
  45. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/evals/harness.py +0 -0
  46. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/hitl_session.py +0 -0
  47. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/hooks.py +0 -0
  48. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/ide_protocol.py +0 -0
  49. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/ide_stdio.py +0 -0
  50. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/intent_classifier.py +0 -0
  51. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/interactions.py +0 -0
  52. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/learning.py +0 -0
  53. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/limits.py +0 -0
  54. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/live_audio_engine.py +0 -0
  55. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/logging_config.py +0 -0
  56. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/mcp_loader.py +0 -0
  57. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/memory/__init__.py +0 -0
  58. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/memory/embedding_memory_service.py +0 -0
  59. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/memory/file_memory_service.py +0 -0
  60. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/modality_tools.py +0 -0
  61. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/model_errors.py +0 -0
  62. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/model_routing.py +0 -0
  63. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/multimodal_input.py +0 -0
  64. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/openapi_loader.py +0 -0
  65. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/output_styles.py +0 -0
  66. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/paths.py +0 -0
  67. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/permissions.py +0 -0
  68. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/plugins/__init__.py +0 -0
  69. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  70. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  71. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/policy_profile.py +0 -0
  72. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/pricing.py +0 -0
  73. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/prompt_suggestions.py +0 -0
  74. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query/__init__.py +0 -0
  75. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query/config.py +0 -0
  76. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query/deps.py +0 -0
  77. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query/engine.py +0 -0
  78. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query/stop_hooks.py +0 -0
  79. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query/token_budget.py +0 -0
  80. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query/transitions.py +0 -0
  81. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/query_sanitizer.py +0 -0
  82. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/refine.py +0 -0
  83. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/review_agent.py +0 -0
  84. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/rules.py +0 -0
  85. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/session_runtime.py +0 -0
  86. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/session_store.py +0 -0
  87. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/session_summariser.py +0 -0
  88. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/skills.py +0 -0
  89. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/slash_commands.py +0 -0
  90. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/thinking.py +0 -0
  91. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tool_registry.py +0 -0
  92. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tool_result_store.py +0 -0
  93. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/bash.py +0 -0
  94. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/browser.py +0 -0
  95. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/compress_memory.py +0 -0
  96. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/curated_memory.py +0 -0
  97. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/edit.py +0 -0
  98. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/filesystem.py +0 -0
  99. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/notebook.py +0 -0
  100. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/notes.py +0 -0
  101. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/repo_map.py +0 -0
  102. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/search.py +0 -0
  103. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/shell.py +0 -0
  104. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/shell_gate.py +0 -0
  105. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/skills.py +0 -0
  106. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/tasks.py +0 -0
  107. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/think.py +0 -0
  108. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/todo.py +0 -0
  109. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/veomem_tools.py +0 -0
  110. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/web.py +0 -0
  111. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools/web_search.py +0 -0
  112. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tools_inspector.py +0 -0
  113. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/trust.py +0 -0
  114. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tui/input_handler.py +0 -0
  115. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tui/spinner.py +0 -0
  116. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tui/welcome_banner.py +0 -0
  117. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/tui/welcome_rich.py +0 -0
  118. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/veomem_bridge.py +0 -0
  119. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/version.py +0 -0
  120. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/vertex.py +0 -0
  121. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/wal.py +0 -0
  122. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/web/__init__.py +0 -0
  123. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/web/sse_adapter.py +0 -0
  124. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/web/terminal_repl.py +0 -0
  125. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/web/web_sse_compat.py +0 -0
  126. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode/workspace_hints.py +0 -0
  127. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode.egg-info/dependency_links.txt +0 -0
  128. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode.egg-info/entry_points.txt +0 -0
  129. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode.egg-info/requires.txt +0 -0
  130. {gemcode-0.3.105 → gemcode-0.3.107}/src/gemcode.egg-info/top_level.txt +0 -0
  131. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_add_dir.py +0 -0
  132. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_agent_instruction.py +0 -0
  133. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_autocompact.py +0 -0
  134. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_capability_routing.py +0 -0
  135. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_checkpoint_diff_command.py +0 -0
  136. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_cli_init.py +0 -0
  137. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_compress_memory_tool.py +0 -0
  138. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_computer_use_permissions.py +0 -0
  139. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_context_budget.py +0 -0
  140. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_context_warning.py +0 -0
  141. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_credentials.py +0 -0
  142. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_eval_harness_layout.py +0 -0
  143. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_ide_stdio_attachments.py +0 -0
  144. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_interactive_permission_ask.py +0 -0
  145. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_kaira_scheduler.py +0 -0
  146. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_modality_tools.py +0 -0
  147. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_model_error_retry.py +0 -0
  148. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_model_errors.py +0 -0
  149. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_model_routing.py +0 -0
  150. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_output_styles_and_rules.py +0 -0
  151. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_paths.py +0 -0
  152. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_permissions.py +0 -0
  153. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_prompt_suggestions.py +0 -0
  154. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_repl_commands.py +0 -0
  155. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_repl_slash.py +0 -0
  156. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_skills.py +0 -0
  157. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_slash_commands.py +0 -0
  158. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_slash_completion_registry.py +0 -0
  159. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_thinking_config.py +0 -0
  160. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_token_budget.py +0 -0
  161. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_tool_context_circulation.py +0 -0
  162. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_tools_inspector.py +0 -0
  163. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_web_sse_adapter.py +0 -0
  164. {gemcode-0.3.105 → gemcode-0.3.107}/tests/test_workspace_hints.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.105
3
+ Version: 0.3.107
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -327,6 +327,17 @@ GemCode combines:
327
327
  Reference:
328
328
  - [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md)
329
329
 
330
+ ### Super mode (fully autonomous)
331
+
332
+ Use when you want GemCode to run without GemCode’s own confirmation prompts (mutations, shell, ADK confirmation handoffs, AFC stdin prompt, attachment gate, auto-trust on CLI, and non-interactive `get_user_choice` = first option).
333
+
334
+ - **CLI:** `gemcode -C . --super "your task"`
335
+ - **Env:** `GEMCODE_SUPER_MODE=1`
336
+ - **REPL/TUI:** `/super` (use `/super off` to clear the flag only)
337
+ - **Kaira:** `gemcode kaira -C . --super`
338
+
339
+ Details and safety notes: [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md#super-mode-fully-autonomous).
340
+
330
341
  ## Common commands
331
342
 
332
343
  ### Inspect models
@@ -349,6 +360,33 @@ gemcode -C . --attach ./report.pdf "Summarize this"
349
360
  gemcode kaira -C .
350
361
  ```
351
362
 
363
+ ### Orchestration (Kaira + org delegation)
364
+
365
+ Docs:
366
+ - `../docs/orchestration.md`
367
+
368
+ In one terminal:
369
+
370
+ ```bash
371
+ gemcode kaira -C .
372
+ ```
373
+
374
+ In another terminal:
375
+
376
+ ```bash
377
+ gemcode -C .
378
+ ```
379
+
380
+ Then in the REPL/TUI:
381
+
382
+ ```text
383
+ /org tree
384
+ /org hire verifier "QA / test planner" subagent gemcode "Find risks, propose tests, review plans."
385
+ /org assign verifier "Review the plan and propose tests"
386
+ /kaira jobs
387
+ /kaira follow <job_id_prefix>
388
+ ```
389
+
352
390
  ### Start the IDE bridge
353
391
  ```bash
354
392
  gemcode ide --stdio
@@ -383,6 +421,7 @@ Status note:
383
421
  | `/review` | Run a review workflow |
384
422
  | `/eval` | Run evaluation gates |
385
423
  | `/kaira` | Show scheduler usage help |
424
+ | `/super` | Super mode: auto-approve tools, no GemCode HITL · `/super off` |
386
425
 
387
426
  Detailed behavior:
388
427
  - [`../docs/cli-and-repl.md`](../docs/cli-and-repl.md)
@@ -135,6 +135,17 @@ GemCode combines:
135
135
  Reference:
136
136
  - [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md)
137
137
 
138
+ ### Super mode (fully autonomous)
139
+
140
+ Use when you want GemCode to run without GemCode’s own confirmation prompts (mutations, shell, ADK confirmation handoffs, AFC stdin prompt, attachment gate, auto-trust on CLI, and non-interactive `get_user_choice` = first option).
141
+
142
+ - **CLI:** `gemcode -C . --super "your task"`
143
+ - **Env:** `GEMCODE_SUPER_MODE=1`
144
+ - **REPL/TUI:** `/super` (use `/super off` to clear the flag only)
145
+ - **Kaira:** `gemcode kaira -C . --super`
146
+
147
+ Details and safety notes: [`../docs/tools-and-permissions.md`](../docs/tools-and-permissions.md#super-mode-fully-autonomous).
148
+
138
149
  ## Common commands
139
150
 
140
151
  ### Inspect models
@@ -157,6 +168,33 @@ gemcode -C . --attach ./report.pdf "Summarize this"
157
168
  gemcode kaira -C .
158
169
  ```
159
170
 
171
+ ### Orchestration (Kaira + org delegation)
172
+
173
+ Docs:
174
+ - `../docs/orchestration.md`
175
+
176
+ In one terminal:
177
+
178
+ ```bash
179
+ gemcode kaira -C .
180
+ ```
181
+
182
+ In another terminal:
183
+
184
+ ```bash
185
+ gemcode -C .
186
+ ```
187
+
188
+ Then in the REPL/TUI:
189
+
190
+ ```text
191
+ /org tree
192
+ /org hire verifier "QA / test planner" subagent gemcode "Find risks, propose tests, review plans."
193
+ /org assign verifier "Review the plan and propose tests"
194
+ /kaira jobs
195
+ /kaira follow <job_id_prefix>
196
+ ```
197
+
160
198
  ### Start the IDE bridge
161
199
  ```bash
162
200
  gemcode ide --stdio
@@ -191,6 +229,7 @@ Status note:
191
229
  | `/review` | Run a review workflow |
192
230
  | `/eval` | Run evaluation gates |
193
231
  | `/kaira` | Show scheduler usage help |
232
+ | `/super` | Super mode: auto-approve tools, no GemCode HITL · `/super off` |
194
233
 
195
234
  Detailed behavior:
196
235
  - [`../docs/cli-and-repl.md`](../docs/cli-and-repl.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gemcode"
7
- version = "0.3.105"
7
+ version = "0.3.107"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -733,6 +733,11 @@ If you need more tool usage examples, set `GEMCODE_VERBOSE_INSTRUCTIONS=1`.
733
733
  - Always give the sub-agent enough context to operate independently.
734
734
  - End your task prompt with "Summarise your findings clearly." so the result is useful.
735
735
 
736
+ - **`spawn_subtasks`** — spawn multiple isolated sub-agents in parallel (preferred fan-out helper).
737
+ - Use this instead of manually issuing many `run_subtask` calls.
738
+ - Provide 3–6 focused tasks; keep each subtask self-contained.
739
+ - Then synthesise the combined findings into a single plan/answer.
740
+
736
741
  ## Multi-step task execution
737
742
  One user message = many model↔tool rounds (up to 256 LLM calls by default). This is intentional — you are expected to do complete tasks autonomously.
738
743
 
@@ -1008,9 +1013,11 @@ def build_root_agent(
1008
1013
  tools = [preload_memory, *tools]
1009
1014
 
1010
1015
  # ADK built-in interactive + artifact tools — always available when ADK supports them.
1016
+ # In super mode, ``get_user_choice`` auto-picks the first option (no UI).
1011
1017
  try:
1012
- from google.adk.tools import get_user_choice, load_artifacts, exit_loop
1013
- tools = [*tools, get_user_choice, load_artifacts, exit_loop]
1018
+ from gemcode.tools.user_choice import append_user_choice_load_artifacts_exit_loop
1019
+
1020
+ append_user_choice_load_artifacts_exit_loop(cfg, tools)
1014
1021
  except Exception:
1015
1022
  pass
1016
1023
 
@@ -13,7 +13,7 @@ import uuid
13
13
  import warnings
14
14
  from pathlib import Path
15
15
 
16
- from gemcode.config import GemCodeConfig, load_cli_environment
16
+ from gemcode.config import GemCodeConfig, apply_super_mode, load_cli_environment
17
17
  from gemcode.tools_inspector import inspect_tools, smoke_tools
18
18
  from gemcode.invoke import run_turn
19
19
  from gemcode.model_routing import pick_effective_model
@@ -43,6 +43,11 @@ def _maybe_prompt_trust(cfg: GemCodeConfig) -> None:
43
43
  On first use in a project root, ask the user to trust the folder so file,
44
44
  shell, and git tools can run. If not trusted, we exit before any tool runs.
45
45
  """
46
+ if getattr(cfg, "super_mode", False):
47
+ root = cfg.project_root.resolve()
48
+ if not is_trusted_root(root):
49
+ trust_root(root, trusted=True)
50
+ return
46
51
  # Non-interactive sessions can't answer prompts.
47
52
  if not (hasattr(sys.stdin, "isatty") and sys.stdin.isatty()):
48
53
  return
@@ -220,7 +225,9 @@ async def _run_repl(cfg: GemCodeConfig, session_id: str, *, use_mcp: bool) -> No
220
225
  "on",
221
226
  ):
222
227
  try:
223
- if (
228
+ if getattr(cfg, "super_mode", False):
229
+ pass
230
+ elif (
224
231
  hasattr(sys.stdin, "isatty")
225
232
  and sys.stdin.isatty()
226
233
  and not cfg.yes_to_all
@@ -922,6 +929,11 @@ def main() -> None:
922
929
  action="store_true",
923
930
  help="Allow write_file / search_replace (disables interactive HITL prompts).",
924
931
  )
932
+ kaira_parser.add_argument(
933
+ "--super",
934
+ action="store_true",
935
+ help="Fully autonomous jobs: auto-approve tools/shell, no HITL (implies --yes).",
936
+ )
925
937
  kaira_parser.add_argument(
926
938
  "--interactive-ask",
927
939
  action="store_true",
@@ -978,7 +990,11 @@ def main() -> None:
978
990
  cfg.model_mode = "fast"
979
991
 
980
992
  cfg.yes_to_all = bool(args.yes)
981
- if args.interactive_ask:
993
+ if getattr(args, "super", False):
994
+ cfg.super_mode = True
995
+ if cfg.super_mode:
996
+ apply_super_mode(cfg)
997
+ elif args.interactive_ask:
982
998
  cfg.interactive_permission_ask = True
983
999
  else:
984
1000
  if "GEMCODE_INTERACTIVE_PERMISSION_ASK" not in os.environ:
@@ -1023,6 +1039,11 @@ def main() -> None:
1023
1039
  parser.add_argument("-C", "--directory", type=Path, default=Path.cwd(), help="Project root")
1024
1040
  parser.add_argument("--session", default=None, help="Session id for SQLite-backed history")
1025
1041
  parser.add_argument("--yes", action="store_true", help="Allow write_file / search_replace")
1042
+ parser.add_argument(
1043
+ "--super",
1044
+ action="store_true",
1045
+ help="Super mode: auto-approve all tool/shell use, skip HITL and AFC prompts (implies --yes).",
1046
+ )
1026
1047
  parser.add_argument(
1027
1048
  "--interactive-ask",
1028
1049
  action="store_true",
@@ -1096,7 +1117,11 @@ def main() -> None:
1096
1117
  if args.model_mode is None:
1097
1118
  cfg.model_mode = "fast"
1098
1119
  cfg.yes_to_all = args.yes
1099
- if args.interactive_ask:
1120
+ if args.super:
1121
+ cfg.super_mode = True
1122
+ if cfg.super_mode:
1123
+ apply_super_mode(cfg)
1124
+ elif args.interactive_ask:
1100
1125
  cfg.interactive_permission_ask = True
1101
1126
  else:
1102
1127
  # If user didn't explicitly set env, default to HITL when we're in a TTY.
@@ -374,6 +374,13 @@ class GemCodeConfig:
374
374
  default_factory=lambda: _truthy_env("GEMCODE_BACKGROUND_LEARNER", default=False)
375
375
  )
376
376
 
377
+ # "Super" mode: fully autonomous session — auto-approve mutating/shell tools,
378
+ # skip interactive HITL and AFC tool-mode prompts, and prefer non-blocking UX.
379
+ # Enable with ``GEMCODE_SUPER_MODE=1`` or ``gemcode --super``.
380
+ super_mode: bool = field(
381
+ default_factory=lambda: _truthy_env("GEMCODE_SUPER_MODE", default=False)
382
+ )
383
+
377
384
  def __post_init__(self) -> None:
378
385
  self.project_root = self.project_root.resolve()
379
386
  # Default agentic depth when env omits GEMCODE_MAX_LLM_CALLS (was: None → SDK default).
@@ -479,6 +486,24 @@ class GemCodeConfig:
479
486
  "tar",
480
487
  )
481
488
  )
489
+ if self.super_mode:
490
+ apply_super_mode(self)
491
+
492
+
493
+ def apply_super_mode(cfg: GemCodeConfig) -> None:
494
+ """
495
+ Apply super-mode policy: no interactive tool HITL, auto-approve GemCode gates,
496
+ keep all toolsets (skip AFC stdin prompt via ``_afc_choice``), relax strict
497
+ permission mode so shell tools can run.
498
+ """
499
+ if not getattr(cfg, "super_mode", False):
500
+ return
501
+ cfg.yes_to_all = True
502
+ cfg.interactive_permission_ask = False
503
+ if getattr(cfg, "permission_mode", "") == "strict":
504
+ cfg.permission_mode = "default"
505
+ object.__setattr__(cfg, "_afc_choice", "all")
506
+ object.__setattr__(cfg, "_attachments_allowed", True)
482
507
 
483
508
 
484
509
  def load_dotenv_optional() -> None:
@@ -25,6 +25,82 @@ _TRANSIENT_RETRY_DELAYS = [2.0, 5.0, 12.0]
25
25
 
26
26
  _HITL_PROMPT_LOCK = Lock()
27
27
 
28
+ async def _maybe_enqueue_kaira_autopilot(*, cfg: "GemCodeConfig", session_id: str) -> None:
29
+ """If Kaira IPC is available, enqueue background quality checks after edits."""
30
+ try:
31
+ enabled = os.environ.get("GEMCODE_KAIRA_AUTOPILOT", "1").strip().lower() in (
32
+ "1",
33
+ "true",
34
+ "yes",
35
+ "on",
36
+ )
37
+ if not enabled:
38
+ return
39
+ # Only run when files were touched (edit tools track this).
40
+ touched = getattr(cfg, "_touched_paths", None)
41
+ if not touched:
42
+ return
43
+ # Avoid enqueuing repeatedly within the same session unless touched paths change.
44
+ last_fp = str(getattr(cfg, "_kaira_autopilot_fp", "") or "")
45
+ fp = ",".join(sorted(str(x) for x in touched))[:4000]
46
+ if fp and fp == last_fp:
47
+ return
48
+ object.__setattr__(cfg, "_kaira_autopilot_fp", fp)
49
+
50
+ sock = os.environ.get("GEMCODE_KAIRA_SOCKET") or str(cfg.project_root / ".gemcode" / "ipc.sock")
51
+ if not Path(sock).exists():
52
+ return
53
+ # Heuristic: suggest likely checks, but let the agent choose based on repo.
54
+ prompt = (
55
+ "You are Kaira (background worker). Run the most relevant automated quality checks for this repo "
56
+ "based on its files, and report succinctly.\n\n"
57
+ "Rules:\n"
58
+ "- Prefer fast checks first (lint/typecheck/unit tests).\n"
59
+ "- If Python: try `pytest -q` (or detect other common runners).\n"
60
+ "- If Node: try `npm test` / `npm run lint` when package.json exists.\n"
61
+ "- If there are failures, include the smallest actionable summary and exact command to reproduce.\n"
62
+ "- If everything passes, say PASS and list what you ran.\n"
63
+ "- Return a final STRICT JSON report with keys: status, summary, evidence, recommended_next_actions.\n\n"
64
+ f"Touched files (recent): {', '.join(sorted(list(touched))[:30])}"
65
+ )
66
+
67
+ # Org-aware routing: delegate to the kaira org member if present so the
68
+ # manager/worker hierarchy stays consistent.
69
+ try:
70
+ auto_org = os.environ.get("GEMCODE_AUTO_SLASH_ORG", "1").strip().lower() in (
71
+ "1",
72
+ "true",
73
+ "yes",
74
+ "on",
75
+ )
76
+ if auto_org:
77
+ from gemcode.org import find_member
78
+ m = find_member(cfg.project_root, "kaira")
79
+ if m is not None and m.kind == "kaira_worker":
80
+ from gemcode.tools.org_tools import make_org_tools
81
+ tools = make_org_tools(cfg)
82
+ org_delegate = None
83
+ for t in tools:
84
+ if getattr(t, "__name__", "") == "org_delegate":
85
+ org_delegate = t
86
+ break
87
+ if org_delegate is not None:
88
+ await org_delegate("kaira", prompt, "") # type: ignore[misc]
89
+ return
90
+ except Exception:
91
+ pass
92
+
93
+ from gemcode.kaira_client import KairaIpcClient
94
+
95
+ client = await KairaIpcClient.connect(socket_path=sock)
96
+ try:
97
+ # Low priority by default; user can override with env in future.
98
+ await client.request(action="enqueue", prompt=prompt, priority=-1, session_id=session_id)
99
+ finally:
100
+ await client.close()
101
+ except Exception:
102
+ return
103
+
28
104
 
29
105
  def _events_to_text(events: list[Any]) -> str:
30
106
  """Best-effort extraction of assistant text from ADK events."""
@@ -102,6 +178,56 @@ async def run_turn(
102
178
  object.__setattr__(cfg, "_risk_score", risk)
103
179
  except Exception:
104
180
  pass
181
+
182
+ # Deterministic manager dispatcher: pre-delegate certain work to org members
183
+ # and inject their results into the prompt before the main agent runs.
184
+ try:
185
+ auto_mgr = os.environ.get("GEMCODE_MANAGER_DISPATCH", "1").strip().lower() in (
186
+ "1","true","yes","on"
187
+ )
188
+ if auto_mgr:
189
+ import re
190
+ p0 = (prompt or "")[:12_000]
191
+ # Only do this for broad/complex prompts.
192
+ score = float(getattr(cfg, "_parallelism_score", 0.0) or 0.0)
193
+ if score >= float(os.environ.get("GEMCODE_MANAGER_DISPATCH_THRESHOLD", "0.7")):
194
+ from gemcode.tools.org_tools import make_org_tools
195
+ tools = make_org_tools(cfg)
196
+ org_delegate = None
197
+ for t in tools:
198
+ if getattr(t, "__name__", "") == "org_delegate":
199
+ org_delegate = t
200
+ break
201
+ # Ask verifier for a quick risk check / plan critique (fast, in-process).
202
+ if org_delegate is not None and re.search(r"\\b(fix|refactor|rewrite|change|implement)\\b", p0, re.I):
203
+ v = await org_delegate("verifier", "Review the requested task and list key risks + verification steps.", p0) # type: ignore[misc]
204
+ if isinstance(v, dict) and v.get("ok") and v.get("result"):
205
+ object.__setattr__(cfg, "_manager_verifier_context", str(v.get("result"))[:4000])
206
+ except Exception:
207
+ pass
208
+ # Parallelism score: heuristic signal for automatic subtask fan-out.
209
+ try:
210
+ import re
211
+ p2 = (prompt or "")[:20_000]
212
+ par = 0.0
213
+ if len(p2) > 800:
214
+ par += 0.15
215
+ if len(p2) > 2400:
216
+ par += 0.2
217
+ if re.search(r"\b(analy[sz]e|audit|map|inventory|scan|survey)\b", p2, re.I):
218
+ par += 0.2
219
+ if re.search(r"\b(refactor|migrate|rewrite|redesign|architecture)\b", p2, re.I):
220
+ par += 0.2
221
+ if re.search(r"\b(across|entire|whole|end-to-end|e2e|multiple modules|many files)\b", p2, re.I):
222
+ par += 0.2
223
+ if p2.count("/") >= 8 or p2.count(".py") + p2.count(".ts") + p2.count(".tsx") >= 5:
224
+ par += 0.15
225
+ if attachment_paths:
226
+ par += 0.08
227
+ par = max(0.0, min(1.0, float(par)))
228
+ object.__setattr__(cfg, "_parallelism_score", par)
229
+ except Exception:
230
+ pass
105
231
  run_config = (
106
232
  RunConfig(max_llm_calls=max_llm_calls) if max_llm_calls is not None else None
107
233
  )
@@ -222,9 +348,48 @@ async def run_turn(
222
348
  for w in attach_warn:
223
349
  print(f"[gemcode] {w}", file=sys.stderr)
224
350
  else:
225
- current_message = types.Content(
226
- role="user", parts=[types.Part(text=prompt)]
227
- )
351
+ effective_prompt = prompt
352
+ # Auto fan-out: when prompt looks broad, guide model to spawn parallel
353
+ # isolated subtasks first (bounded) and then synthesise.
354
+ try:
355
+ auto_on = os.environ.get("GEMCODE_AUTO_FANOUT", "1").strip().lower() in (
356
+ "1",
357
+ "true",
358
+ "yes",
359
+ "on",
360
+ )
361
+ threshold = float(os.environ.get("GEMCODE_AUTO_FANOUT_THRESHOLD", "0.6"))
362
+ if auto_on and cfg is not None:
363
+ score = float(getattr(cfg, "_parallelism_score", 0.0) or 0.0)
364
+ already = bool(getattr(cfg, "_auto_fanout_applied", False))
365
+ if (not already) and score >= threshold:
366
+ object.__setattr__(cfg, "_auto_fanout_applied", True)
367
+ effective_prompt = (
368
+ "Before you answer, do a quick parallel exploration pass:\n"
369
+ "- Decompose this into 3–6 independent investigation subtasks.\n"
370
+ "- Call `spawn_subtasks(tasks=[...], max_concurrency=4)` to run them in parallel.\n"
371
+ "- If an org member is appropriate, prefer delegating with `org_delegate` / `org_spawn`.\n"
372
+ "- Synthesize the results into a single plan/answer, then proceed.\n\n"
373
+ + (prompt or "")
374
+ )
375
+ except Exception:
376
+ pass
377
+
378
+ # Inject dispatcher context (e.g., verifier critique) if available.
379
+ try:
380
+ if cfg is not None:
381
+ ctx = str(getattr(cfg, "_manager_verifier_context", "") or "").strip()
382
+ if ctx:
383
+ effective_prompt = (
384
+ "Manager pre-delegation result (verifier):\n"
385
+ + ctx
386
+ + "\n\nUser request:\n"
387
+ + (effective_prompt or "")
388
+ )
389
+ except Exception:
390
+ pass
391
+
392
+ current_message = types.Content(role="user", parts=[types.Part(text=effective_prompt)])
228
393
 
229
394
  async def _await_runner_events(
230
395
  *, next_message: types.Content, do_reset: bool
@@ -295,11 +460,20 @@ async def run_turn(
295
460
  and hasattr(sys.stdin, "isatty")
296
461
  and sys.stdin.isatty()
297
462
  )
463
+ auto_ok = bool(
464
+ cfg is not None
465
+ and (
466
+ bool(getattr(cfg, "yes_to_all", False))
467
+ or bool(getattr(cfg, "super_mode", False))
468
+ )
469
+ )
298
470
 
299
471
  parts: list[types.Part] = []
300
472
  for fc in confirmation_fcs:
301
473
  tool_name, hint = _extract_hint_and_tool(fc)
302
- if interactive_enabled:
474
+ if auto_ok:
475
+ ok = True
476
+ elif interactive_enabled:
303
477
  suffix = f"\n Hint: {hint}" if hint else ""
304
478
  ok = _prompt_yes_no(
305
479
  f"\n[gemcode HITL] Approve tool call '{tool_name}'? [y/N]{suffix}\n> "
@@ -347,6 +521,12 @@ async def run_turn(
347
521
  )
348
522
  continue
349
523
 
524
+ # Background autopilot: if we touched files, enqueue Kaira checks (best-effort).
525
+ if cfg is not None:
526
+ try:
527
+ await _maybe_enqueue_kaira_autopilot(cfg=cfg, session_id=session_id)
528
+ except Exception:
529
+ pass
350
530
  return collected
351
531
  finally:
352
532
  if cfg is not None and orig_ctx_chars is not None:
@@ -0,0 +1,51 @@
1
+ from __future__ import annotations
2
+
3
+ import asyncio
4
+ import uuid
5
+ from dataclasses import dataclass
6
+ from typing import Any, AsyncIterator
7
+
8
+ from gemcode.ide_protocol import IdeEmitter, make_response, parse_json_line
9
+
10
+
11
+ @dataclass
12
+ class KairaIpcClient:
13
+ reader: asyncio.StreamReader
14
+ writer: asyncio.StreamWriter
15
+ emitter: IdeEmitter
16
+
17
+ @classmethod
18
+ async def connect(cls, *, socket_path: str) -> "KairaIpcClient":
19
+ reader, writer = await asyncio.open_unix_connection(socket_path)
20
+ return cls(reader=reader, writer=writer, emitter=IdeEmitter(stream=writer))
21
+
22
+ async def close(self) -> None:
23
+ try:
24
+ self.writer.close()
25
+ await self.writer.wait_closed()
26
+ except Exception:
27
+ pass
28
+
29
+ async def request(self, *, action: str, **payload: Any) -> dict[str, Any]:
30
+ req_id = f"req_{uuid.uuid4().hex[:12]}"
31
+ msg = {"type": "request", "id": req_id, "action": action}
32
+ msg.update(payload)
33
+ self.emitter.send(msg)
34
+ # Wait for matching response.
35
+ while True:
36
+ line = await self.reader.readline()
37
+ if not line:
38
+ return make_response(id=req_id, ok=False, error="ipc_eof")
39
+ obj = parse_json_line(line.decode("utf-8", errors="replace").strip())
40
+ if obj.get("type") == "response" and str(obj.get("id") or "") == req_id:
41
+ return obj
42
+ # Other messages (events) are ignored here; caller should use iter_messages.
43
+
44
+ async def iter_messages(self) -> AsyncIterator[dict[str, Any]]:
45
+ while True:
46
+ line = await self.reader.readline()
47
+ if not line:
48
+ return
49
+ obj = parse_json_line(line.decode("utf-8", errors="replace").strip())
50
+ yield obj
51
+