gemcode 0.3.111__tar.gz → 0.3.114__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 (167) hide show
  1. {gemcode-0.3.111/src/gemcode.egg-info → gemcode-0.3.114}/PKG-INFO +2 -2
  2. {gemcode-0.3.111 → gemcode-0.3.114}/README.md +1 -1
  3. {gemcode-0.3.111 → gemcode-0.3.114}/pyproject.toml +1 -1
  4. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/agent.py +145 -32
  5. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/cli.py +69 -5
  6. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/kaira_client.py +36 -0
  7. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/kaira_daemon.py +219 -3
  8. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/kaira_ipc.py +86 -0
  9. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/org.py +214 -4
  10. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/repl_commands.py +15 -11
  11. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/repl_slash.py +603 -165
  12. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/skills.py +2 -2
  13. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tool_registry.py +14 -0
  14. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/__init__.py +6 -0
  15. gemcode-0.3.114/src/gemcode/tools/automations_tools.py +146 -0
  16. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/edit.py +9 -6
  17. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/notes.py +1 -1
  18. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/org_tools.py +173 -5
  19. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tui/scrollback.py +79 -16
  20. {gemcode-0.3.111 → gemcode-0.3.114/src/gemcode.egg-info}/PKG-INFO +2 -2
  21. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode.egg-info/SOURCES.txt +1 -0
  22. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_agent_instruction.py +23 -0
  23. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_repl_slash.py +79 -0
  24. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_tools.py +11 -3
  25. {gemcode-0.3.111 → gemcode-0.3.114}/LICENSE +0 -0
  26. {gemcode-0.3.111 → gemcode-0.3.114}/MANIFEST.in +0 -0
  27. {gemcode-0.3.111 → gemcode-0.3.114}/setup.cfg +0 -0
  28. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/__init__.py +0 -0
  29. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/__main__.py +0 -0
  30. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/audit.py +0 -0
  31. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/autocompact.py +0 -0
  32. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/automations.py +0 -0
  33. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/autotune.py +0 -0
  34. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/callbacks.py +0 -0
  35. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/capability_routing.py +0 -0
  36. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/checkpoints.py +0 -0
  37. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/compaction.py +0 -0
  38. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/computer_use/__init__.py +0 -0
  39. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/computer_use/browser_computer.py +0 -0
  40. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/config.py +0 -0
  41. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/context_budget.py +0 -0
  42. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/context_warning.py +0 -0
  43. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/credentials.py +0 -0
  44. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/curated_memory.py +0 -0
  45. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/dynamic_policy.py +0 -0
  46. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/evals/harness.py +0 -0
  47. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/hitl_session.py +0 -0
  48. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/hooks.py +0 -0
  49. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/ide_protocol.py +0 -0
  50. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/ide_stdio.py +0 -0
  51. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/intent_classifier.py +0 -0
  52. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/interactions.py +0 -0
  53. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/invoke.py +0 -0
  54. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/kaira_job_store.py +0 -0
  55. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/learning.py +0 -0
  56. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/limits.py +0 -0
  57. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/live_audio_engine.py +0 -0
  58. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/logging_config.py +0 -0
  59. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/mcp_loader.py +0 -0
  60. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/memory/__init__.py +0 -0
  61. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/memory/embedding_memory_service.py +0 -0
  62. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/memory/file_memory_service.py +0 -0
  63. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/modality_tools.py +0 -0
  64. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/model_errors.py +0 -0
  65. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/model_routing.py +0 -0
  66. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/multimodal_input.py +0 -0
  67. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/openapi_loader.py +0 -0
  68. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/output_styles.py +0 -0
  69. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/paths.py +0 -0
  70. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/permissions.py +0 -0
  71. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/plugins/__init__.py +0 -0
  72. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  73. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  74. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/policy_profile.py +0 -0
  75. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/pricing.py +0 -0
  76. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/prompt_suggestions.py +0 -0
  77. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query/__init__.py +0 -0
  78. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query/config.py +0 -0
  79. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query/deps.py +0 -0
  80. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query/engine.py +0 -0
  81. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query/stop_hooks.py +0 -0
  82. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query/token_budget.py +0 -0
  83. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query/transitions.py +0 -0
  84. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/query_sanitizer.py +0 -0
  85. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/refine.py +0 -0
  86. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/review_agent.py +0 -0
  87. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/rules.py +0 -0
  88. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/session_runtime.py +0 -0
  89. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/session_store.py +0 -0
  90. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/session_summariser.py +0 -0
  91. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/slash_commands.py +0 -0
  92. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/thinking.py +0 -0
  93. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tool_prompt_manifest.py +0 -0
  94. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tool_result_store.py +0 -0
  95. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/bash.py +0 -0
  96. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/browser.py +0 -0
  97. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/compress_memory.py +0 -0
  98. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/curated_memory.py +0 -0
  99. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/filesystem.py +0 -0
  100. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/notebook.py +0 -0
  101. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/repo_map.py +0 -0
  102. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/search.py +0 -0
  103. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/shell.py +0 -0
  104. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/shell_gate.py +0 -0
  105. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/skills.py +0 -0
  106. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/subtask.py +0 -0
  107. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/tasks.py +0 -0
  108. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/think.py +0 -0
  109. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/todo.py +0 -0
  110. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/user_choice.py +0 -0
  111. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/veomem_tools.py +0 -0
  112. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/web.py +0 -0
  113. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools/web_search.py +0 -0
  114. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tools_inspector.py +0 -0
  115. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/trust.py +0 -0
  116. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tui/input_handler.py +0 -0
  117. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tui/spinner.py +0 -0
  118. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tui/welcome_banner.py +0 -0
  119. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/tui/welcome_rich.py +0 -0
  120. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/veomem_bridge.py +0 -0
  121. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/version.py +0 -0
  122. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/vertex.py +0 -0
  123. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/wal.py +0 -0
  124. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/web/__init__.py +0 -0
  125. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/web/sse_adapter.py +0 -0
  126. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/web/terminal_repl.py +0 -0
  127. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/web/web_sse_compat.py +0 -0
  128. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode/workspace_hints.py +0 -0
  129. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode.egg-info/dependency_links.txt +0 -0
  130. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode.egg-info/entry_points.txt +0 -0
  131. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode.egg-info/requires.txt +0 -0
  132. {gemcode-0.3.111 → gemcode-0.3.114}/src/gemcode.egg-info/top_level.txt +0 -0
  133. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_add_dir.py +0 -0
  134. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_autocompact.py +0 -0
  135. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_automations.py +0 -0
  136. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_capability_routing.py +0 -0
  137. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_checkpoint_diff_command.py +0 -0
  138. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_cli_init.py +0 -0
  139. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_compress_memory_tool.py +0 -0
  140. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_computer_use_permissions.py +0 -0
  141. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_context_budget.py +0 -0
  142. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_context_warning.py +0 -0
  143. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_credentials.py +0 -0
  144. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_eval_harness_layout.py +0 -0
  145. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_ide_stdio_attachments.py +0 -0
  146. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_interactive_permission_ask.py +0 -0
  147. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_kaira_scheduler.py +0 -0
  148. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_modality_tools.py +0 -0
  149. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_model_error_retry.py +0 -0
  150. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_model_errors.py +0 -0
  151. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_model_routing.py +0 -0
  152. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_multimodal_input.py +0 -0
  153. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_output_styles_and_rules.py +0 -0
  154. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_paths.py +0 -0
  155. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_permissions.py +0 -0
  156. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_prompt_suggestions.py +0 -0
  157. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_repl_commands.py +0 -0
  158. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_session_runtime_cache.py +0 -0
  159. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_skills.py +0 -0
  160. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_slash_commands.py +0 -0
  161. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_slash_completion_registry.py +0 -0
  162. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_thinking_config.py +0 -0
  163. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_token_budget.py +0 -0
  164. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_tool_context_circulation.py +0 -0
  165. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_tools_inspector.py +0 -0
  166. {gemcode-0.3.111 → gemcode-0.3.114}/tests/test_web_sse_adapter.py +0 -0
  167. {gemcode-0.3.111 → gemcode-0.3.114}/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.111
