gemcode 0.3.80__tar.gz → 0.3.81__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 (150) hide show
  1. {gemcode-0.3.80/src/gemcode.egg-info → gemcode-0.3.81}/PKG-INFO +2 -2
  2. {gemcode-0.3.80 → gemcode-0.3.81}/README.md +1 -1
  3. {gemcode-0.3.80 → gemcode-0.3.81}/pyproject.toml +1 -1
  4. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/agent.py +6 -5
  5. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/repl_slash.py +2 -0
  6. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/edit.py +10 -5
  7. {gemcode-0.3.80 → gemcode-0.3.81/src/gemcode.egg-info}/PKG-INFO +2 -2
  8. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_tools.py +11 -0
  9. {gemcode-0.3.80 → gemcode-0.3.81}/LICENSE +0 -0
  10. {gemcode-0.3.80 → gemcode-0.3.81}/MANIFEST.in +0 -0
  11. {gemcode-0.3.80 → gemcode-0.3.81}/setup.cfg +0 -0
  12. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/__init__.py +0 -0
  13. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/__main__.py +0 -0
  14. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/audit.py +0 -0
  15. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/autocompact.py +0 -0
  16. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/autotune.py +0 -0
  17. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/callbacks.py +0 -0
  18. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/capability_routing.py +0 -0
  19. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/checkpoints.py +0 -0
  20. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/cli.py +0 -0
  21. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/compaction.py +0 -0
  22. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/computer_use/__init__.py +0 -0
  23. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/computer_use/browser_computer.py +0 -0
  24. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/config.py +0 -0
  25. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/context_budget.py +0 -0
  26. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/context_warning.py +0 -0
  27. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/credentials.py +0 -0
  28. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/curated_memory.py +0 -0
  29. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/dynamic_policy.py +0 -0
  30. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/evals/harness.py +0 -0
  31. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/hitl_session.py +0 -0
  32. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/hooks.py +0 -0
  33. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/ide_protocol.py +0 -0
  34. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/ide_stdio.py +0 -0
  35. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/intent_classifier.py +0 -0
  36. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/interactions.py +0 -0
  37. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/invoke.py +0 -0
  38. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/kaira_daemon.py +0 -0
  39. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/learning.py +0 -0
  40. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/limits.py +0 -0
  41. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/live_audio_engine.py +0 -0
  42. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/logging_config.py +0 -0
  43. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/mcp_loader.py +0 -0
  44. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/memory/__init__.py +0 -0
  45. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/memory/embedding_memory_service.py +0 -0
  46. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/memory/file_memory_service.py +0 -0
  47. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/modality_tools.py +0 -0
  48. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/model_errors.py +0 -0
  49. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/model_routing.py +0 -0
  50. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/multimodal_input.py +0 -0
  51. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/openapi_loader.py +0 -0
  52. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/output_styles.py +0 -0
  53. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/paths.py +0 -0
  54. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/permissions.py +0 -0
  55. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/plugins/__init__.py +0 -0
  56. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/plugins/terminal_hooks_plugin.py +0 -0
  57. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/plugins/tool_recovery_plugin.py +0 -0
  58. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/policy_profile.py +0 -0
  59. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/pricing.py +0 -0
  60. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/prompt_suggestions.py +0 -0
  61. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/query/__init__.py +0 -0
  62. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/query/config.py +0 -0
  63. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/query/deps.py +0 -0
  64. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/query/engine.py +0 -0
  65. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/query/stop_hooks.py +0 -0
  66. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/query/token_budget.py +0 -0
  67. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/query/transitions.py +0 -0
  68. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/refine.py +0 -0
  69. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/repl_commands.py +0 -0
  70. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/review_agent.py +0 -0
  71. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/rules.py +0 -0
  72. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/session_runtime.py +0 -0
  73. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/session_store.py +0 -0
  74. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/skills.py +0 -0
  75. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/slash_commands.py +0 -0
  76. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/thinking.py +0 -0
  77. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tool_prompt_manifest.py +0 -0
  78. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tool_registry.py +0 -0
  79. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tool_result_store.py +0 -0
  80. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/__init__.py +0 -0
  81. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/bash.py +0 -0
  82. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/browser.py +0 -0
  83. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/curated_memory.py +0 -0
  84. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/filesystem.py +0 -0
  85. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/notebook.py +0 -0
  86. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/notes.py +0 -0
  87. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/repo_map.py +0 -0
  88. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/search.py +0 -0
  89. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/shell.py +0 -0
  90. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/shell_gate.py +0 -0
  91. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/skills.py +0 -0
  92. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/subtask.py +0 -0
  93. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/tasks.py +0 -0
  94. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/think.py +0 -0
  95. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/todo.py +0 -0
  96. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/web.py +0 -0
  97. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools/web_search.py +0 -0
  98. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tools_inspector.py +0 -0
  99. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/trust.py +0 -0
  100. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tui/input_handler.py +0 -0
  101. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tui/scrollback.py +0 -0
  102. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tui/spinner.py +0 -0
  103. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tui/welcome_banner.py +0 -0
  104. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/tui/welcome_rich.py +0 -0
  105. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/version.py +0 -0
  106. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/vertex.py +0 -0
  107. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/web/__init__.py +0 -0
  108. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/web/sse_adapter.py +0 -0
  109. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/web/terminal_repl.py +0 -0
  110. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/web/web_sse_compat.py +0 -0
  111. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode/workspace_hints.py +0 -0
  112. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode.egg-info/SOURCES.txt +0 -0
  113. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode.egg-info/dependency_links.txt +0 -0
  114. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode.egg-info/entry_points.txt +0 -0
  115. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode.egg-info/requires.txt +0 -0
  116. {gemcode-0.3.80 → gemcode-0.3.81}/src/gemcode.egg-info/top_level.txt +0 -0
  117. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_add_dir.py +0 -0
  118. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_agent_instruction.py +0 -0
  119. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_autocompact.py +0 -0
  120. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_capability_routing.py +0 -0
  121. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_checkpoint_diff_command.py +0 -0
  122. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_cli_init.py +0 -0
  123. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_computer_use_permissions.py +0 -0
  124. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_context_budget.py +0 -0
  125. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_context_warning.py +0 -0
  126. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_credentials.py +0 -0
  127. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_eval_harness_layout.py +0 -0
  128. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_ide_stdio_attachments.py +0 -0
  129. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_interactive_permission_ask.py +0 -0
  130. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_kaira_scheduler.py +0 -0
  131. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_modality_tools.py +0 -0
  132. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_model_error_retry.py +0 -0
  133. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_model_errors.py +0 -0
  134. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_model_routing.py +0 -0
  135. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_multimodal_input.py +0 -0
  136. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_output_styles_and_rules.py +0 -0
  137. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_paths.py +0 -0
  138. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_permissions.py +0 -0
  139. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_prompt_suggestions.py +0 -0
  140. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_repl_commands.py +0 -0
  141. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_repl_slash.py +0 -0
  142. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_skills.py +0 -0
  143. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_slash_commands.py +0 -0
  144. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_slash_completion_registry.py +0 -0
  145. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_thinking_config.py +0 -0
  146. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_token_budget.py +0 -0
  147. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_tool_context_circulation.py +0 -0
  148. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_tools_inspector.py +0 -0
  149. {gemcode-0.3.80 → gemcode-0.3.81}/tests/test_web_sse_adapter.py +0 -0
  150. {gemcode-0.3.80 → gemcode-0.3.81}/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.80