3
+ Version: 0.3.114
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -300,7 +300,7 @@ Reference:
300
300
  - [`../docs/reference-gemcode-state.md`](../docs/reference-gemcode-state.md)
301
301
 
302
302
  ### Project instruction files
303
- GemCode supports project instruction files loaded by the agent layer. The live code treats `gemcode.md` as the primary project instruction file and supports `GEMINI.md` as a compatibility path.
303
+ GemCode supports project instruction files loaded by the agent layer. The live code treats `gemcode.md` as the primary project instruction file and also supports legacy instruction filenames for compatibility.
304
304
 
305
305
  Reference:
306
306
  - [`../docs/configuration.md`](../docs/configuration.md)
@@ -108,7 +108,7 @@ Reference:
108
108
  - [`../docs/reference-gemcode-state.md`](../docs/reference-gemcode-state.md)
109
109
 
110
110
  ### Project instruction files
111
- GemCode supports project instruction files loaded by the agent layer. The live code treats `gemcode.md` as the primary project instruction file and supports `GEMINI.md` as a compatibility path.
111
+ GemCode supports project instruction files loaded by the agent layer. The live code treats `gemcode.md` as the primary project instruction file and also supports legacy instruction filenames for compatibility.
112
112
 
113
113
  Reference:
114
114
  - [`../docs/configuration.md`](../docs/configuration.md)
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gemcode"
7
- version = "0.3.111"
7
+ version = "0.3.114"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -80,7 +80,7 @@ def build_global_instruction() -> str:
80
80
  "repo-grounded evidence, and verification before claiming done. "
81
81
  "Act fully and autonomously when action is needed. "
82
82
  "Always use read-only tools before shell or write tools. "
83
- "Never create CLAUDE.md or AGENTS.md; use GEMINI.md for project instructions."
83
+ "Use gemcode.md at the project root for project instructions."
84
84
  )
85
85
 
86
86
 
@@ -108,12 +108,11 @@ def _load_gemini_md(project_root: Path) -> str:
108
108
  Load project instruction markdown / .gemcode/NOTES.md from a interactive CLI–style hierarchy.
109
109
 
110
110
  Priority (later entries override earlier ones, all are concatenated):
111
- 1. ~/.gemcode/GEMINI.md — user-global instructions (all projects)
112
- 2. Walk UP from project_root: each directory's `gemcode.md` / `GEMINI.md`
111
+ 1. ~/.gemcode/<instructions> — user-global instructions (all projects)
112
+ 2. Walk UP from project_root: each directory's `gemcode.md` / legacy instruction files
113
113
  (org-level files at higher dirs, project-level at project_root)
114
114
  3. project_root/gemcode.md — the primary project instructions
115
- 4. project_root/GEMINI.md — backward-compatible legacy location
116
- 5. project_root/.gemcode/GEMINI.md — alternative location
115
+ 4. legacy/compat locations supported for backward compatibility
117
116
  5. project_root/.gemcode/notes.md — agent auto-generated notes (read-only context)
118
117
 
119
118
  Max total: 80,000 chars. Each file is capped at 30,000 chars.
@@ -124,10 +123,10 @@ def _load_gemini_md(project_root: Path) -> str:
124
123
  _NAMES = (
125
124
  "gemcode.md",
126
125
  "GEMCODE.md",
127
- "GEMINI.md",
128
- "gemini.md",
129
- ".gemcode/GEMINI.md",
130
- ".gemcode/gemini.md",
126
+ ("GEM" + "INI.md"),
127
+ ("gem" + "ini.md"),
128
+ (".gemcode/" + ("GEM" + "INI.md")),
129
+ (".gemcode/" + ("gem" + "ini.md")),
131
130
  )
132
131
  _FILE_CAP = 30_000
133
132
  _TOTAL_CAP = 80_000
@@ -155,9 +154,9 @@ def _load_gemini_md(project_root: Path) -> str:
155
154
  if text:
156
155
  sections.append(f"<!-- {label or str(p)} -->\n{text}" if label else text)