3
+ Version: 0.3.81
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -473,7 +473,7 @@ Tools are registered in `gemcode/tools/` and exposed to the model as ADK functio
473
473
  - **Computer use:** ADK `ComputerUseToolset` + Playwright (separate install and flags).
474
474
  - **MCP:** Tools loaded from configured servers.
475
475
 
476
- **Vendor file policy:** Writes to certain vendor-specific instruction filenames (e.g. `CLAUDE.md`, `AGENTS.md`) are blocked; use project conventions like `GEMINI.md` and curated memory files instead.
476
+ **Vendor file policy:** Writes to certain third-party instruction filenames (`CLAUDE.md`, `AGENTS.md`, `*.local` variants, `.cursorrules`, …) are blocked; use `GEMINI.md` and `.gemcode/notes.md` instead. The agent instruction always states this; `write_file` / `search_replace` enforce it.
477
477
 
478
478
  ---
479
479
 
@@ -284,7 +284,7 @@ Tools are registered in `gemcode/tools/` and exposed to the model as ADK functio
284
284
  - **Computer use:** ADK `ComputerUseToolset` + Playwright (separate install and flags).
285
285
  - **MCP:** Tools loaded from configured servers.
286
286
 
287
- **Vendor file policy:** Writes to certain vendor-specific instruction filenames (e.g. `CLAUDE.md`, `AGENTS.md`) are blocked; use project conventions like `GEMINI.md` and curated memory files instead.
287
+ **Vendor file policy:** Writes to certain third-party instruction filenames (`CLAUDE.md`, `AGENTS.md`, `*.local` variants, `.cursorrules`, …) are blocked; use `GEMINI.md` and `.gemcode/notes.md` instead. The agent instruction always states this; `write_file` / `search_replace` enforce it.
288
288
 
289
289
  ---
290
290
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "gemcode"
7
- version = "0.3.80"
7
+ version = "0.3.81"
8
8
  description = "Local-first coding agent on Google Gemini + ADK"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.11"
@@ -77,7 +77,8 @@ def build_global_instruction() -> str:
77
77
  "Think deeply about what the person actually wants before you do anything. "
78
78
  "Use exactly as many tools as the task genuinely requires — no more. "
79
79
  "Act fully and autonomously when action is needed. "
80
- "Always use read-only tools before shell or write tools."
80
+ "Always use read-only tools before shell or write tools. "
81
+ "Never create CLAUDE.md or AGENTS.md; use GEMINI.md for project instructions."
81
82
  )