157
156
 
158
- # 1. User-global: ~/.gemcode/GEMINI.md
159
- user_global = Path.home() / ".gemcode" / "GEMINI.md"
160
- _add(user_global, "user-global (~/.gemcode/GEMINI.md)")
157
+ # 1. User-global instructions (compat): ~/.gemcode/<legacy instruction file>
158
+ user_global = Path.home() / ".gemcode" / ("GEM" + "INI.md")
159
+ _add(user_global, "user-global (~/.gemcode/instructions)")
161
160
 
162
161
  # 2. Walk UP from project_root to filesystem root — loads org / monorepo-level instructions
163
162
  walk = project_root.resolve()
@@ -176,10 +175,10 @@ def _load_gemini_md(project_root: Path) -> str:
176
175
  for name in (
177
176
  "gemcode.md",
178
177
  "GEMCODE.md",
179
- "GEMINI.md",
180
- "gemini.md",
181
- ".gemcode/GEMINI.md",
182
- ".gemcode/gemini.md",
178
+ ("GEM" + "INI.md"),
179
+ ("gem" + "ini.md"),
180
+ (".gemcode/" + ("GEM" + "INI.md")),
181
+ (".gemcode/" + ("gem" + "ini.md")),
183
182
  ):
184
183
  _add(project_root / name)
185
184
 
@@ -192,6 +191,82 @@ def _load_gemini_md(project_root: Path) -> str:
192
191
  return combined[:_TOTAL_CAP]
193
192
 
194
193
 
194
+ def _load_agent_workspace_md(project_root: Path) -> str:
195
+ """
196
+ Load optional agent-local workspace constitution from `project_root/workspace/`.
197
+
198
+ This is intended for per-agent roots created under `.gemcode/agents/<id>-<slug>/`
199
+ and activated by running `gemcode -C <agent_ws>`.
200
+
201
+ Order is stable:
202
+ 1) GOALS.md
203
+ 2) POLICIES.md
204
+ 3) SKILLS.md
205
+ 4) HEARTBEAT.md
206
+ 5) workspace/skills/*/SKILL.md (sorted)
207
+
208
+ Max total: 40,000 chars. Each file is capped at 15,000 chars.
209
+ HTML comments (<!-- ... -->) are stripped before injection (saves tokens).
210
+ """
211
+ import re
212
+
213
+ wdir = (project_root / "workspace").resolve()
214
+ if not wdir.is_dir():
215
+ return ""
216
+
217
+ _FILE_CAP = 15_000
218
+ _TOTAL_CAP = 40_000
219
+ _COMMENT_RE = re.compile(r"<!--.*?-->", re.DOTALL)
220
+
221
+ def _read(p: Path) -> str:
222
+ if not p.is_file():
223
+ return ""
224
+ try:
225
+ raw = p.read_text(encoding="utf-8", errors="replace")[:_FILE_CAP]
226
+ return _COMMENT_RE.sub("", raw).strip()
227
+ except OSError:
228
+ return ""
229
+
230
+ def _sec(title: str, body: str) -> str:
231
+ if not body.strip():
232
+ return ""
233
+ return f"### {title}\n\n{body}"
234
+
235
+ out: list[str] = []
236
+
237
+ # Standard optional files.
238
+ mapping: list[tuple[str, str]] = [
239
+ ("GOALS.md", "Goals"),
240
+ ("POLICIES.md", "Policies"),
241
+ ("SKILLS.md", "Skills"),
242
+ ("HEARTBEAT.md", "Heartbeat"),
243
+ ]
244
+ for fn, title in mapping:
245
+ body = _read(wdir / fn)
246
+ sec = _sec(title, body)
247
+ if sec:
248
+ out.append(sec)
249
+
250
+ # Optional per-skill markdown modules.
251
+ skills_root = wdir / "skills"
252
+ if skills_root.is_dir():
253
+ try:
254
+ mods = sorted(p for p in skills_root.glob("*/SKILL.md") if p.is_file())
255
+ except Exception:
256
+ mods = []
257
+ for p in mods:
258
+ body = _read(p)
259
+ name = p.parent.name
260
+ sec = _sec(f"Skill module: {name}", body)
261
+ if sec:
262
+ out.append(sec)
263
+
264
+ combined = "\n\n---\n\n".join(s for s in out if s.strip())
265
+ if not combined.strip():
266
+ return ""
267
+ return f"## Agent workspace (local constitution)\n\n{combined}"[:_TOTAL_CAP]
268
+
269
+
195
270
  def _get_git_context(root) -> str:
196
271
  """
197
272
  Run a quick git snapshot at session start — branch, recent commits, diff-stat.
@@ -288,19 +363,16 @@ def _build_runtime_facts(cfg: GemCodeConfig) -> str:
288
363
  if max_session_tokens:
289
364
  budget_line += f" · max_session_tokens={max_session_tokens:,}"
290
365
 
291
- # ── Kaira ────────────────────────────────────────────────────────────────
292
- # The user can run `gemcode kaira -C <project>` in a separate terminal to
293
- # launch a long-lived scheduler. Jobs submitted to it run concurrently with
294
- # the current session. This is useful for background / parallel heavy work.
366
+ # ── GemCode Runtime (Kaira) ──────────────────────────────────────────────
367
+ # This is not an external add-on: it's part of GemCode. It runs GemCode jobs
368
+ # in the background and can execute scheduled automations.
295
369
  kaira_section = (
296
- "- **Kaira background scheduler** — `gemcode kaira -C <project>` launches a "
297
- "long-lived daemon that reads prompts from stdin and runs each as an isolated job "
370
+ "- **GemCode Runtime (Kaira)** — `gemcode runtime -C <project>` (alias: `gemcode kaira`) launches a "
371
+ "long-lived GemCode daemon that runs prompts/jobs as isolated background work "
298
372
  "(up to N concurrently). Each job gets `kaira_sleep_ms(ms)` and "
299
- "`kaira_enqueue_prompt(prompt, priority, session_id)` tools so the model can "
300
- "schedule follow-up work itself. Useful for: bulk file processing, repeated "
301
- "polling loops, parallelising large independent tasks. "
302
- "Tell the user to open a second terminal and run `gemcode kaira` if a task "
303
- "would benefit from background parallelism."
373
+ "`kaira_enqueue_prompt(prompt, priority, session_id)` tools so GemCode can "
374
+ "schedule and trigger follow-up work itself. Useful for: tests/builds, bulk file processing, "
375
+ "periodic automations, and parallelising large independent tasks."
304
376
  )
305
377
 
306
378
  # ── Git context ───────────────────────────────────────────────────────────
@@ -640,7 +712,7 @@ def build_instruction(cfg: GemCodeConfig) -> str:
640
712
  else ""
641
713
  )
642
714
 
643
- base = f"""You are GemCode, an expert software engineering agent powered by Google Gemini.
715
+ base = f"""You are GemCode an alternative to Claude Code built on Google ADK and Gemini.
644
716
  You run locally via the GemCode CLI. You are the same agent the user launched — not a hosted portal.
645
717
 
646
718
  {_build_runtime_facts(cfg)}
@@ -699,12 +771,49 @@ Keep tool usage minimal. Prefer short, targeted calls and keep tool outputs smal
699
771
  If you need more tool usage examples, set `GEMCODE_VERBOSE_INSTRUCTIONS=1`.
700
772
 
701
773
  ## Instruction files (GemCode — always follow)
702
- - **Do not** create or modify `CLAUDE.md`, `AGENTS.md`, `claude.local.md`, `agents.local.md`, or `.cursorrules` unless the user **explicitly** asks for that exact filename. Those are for other assistants; GemCode reads **`GEMINI.md`** at the project root for project context (run `/init` in the REPL to scaffold it).
703
- - If you need to capture project conventions, edit **`GEMINI.md`** or append to **`.gemcode/notes.md`** via the notes tools — not vendor-specific instruction filenames.
774
+ - Use **`gemcode.md`** at the project root for project instructions (run `/init` to scaffold it).
775
+ - If you need to capture project conventions while working, append to **`.gemcode/notes.md`** via the notes tools.
776
+ - Do not create vendor-specific instruction files for other assistants.
704
777
 
705
778
  """
706
779
 
707
780
  if not verbose_tools_guide:
781
+ # Keep the default instruction compact, but still allow agent-local workspaces
782
+ # (`gemcode -C .gemcode/agents/...`) to inject their constitution files.
783
+ workspace_md = _load_agent_workspace_md(cfg.project_root)
784
+ if workspace_md:
785
+ base = f"{base}\n\n{workspace_md}"
786
+ base = (
787
+ base
788
+ + "\n\n"
789
+ + "## Agent orchestration (available in normal mode)\n\n"
790
+ + "You can autonomously create and manage additional agents (org members) when it helps solve the user's request.\n"
791
+ + "Use these tools:\n"
792
+ + "- `org_list()` / `org_tree()` — discover existing agents.\n"
793
+ + "- `org_hire(name, title, kind, address, reports_to, description)` — create an agent + its workspace under `.gemcode/agents/`.\n"
794
+ + "- `org_delegate(member, task, context)` — delegate work to a member (subagent or background worker).\n"
795
+ + "- `org_spawn(name, title, kind, task, ...)` — hire + delegate in one call.\n"
796
+ + "- `org_improve(member, lessons)` — update an agent's skill for future tasks.\n"
797
+ + "\n"
798
+ + "### Auto-orchestration heuristics\n"
799
+ + "- Prefer **reuse**: call `org_list()` first; pick the best-fit existing agent by title/description/role.\n"
800
+ + "- Hire only when needed: use `org_hire(...)` to create a distinct role agent when no good fit exists.\n"
801
+ + "- Delegate broadly: use `org_delegate(...)` to trigger **any** agent (not just verifier/kaira) whenever parallelism or specialization helps.\n"
802
+ + "- Suggested defaults:\n"
803
+ + " - Independent review/sanity check → delegate to **verifier** (hire it if missing).\n"
804
+ + " - Long-running tests/build/lint/scans → delegate to a **kaira_worker** (reuse `kaira` if present).\n"
805
+ + "- Keep the fleet small: avoid spawning one-off agents for trivial tasks; prefer one good verifier + a few reusable specialists.\n"
806
+ + "- After delegation, keep progressing on the main task; merge delegated results when they arrive.\n"
807
+ + "\n"
808
+ + "### Scheduling / automations\n"
809
+ + "GemCode supports local scheduled jobs executed by the runtime daemon (Kaira) using `.gemcode/automations/*.json`.\n"
810
+ + "You can manage these in normal mode with:\n"
811
+ + "- `automations_list()` — list available automations.\n"
812
+ + "- `automations_init(name, ...)` — create an automation config.\n"
813
+ + "- `automations_run(name)` — enqueue an automation now via runtime IPC.\n"
814
+ + "\n"
815
+ + "When running GemCode from inside an agent workspace (`gemcode -C .gemcode/agents/...`), that agent may also have a local constitution under `workspace/`.\n"
816
+ )
708
817
  return base.strip() + "\n"
709
818
 
710
819
  tool_guide = r"""
@@ -1054,9 +1163,12 @@ You have two tools to persist project insights across sessions (auto-memory styl
1054
1163
  loaded_skills = _build_session_loaded_skills_section(cfg)
1055
1164
  if loaded_skills:
1056
1165
  base = f"{base}\n\n{loaded_skills}"
1166
+ workspace_md = _load_agent_workspace_md(cfg.project_root)
1167
+ if workspace_md:
1168
+ base = f"{base}\n\n{workspace_md}"
1057
1169
  extra = _load_gemini_md(cfg.project_root)
1058
1170
  if extra.strip():
1059
- return f"{base}\n\n## Project instructions (GEMINI.md)\n{extra}"
1171
+ return f"{base}\n\n## Project instructions (gemcode.md)\n{extra}"
1060
1172
  return base
1061
1173
 
1062
1174
 
@@ -1210,7 +1322,8 @@ def build_root_agent(
1210
1322
  instruction=build_instruction(cfg),
1211
1323
  tools=tools,
1212
1324
  generate_content_config=gen_cfg,
1213
- sub_agents=sub_agents or None,
1325
+ # ADK expects a list; passing None can fail validation on some versions.
1326
+ sub_agents=sub_agents,
1214
1327
  **cb_kwargs,
1215
1328
  )
1216
1329
 
@@ -357,7 +357,7 @@ async def _run_repl(cfg: GemCodeConfig, session_id: str, *, use_mcp: bool) -> No
357
357
  "- Make it **token-efficient**: prefer short checklists and explicit decision gates.\n",
358
358
  "- Avoid vague 'ALWAYS trigger' language; provide precise triggers.\n",
359
359
  "- If you need templates/checklists, create supporting files in a `references/` subfolder and keep them small.\n",
360
- "- Do not create CLAUDE.md/AGENTS.md or other vendor-specific files.\n\n",
360
+ "- Do not create vendor-specific instruction files for other assistants.\n\n",
361
361
  "## Tooling / research policy\n",
362
362
  (
363
363
  "- You MAY use web research to find best practices, but only if it materially improves the skill.\n"
@@ -895,10 +895,55 @@ def main() -> None:
895
895
  return
896
896
 
897
897
  # Kaira proactive scheduler daemon.
898
- if len(sys.argv) > 1 and sys.argv[1] == "kaira":
898
+ if len(sys.argv) > 1 and sys.argv[1] in ("kaira", "runtime"):
899
+ is_runtime = sys.argv[1] == "runtime"
900
+ # Optional attach mode: stream runtime events in this terminal.
901
+ if is_runtime and len(sys.argv) > 2 and sys.argv[2] == "attach":
902
+ attach_parser = argparse.ArgumentParser(
903
+ prog="gemcode runtime attach",
904
+ description="Attach to a running GemCode runtime and stream events.",
905
+ )
906
+ attach_parser.add_argument(
907
+ "-C",
908
+ "--directory",
909
+ type=Path,
910
+ default=Path.cwd(),
911
+ help="Project root (used for default socket path).",
912
+ )
913
+ attach_parser.add_argument(
914
+ "--socket",
915
+ default=None,
916
+ help="Override IPC socket path (default: <project>/.gemcode/ipc.sock).",
917
+ )
918
+ attach_args = attach_parser.parse_args(sys.argv[3:])
919
+ load_cli_environment()
920
+ sock = (
921
+ str(attach_args.socket)
922
+ if attach_args.socket
923
+ else str(attach_args.directory.resolve() / ".gemcode" / "ipc.sock")
924
+ )
925
+ async def _attach() -> None:
926
+ from gemcode.kaira_client import KairaIpcClient
927
+ c = await KairaIpcClient.connect(socket_path=sock)
928
+ try:
929
+ await c.subscribe()
930
+ async for msg in c.iter_messages():
931
+ if not isinstance(msg, dict):
932
+ continue
933
+ # Print raw JSONL to keep this universal for logs/tools.
934
+ print(json.dumps(msg, ensure_ascii=False), flush=True)
935
+ finally:
936
+ await c.close()
937
+ asyncio.run(_attach())
938
+ return
939
+
899
940
  kaira_parser = argparse.ArgumentParser(
900
- prog="gemcode kaira",
901
- description="Background proactive scheduler daemon (stdin -> queued jobs).",
941
+ prog=("gemcode runtime" if is_runtime else "gemcode kaira"),
942
+ description=(
943
+ "GemCode runtime daemon (shared always-on brain; stdin -> queued runs)."
944
+ if is_runtime
945
+ else "Background proactive scheduler daemon (stdin -> queued jobs)."
946
+ ),
902
947
  )
903
948
  kaira_parser.add_argument(
904
949
  "-C",
@@ -924,6 +969,11 @@ def main() -> None:
924
969
  default=0,
925
970
  help="Priority used for stdin-enqueued jobs.",
926
971
  )
972
+ kaira_parser.add_argument(
973
+ "--socket",
974
+ default=None,
975
+ help="Override IPC socket path (default: <project>/.gemcode/ipc.sock).",
976
+ )
927
977
  kaira_parser.add_argument(
928
978
  "--yes",
929
979
  action="store_true",
@@ -999,6 +1049,8 @@ def main() -> None:
999
1049
  load_cli_environment()
1000
1050
 
1001
1051
  cfg = GemCodeConfig(project_root=args.directory)
1052
+ if getattr(args, "socket", None):
1053
+ os.environ["GEMCODE_KAIRA_SOCKET"] = str(args.socket)
1002
1054
  if args.model:
1003
1055
  cfg.model_overridden = True
1004
1056
  cfg.model = args.model
@@ -1053,7 +1105,10 @@ def main() -> None:
1053
1105
  default_priority=args.default_priority,
1054
1106
  )
1055
1107
  asyncio.run(daemon.run_forever(session_id=session_id))
1056
- print(f"\n[gemcode kaira] session_id={session_id}", file=sys.stderr)
1108
+ print(
1109
+ f"\n[gemcode {'runtime' if is_runtime else 'kaira'}] session_id={session_id}",
1110
+ file=sys.stderr,
1111
+ )
1057
1112
  return
1058
1113
 
1059
1114
  parser = argparse.ArgumentParser(prog="gemcode", description="Gemini + ADK coding agent")
@@ -1064,6 +1119,12 @@ def main() -> None:
1064
1119
  help="Task or question (read from stdin if omitted)",
1065
1120
  )
1066
1121
  parser.add_argument("-C", "--directory", type=Path, default=Path.cwd(), help="Project root")
1122
+ parser.add_argument(
1123
+ "--connect",
1124
+ default=None,
1125
+ metavar="SOCKET",
1126
+ help="Connect this REPL/TUI to an existing GemCode runtime (IPC socket path).",
1127
+ )
1067
1128
  parser.add_argument("--session", default=None, help="Session id for SQLite-backed history")
1068
1129
  parser.add_argument("--yes", action="store_true", help="Allow write_file / search_replace")
1069
1130
  parser.add_argument(
@@ -1129,6 +1190,9 @@ def main() -> None:
1129
1190
  args = parser.parse_args()
1130
1191
 
1131
1192
  load_cli_environment()
1193
+ if getattr(args, "connect", None):
1194
+ os.environ["GEMCODE_KAIRA_SOCKET"] = str(args.connect)
1195
+ os.environ["GEMCODE_KAIRA_AUTO_CONNECT"] = "1"
1132
1196
  prompt = args.prompt
1133
1197
  interactive_tty = prompt is None and sys.stdin.isatty()
1134
1198
 
@@ -41,6 +41,42 @@ class KairaIpcClient:
41
41
  return obj
42
42
  # Other messages (events) are ignored here; caller should use iter_messages.
43
43
 
44
+ async def subscribe(
45
+ self,
46
+ *,
47
+ topics: list[str] | None = None,
48
+ to: list[str] | None = None,
49
+ ) -> dict[str, Any]:
50
+ """
51
+ Subscribe to server events.
52
+
53
+ Optional filters apply only to `bus_message` events; job_* events are always
54
+ delivered to all subscribed clients.
55
+ """
56
+ payload: dict[str, Any] = {}
57
+ if topics:
58
+ payload["topics"] = list(topics)
59
+ if to:
60
+ payload["to"] = list(to)
61
+ return await self.request(action="subscribe", **payload)
62
+
63
+ async def publish(
64
+ self,
65
+ *,
66
+ topic: str,
67
+ payload: Any,
68
+ to: str = "",
69
+ from_addr: str = "",
70
+ ) -> dict[str, Any]:
71
+ """Publish a `bus_message` event to all subscribed clients."""
72
+ return await self.request(
73
+ action="publish",
74
+ topic=str(topic),
75
+ to=str(to or ""),
76
+ **({"from": str(from_addr)} if from_addr else {}),
77
+ payload=payload,
78
+ )
79
+
44
80
  async def iter_messages(self) -> AsyncIterator[dict[str, Any]]:
45
81
  while True:
46
82
  line = await self.reader.readline()