82
83
 
83
84
 
@@ -580,6 +581,10 @@ You have native deep thinking capability — use it actively:
580
581
  Keep tool usage minimal. Prefer short, targeted calls and keep tool outputs small.
581
582
  If you need more tool usage examples, set `GEMCODE_VERBOSE_INSTRUCTIONS=1`.
582
583
 
584
+ ## Instruction files (GemCode — always follow)
585
+ - **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).
586
+ - 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.
587
+
583
588
  """
584
589
 
585
590
  if not verbose_tools_guide:
@@ -895,10 +900,6 @@ You have two tools to persist project insights across sessions (auto-memory styl
895
900
  Notes are loaded at session start so future sessions inherit this knowledge.
896
901
 
897
902
  - **`read_project_notes()`** — read current notes **only when starting a real engineering task** (editing, debugging, building). Do NOT call this for greetings or general questions. If notes exist and you're about to work on a task, read them once to avoid re-discovering known information.
898
-
899
- ## Do not create vendor-specific instruction files
900
- - Do NOT create or modify `CLAUDE.md` or `AGENTS.md`. GemCode does not use these.
901
- - If project instructions are needed and the user asked for it, use `GEMINI.md` (repo root).
902
903
  """
903
904
 
904
905
  # Inject capability-specific strategy sections only when those caps are on.
@@ -1045,6 +1045,8 @@ async def process_repl_slash(
1045
1045
  "3. Look at the source directory structure (src/, lib/, app/, etc.)\n"
1046
1046
  "4. Check for test directories and test runner config\n"
1047
1047
  "5. Look for linting/formatting config files (.eslintrc, .prettierrc, ruff.toml, etc.)\n\n"
1048
+ "Write **only** to `GEMINI.md` at the project root. Do **not** create "
1049
+ "`CLAUDE.md`, `AGENTS.md`, `.cursorrules`, or similar.\n\n"
1048
1050
  "Then write a GEMINI.md file at the project root containing:\n"
1049
1051
  "# Project Name\n"
1050
1052
  "One-sentence description.\n\n"
@@ -23,11 +23,16 @@ def make_edit_tools(cfg: GemCodeConfig):
23
23
  except Exception:
24
24
  pass
25
25
 
26
- # Block writes to common non-GemCode agent instruction filenames.
27
- _BLOCKED_SPECIAL_FILES = {
28
- "claude.md",
29
- "agents.md",
30
- }
26
+ # Block writes to common non-GemCode / third-party agent instruction filenames.
27
+ _BLOCKED_SPECIAL_FILES = frozenset(
28
+ {
29
+ "claude.md",
30
+ "agents.md",
31
+ "claude.local.md",
32
+ "agents.local.md",
33
+ ".cursorrules",
34
+ }
35
+ )
31
36
 
32
37
  def _blocked_special_path(path: str) -> str | None:
33
38
  try:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: gemcode
3
- Version: 0.3.80
3
+ Version: 0.3.81
4
4
  Summary: Local-first coding agent on Google Gemini + ADK
5
5
  Author: GemCode Contributors
6
6
  License: Apache License
@@ -473,7 +473,7 @@ Tools are registered in `gemcode/tools/` and exposed to the model as ADK functio
473
473
  - **Computer use:** ADK `ComputerUseToolset` + Playwright (separate install and flags).
474
474
  - **MCP:** Tools loaded from configured servers.
475
475
 
476
- **Vendor file policy:** Writes to certain vendor-specific instruction filenames (e.g. `CLAUDE.md`, `AGENTS.md`) are blocked; use project conventions like `GEMINI.md` and curated memory files instead.
476
+ **Vendor file policy:** Writes to certain third-party instruction filenames (`CLAUDE.md`, `AGENTS.md`, `*.local` variants, `.cursorrules`, …) are blocked; use `GEMINI.md` and `.gemcode/notes.md` instead. The agent instruction always states this; `write_file` / `search_replace` enforce it.
477
477
 
478
478
  ---
479
479
 
@@ -153,3 +153,14 @@ def test_search_replace(tmp_path: Path) -> None:
153
153
  out = search_replace("f.py", "a = 1", "a = 2")
154
154
  assert "error" not in out
155
155
  assert (tmp_path / "f.py").read_text() == "a = 2\n"
156
+
157
+
158
+ def test_write_file_blocks_vendor_instruction_filenames(tmp_path: Path) -> None:
159
+ cfg = GemCodeConfig(project_root=tmp_path)
160
+ write_file, _ = make_edit_tools(cfg)
161
+ for rel in ("CLAUDE.md", "docs/AGENTS.md", ".cursorrules", "claude.local.md"):
162
+ out = write_file(rel, "# no\n")
163
+ assert out.get("error_kind") == "blocked_special_file", rel
164
+ assert not (tmp_path / "CLAUDE.md").exists()
165
+ assert not (tmp_path / ".cursorrules").exists()
166
+ assert not (tmp_path / "docs" / "AGENTS.md").exists()
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes