gobby 0.2.6__py3-none-any.whl → 0.2.7__py3-none-any.whl

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 (146) hide show
  1. gobby/__init__.py +1 -1
  2. gobby/adapters/__init__.py +2 -1
  3. gobby/adapters/codex_impl/__init__.py +28 -0
  4. gobby/adapters/codex_impl/adapter.py +722 -0
  5. gobby/adapters/codex_impl/client.py +679 -0
  6. gobby/adapters/codex_impl/protocol.py +20 -0
  7. gobby/adapters/codex_impl/types.py +68 -0
  8. gobby/agents/definitions.py +11 -1
  9. gobby/agents/isolation.py +395 -0
  10. gobby/agents/sandbox.py +261 -0
  11. gobby/agents/spawn.py +42 -287
  12. gobby/agents/spawn_executor.py +385 -0
  13. gobby/agents/spawners/__init__.py +24 -0
  14. gobby/agents/spawners/command_builder.py +189 -0
  15. gobby/agents/spawners/embedded.py +21 -2
  16. gobby/agents/spawners/headless.py +21 -2
  17. gobby/agents/spawners/prompt_manager.py +125 -0
  18. gobby/cli/install.py +4 -4
  19. gobby/cli/installers/claude.py +6 -0
  20. gobby/cli/installers/gemini.py +6 -0
  21. gobby/cli/installers/shared.py +103 -4
  22. gobby/cli/sessions.py +1 -1
  23. gobby/cli/utils.py +9 -2
  24. gobby/config/__init__.py +12 -97
  25. gobby/config/app.py +10 -94
  26. gobby/config/extensions.py +2 -2
  27. gobby/config/features.py +7 -130
  28. gobby/config/tasks.py +4 -28
  29. gobby/hooks/__init__.py +0 -13
  30. gobby/hooks/event_handlers.py +45 -2
  31. gobby/hooks/hook_manager.py +2 -2
  32. gobby/hooks/plugins.py +1 -1
  33. gobby/hooks/webhooks.py +1 -1
  34. gobby/llm/resolver.py +3 -2
  35. gobby/mcp_proxy/importer.py +62 -4
  36. gobby/mcp_proxy/instructions.py +2 -0
  37. gobby/mcp_proxy/registries.py +1 -4
  38. gobby/mcp_proxy/services/recommendation.py +43 -11
  39. gobby/mcp_proxy/tools/agents.py +31 -731
  40. gobby/mcp_proxy/tools/clones.py +0 -385
  41. gobby/mcp_proxy/tools/memory.py +2 -2
  42. gobby/mcp_proxy/tools/sessions/__init__.py +14 -0
  43. gobby/mcp_proxy/tools/sessions/_commits.py +232 -0
  44. gobby/mcp_proxy/tools/sessions/_crud.py +253 -0
  45. gobby/mcp_proxy/tools/sessions/_factory.py +63 -0
  46. gobby/mcp_proxy/tools/sessions/_handoff.py +499 -0
  47. gobby/mcp_proxy/tools/sessions/_messages.py +138 -0
  48. gobby/mcp_proxy/tools/skills/__init__.py +14 -29
  49. gobby/mcp_proxy/tools/spawn_agent.py +417 -0
  50. gobby/mcp_proxy/tools/tasks/_lifecycle.py +52 -18
  51. gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +1 -1
  52. gobby/mcp_proxy/tools/worktrees.py +0 -343
  53. gobby/memory/ingestion/__init__.py +5 -0
  54. gobby/memory/ingestion/multimodal.py +221 -0
  55. gobby/memory/manager.py +62 -283
  56. gobby/memory/search/__init__.py +10 -0
  57. gobby/memory/search/coordinator.py +248 -0
  58. gobby/memory/services/__init__.py +5 -0
  59. gobby/memory/services/crossref.py +142 -0
  60. gobby/prompts/loader.py +5 -2
  61. gobby/servers/http.py +1 -4
  62. gobby/servers/routes/admin.py +14 -0
  63. gobby/servers/routes/mcp/endpoints/__init__.py +61 -0
  64. gobby/servers/routes/mcp/endpoints/discovery.py +405 -0
  65. gobby/servers/routes/mcp/endpoints/execution.py +568 -0
  66. gobby/servers/routes/mcp/endpoints/registry.py +378 -0
  67. gobby/servers/routes/mcp/endpoints/server.py +304 -0
  68. gobby/servers/routes/mcp/hooks.py +1 -1
  69. gobby/servers/routes/mcp/tools.py +48 -1506
  70. gobby/sessions/lifecycle.py +1 -1
  71. gobby/sessions/processor.py +10 -0
  72. gobby/sessions/transcripts/base.py +1 -0
  73. gobby/sessions/transcripts/claude.py +15 -5
  74. gobby/skills/parser.py +30 -2
  75. gobby/storage/migrations.py +159 -372
  76. gobby/storage/sessions.py +43 -7
  77. gobby/storage/skills.py +37 -4
  78. gobby/storage/tasks/_lifecycle.py +18 -3
  79. gobby/sync/memories.py +1 -1
  80. gobby/tasks/external_validator.py +1 -1
  81. gobby/tasks/validation.py +22 -20
  82. gobby/tools/summarizer.py +91 -10
  83. gobby/utils/project_context.py +2 -3
  84. gobby/utils/status.py +13 -0
  85. gobby/workflows/actions.py +221 -1217
  86. gobby/workflows/artifact_actions.py +31 -0
  87. gobby/workflows/autonomous_actions.py +11 -0
  88. gobby/workflows/context_actions.py +50 -1
  89. gobby/workflows/enforcement/__init__.py +47 -0
  90. gobby/workflows/enforcement/blocking.py +269 -0
  91. gobby/workflows/enforcement/commit_policy.py +283 -0
  92. gobby/workflows/enforcement/handlers.py +269 -0
  93. gobby/workflows/enforcement/task_policy.py +542 -0
  94. gobby/workflows/git_utils.py +106 -0
  95. gobby/workflows/llm_actions.py +30 -0
  96. gobby/workflows/mcp_actions.py +20 -1
  97. gobby/workflows/memory_actions.py +80 -0
  98. gobby/workflows/safe_evaluator.py +183 -0
  99. gobby/workflows/session_actions.py +44 -0
  100. gobby/workflows/state_actions.py +60 -1
  101. gobby/workflows/stop_signal_actions.py +55 -0
  102. gobby/workflows/summary_actions.py +94 -1
  103. gobby/workflows/task_sync_actions.py +347 -0
  104. gobby/workflows/todo_actions.py +34 -1
  105. gobby/workflows/webhook_actions.py +185 -0
  106. {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/METADATA +6 -1
  107. {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/RECORD +111 -111
  108. {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/WHEEL +1 -1
  109. gobby/adapters/codex.py +0 -1332
  110. gobby/install/claude/commands/gobby/bug.md +0 -51
  111. gobby/install/claude/commands/gobby/chore.md +0 -51
  112. gobby/install/claude/commands/gobby/epic.md +0 -52
  113. gobby/install/claude/commands/gobby/eval.md +0 -235
  114. gobby/install/claude/commands/gobby/feat.md +0 -49
  115. gobby/install/claude/commands/gobby/nit.md +0 -52
  116. gobby/install/claude/commands/gobby/ref.md +0 -52
  117. gobby/mcp_proxy/tools/session_messages.py +0 -1055
  118. gobby/prompts/defaults/expansion/system.md +0 -119
  119. gobby/prompts/defaults/expansion/user.md +0 -48
  120. gobby/prompts/defaults/external_validation/agent.md +0 -72
  121. gobby/prompts/defaults/external_validation/external.md +0 -63
  122. gobby/prompts/defaults/external_validation/spawn.md +0 -83
  123. gobby/prompts/defaults/external_validation/system.md +0 -6
  124. gobby/prompts/defaults/features/import_mcp.md +0 -22
  125. gobby/prompts/defaults/features/import_mcp_github.md +0 -17
  126. gobby/prompts/defaults/features/import_mcp_search.md +0 -16
  127. gobby/prompts/defaults/features/recommend_tools.md +0 -32
  128. gobby/prompts/defaults/features/recommend_tools_hybrid.md +0 -35
  129. gobby/prompts/defaults/features/recommend_tools_llm.md +0 -30
  130. gobby/prompts/defaults/features/server_description.md +0 -20
  131. gobby/prompts/defaults/features/server_description_system.md +0 -6
  132. gobby/prompts/defaults/features/task_description.md +0 -31
  133. gobby/prompts/defaults/features/task_description_system.md +0 -6
  134. gobby/prompts/defaults/features/tool_summary.md +0 -17
  135. gobby/prompts/defaults/features/tool_summary_system.md +0 -6
  136. gobby/prompts/defaults/handoff/compact.md +0 -63
  137. gobby/prompts/defaults/handoff/session_end.md +0 -57
  138. gobby/prompts/defaults/memory/extract.md +0 -61
  139. gobby/prompts/defaults/research/step.md +0 -58
  140. gobby/prompts/defaults/validation/criteria.md +0 -47
  141. gobby/prompts/defaults/validation/validate.md +0 -38
  142. gobby/storage/migrations_legacy.py +0 -1359
  143. gobby/workflows/task_enforcement_actions.py +0 -1343
  144. {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/entry_points.txt +0 -0
  145. {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/licenses/LICENSE.md +0 -0
  146. {gobby-0.2.6.dist-info → gobby-0.2.7.dist-info}/top_level.txt +0 -0
gobby/config/app.py CHANGED
@@ -15,14 +15,8 @@ from typing import Any
15
15
  import yaml
16
16
  from pydantic import BaseModel, Field, field_validator
17
17
 
18
- from gobby.config.extensions import (
19
- HookExtensionsConfig,
20
- PluginItemConfig,
21
- PluginsConfig,
22
- WebhookEndpointConfig,
23
- WebhooksConfig,
24
- WebSocketBroadcastConfig,
25
- )
18
+ # Internal imports for DaemonConfig fields - NOT re-exported
19
+ from gobby.config.extensions import HookExtensionsConfig
26
20
  from gobby.config.features import (
27
21
  ImportMCPServerConfig,
28
22
  MetricsConfig,
@@ -31,14 +25,9 @@ from gobby.config.features import (
31
25
  TaskDescriptionConfig,
32
26
  ToolSummarizerConfig,
33
27
  )
34
-
35
- # Re-export from extracted modules (Strangler Fig pattern for backwards compatibility)
36
- from gobby.config.llm_providers import LLMProviderConfig, LLMProvidersConfig
28
+ from gobby.config.llm_providers import LLMProvidersConfig
37
29
  from gobby.config.logging import LoggingSettings
38
- from gobby.config.persistence import (
39
- MemoryConfig,
40
- MemorySyncConfig,
41
- )
30
+ from gobby.config.persistence import MemoryConfig, MemorySyncConfig
42
31
  from gobby.config.search import SearchConfig
43
32
  from gobby.config.servers import MCPClientProxyConfig, WebSocketSettings
44
33
  from gobby.config.sessions import (
@@ -50,61 +39,10 @@ from gobby.config.sessions import (
50
39
  TitleSynthesisConfig,
51
40
  )
52
41
  from gobby.config.skills import SkillsConfig
53
- from gobby.config.tasks import (
54
- CompactHandoffConfig,
55
- GobbyTasksConfig,
56
- PatternCriteriaConfig,
57
- TaskExpansionConfig,
58
- TaskValidationConfig,
59
- WorkflowConfig,
60
- )
42
+ from gobby.config.tasks import CompactHandoffConfig, GobbyTasksConfig, WorkflowConfig
61
43
 
62
- # Explicit exports for mypy (re-exported symbols from submodules)
63
44
  __all__ = [
64
- # From gobby.config.extensions
65
- "HookExtensionsConfig",
66
- "PluginItemConfig",
67
- "PluginsConfig",
68
- "WebhookEndpointConfig",
69
- "WebhooksConfig",
70
- "WebSocketBroadcastConfig",
71
- # From gobby.config.features
72
- "ImportMCPServerConfig",
73
- "MetricsConfig",
74
- "ProjectVerificationConfig",
75
- "RecommendToolsConfig",
76
- "TaskDescriptionConfig",
77
- "ToolSummarizerConfig",
78
- # From gobby.config.llm_providers
79
- "LLMProviderConfig",
80
- "LLMProvidersConfig",
81
- # From gobby.config.logging
82
- "LoggingSettings",
83
- # From gobby.config.persistence
84
- "MemoryConfig",
85
- "MemorySyncConfig",
86
- # From gobby.config.search
87
- "SearchConfig",
88
- # From gobby.config.servers
89
- "MCPClientProxyConfig",
90
- "WebSocketSettings",
91
- # From gobby.config.skills
92
- "SkillsConfig",
93
- # From gobby.config.sessions
94
- "ArtifactHandoffConfig",
95
- "ContextInjectionConfig",
96
- "MessageTrackingConfig",
97
- "SessionLifecycleConfig",
98
- "SessionSummaryConfig",
99
- "TitleSynthesisConfig",
100
- # From gobby.config.tasks
101
- "CompactHandoffConfig",
102
- "GobbyTasksConfig",
103
- "PatternCriteriaConfig",
104
- "TaskExpansionConfig",
105
- "TaskValidationConfig",
106
- "WorkflowConfig",
107
- # Local definitions
45
+ # Local definitions only - no re-exports
108
46
  "ConductorConfig",
109
47
  "DaemonConfig",
110
48
  "expand_env_vars",
@@ -184,32 +122,6 @@ def expand_env_vars(content: str) -> str:
184
122
  return ENV_VAR_PATTERN.sub(replace_match, content)
185
123
 
186
124
 
187
- # WebSocketSettings moved to gobby.config.servers (re-exported above)
188
- # LoggingSettings moved to gobby.config.logging (re-exported above)
189
- # CompactHandoffConfig moved to gobby.config.tasks (re-exported above)
190
-
191
- # ContextInjectionConfig, SessionSummaryConfig, TitleSynthesisConfig,
192
- # MessageTrackingConfig, SessionLifecycleConfig
193
- # moved to gobby.config.sessions (re-exported above)
194
-
195
- # ToolSummarizerConfig, RecommendToolsConfig, ImportMCPServerConfig,
196
- # MetricsConfig, ProjectVerificationConfig
197
- # moved to gobby.config.features (re-exported above)
198
-
199
- # WebSocketBroadcastConfig, WebhookEndpointConfig, WebhooksConfig,
200
- # PluginItemConfig, PluginsConfig, HookExtensionsConfig
201
- # moved to gobby.config.extensions (re-exported above)
202
-
203
- # PatternCriteriaConfig, TaskExpansionConfig, TaskValidationConfig, WorkflowConfig,
204
- # GobbyTasksConfig, CompactHandoffConfig
205
- # moved to gobby.config.tasks (re-exported above)
206
-
207
- # MCPClientProxyConfig moved to gobby.config.servers (re-exported above)
208
- # LLMProviderConfig and LLMProvidersConfig moved to gobby.config.llm_providers (re-exported above)
209
- # MemoryConfig, MemorySyncConfig
210
- # moved to gobby.config.persistence (re-exported above)
211
-
212
-
213
125
  class DaemonConfig(BaseModel):
214
126
  """
215
127
  Main configuration for Gobby daemon.
@@ -243,6 +155,10 @@ class DaemonConfig(BaseModel):
243
155
  default="~/.gobby/gobby-hub.db",
244
156
  description="Path to hub database for cross-project queries.",
245
157
  )
158
+ use_flattened_baseline: bool = Field(
159
+ default=True,
160
+ description="Use flattened V2 baseline schema (v75) for new databases instead of legacy migrations.",
161
+ )
246
162
 
247
163
  # Sub-configs
248
164
  websocket: WebSocketSettings = Field(
@@ -137,8 +137,8 @@ class PluginsConfig(BaseModel):
137
137
  description="Enable plugin system (disabled by default for security)",
138
138
  )
139
139
  plugin_dirs: list[str] = Field(
140
- default_factory=lambda: ["~/.gobby/plugins", ".gobby/plugins"],
141
- description="Directories to scan for plugins (supports ~ expansion)",
140
+ default_factory=lambda: [".gobby/plugins"],
141
+ description="Directories to scan for plugins (project-scoped)",
142
142
  )
143
143
  auto_discover: bool = Field(
144
144
  default=True,
gobby/config/features.py CHANGED
@@ -42,45 +42,22 @@ class ToolSummarizerConfig(BaseModel):
42
42
  default="claude-haiku-4-5",
43
43
  description="Model to use for summarization (fast/cheap recommended)",
44
44
  )
45
- prompt: str = Field(
46
- default="""Summarize this MCP tool description in 180 characters or less.
47
- Keep it to three sentences or less. Be concise and preserve the key functionality.
48
- Do not add quotes, extra formatting, or code examples.
49
45
 
50
- Description: {description}
51
-
52
- Summary:""",
53
- description="DEPRECATED: Use prompt_path instead. Prompt template for tool description summarization",
54
- )
55
46
  prompt_path: str | None = Field(
56
47
  default=None,
57
48
  description="Path to custom tool summary prompt template (e.g., 'features/tool_summary')",
58
49
  )
59
- system_prompt: str = Field(
60
- default="You are a technical summarizer. Create concise tool descriptions.",
61
- description="DEPRECATED: Use system_prompt_path instead. System prompt for tool description summarization",
62
- )
50
+
63
51
  system_prompt_path: str | None = Field(
64
52
  default=None,
65
53
  description="Path to custom tool summary system prompt (e.g., 'features/tool_summary_system')",
66
54
  )
67
- server_description_prompt: str = Field(
68
- default="""Write a single concise sentence describing what the '{server_name}' MCP server does based on its tools.
69
55
 
70
- Tools:
71
- {tools_list}
72
-
73
- Description (1 sentence, try to keep under 100 characters):""",
74
- description="DEPRECATED: Use server_description_prompt_path instead. Prompt template for server description generation",
75
- )
76
56
  server_description_prompt_path: str | None = Field(
77
57
  default=None,
78
58
  description="Path to custom server description prompt (e.g., 'features/server_description')",
79
59
  )
80
- server_description_system_prompt: str = Field(
81
- default="You write concise technical descriptions.",
82
- description="DEPRECATED: Use server_description_system_prompt_path instead. System prompt for server description generation",
83
- )
60
+
84
61
  server_description_system_prompt_path: str | None = Field(
85
62
  default=None,
86
63
  description="Path to custom server description system prompt (e.g., 'features/server_description_system')",
@@ -110,26 +87,12 @@ class TaskDescriptionConfig(BaseModel):
110
87
  default=50,
111
88
  description="Minimum length of structured extraction before LLM fallback triggers",
112
89
  )
113
- prompt: str = Field(
114
- default="""Generate a concise task description for this task from a spec document.
115
-
116
- Task title: {task_title}
117
- Section: {section_title}
118
- Section content: {section_content}
119
- Existing context: {existing_context}
120
90
 
121
- Write a 1-2 sentence description focusing on the goal and deliverable.
122
- Do not add quotes, extra formatting, or implementation details.""",
123
- description="DEPRECATED: Use prompt_path instead. Prompt template for task description generation",
124
- )
125
91
  prompt_path: str | None = Field(
126
92
  default=None,
127
93
  description="Path to custom task description prompt (e.g., 'features/task_description')",
128
94
  )
129
- system_prompt: str = Field(
130
- default="You are a technical writer creating concise task descriptions for developers.",
131
- description="DEPRECATED: Use system_prompt_path instead. System prompt for task description generation",
132
- )
95
+
133
96
  system_prompt_path: str | None = Field(
134
97
  default=None,
135
98
  description="Path to custom task description system prompt (e.g., 'features/task_description_system')",
@@ -159,83 +122,17 @@ class RecommendToolsConfig(BaseModel):
159
122
  default="claude-sonnet-4-5",
160
123
  description="Model to use for tool recommendations",
161
124
  )
162
- prompt: str = Field(
163
- default="""You are a tool recommendation assistant for Claude Code with access to MCP servers.
164
-
165
- CRITICAL PRIORITIZATION RULES:
166
- 1. Analyze the task type (code navigation, docs lookup, database query, planning, data processing, etc.)
167
- 2. Check available MCP server DESCRIPTIONS for capability matches
168
- 3. If ANY MCP server's description matches the task type -> recommend those tools FIRST
169
- 4. Only recommend built-in Claude Code tools (Grep, Read, Bash, WebSearch) if NO suitable MCP server exists
170
-
171
- TASK TYPE MATCHING GUIDELINES:
172
- - Task needs library/framework documentation -> Look for MCP servers describing "documentation", "library docs", "API reference"
173
- - Task needs code navigation/architecture understanding -> Look for MCP servers describing "code analysis", "symbols", "semantic search"
174
- - Task needs database operations -> Look for MCP servers describing "database", "PostgreSQL", "SQL"
175
- - Task needs complex reasoning/planning -> Look for MCP servers describing "problem-solving", "thinking", "reasoning"
176
- - Task needs data processing/large datasets -> Look for MCP servers describing "code execution", "data processing", "token optimization"
177
-
178
- ANTI-PATTERNS (What NOT to recommend):
179
- - Don't recommend WebSearch when an MCP server provides library/framework documentation
180
- - Don't recommend Grep/Read for code architecture questions when an MCP server does semantic code analysis
181
- - Don't recommend Bash for database queries when an MCP server provides database tools
182
- - Don't recommend direct implementation when an MCP server provides structured reasoning
183
-
184
- OUTPUT FORMAT:
185
- Be concise and specific. Recommend 1-3 tools maximum with:
186
- 1. Which MCP server and tools to use (if applicable)
187
- 2. Brief rationale based on server description matching task type
188
- 3. Suggested workflow (e.g., "First call X, then use result with Y")
189
- 4. Only mention built-in tools if no MCP server is suitable""",
190
- description="DEPRECATED: Use prompt_path instead. System prompt for recommend_tools() MCP tool.",
191
- )
125
+
192
126
  prompt_path: str | None = Field(
193
127
  default=None,
194
128
  description="Path to custom recommend tools system prompt (e.g., 'features/recommend_tools')",
195
129
  )
196
- hybrid_rerank_prompt: str = Field(
197
- default="""You are an expert at selecting tools for tasks.
198
- Task: {task_description}
199
-
200
- Candidate tools (ranked by semantic similarity):
201
- {candidate_list}
202
-
203
- Re-rank these tools by relevance to the task and provide reasoning.
204
- Return the top {top_k} most relevant as JSON:
205
- {{
206
- "recommendations": [
207
- {{
208
- "server": "server_name",
209
- "tool": "tool_name",
210
- "reason": "Why this tool is the best choice"
211
- }}
212
- ]
213
- }}""",
214
- description="DEPRECATED: Use hybrid_rerank_prompt_path instead. Prompt template for hybrid mode re-ranking",
215
- )
130
+
216
131
  hybrid_rerank_prompt_path: str | None = Field(
217
132
  default=None,
218
133
  description="Path to custom hybrid re-rank prompt (e.g., 'features/recommend_tools_hybrid')",
219
134
  )
220
- llm_prompt: str = Field(
221
- default="""You are an expert at selecting the right tools for a given task.
222
- Task: {task_description}
223
-
224
- Available Servers: {available_servers}
225
-
226
- Please recommend which tools from these servers would be most useful for this task.
227
- Return a JSON object with this structure:
228
- {{
229
- "recommendations": [
230
- {{
231
- "server": "server_name",
232
- "tool": "tool_name",
233
- "reason": "Why this tool is useful"
234
- }}
235
- ]
236
- }}""",
237
- description="DEPRECATED: Use llm_prompt_path instead. Prompt template for LLM mode recommendations",
238
- )
135
+
239
136
  llm_prompt_path: str | None = Field(
240
137
  default=None,
241
138
  description="Path to custom LLM recommendation prompt (e.g., 'features/recommend_tools_llm')",
@@ -276,37 +173,17 @@ class ImportMCPServerConfig(BaseModel):
276
173
  default="claude-haiku-4-5",
277
174
  description="Model to use for config extraction",
278
175
  )
279
- prompt: str = Field(
280
- default=DEFAULT_IMPORT_MCP_SERVER_PROMPT,
281
- description="DEPRECATED: Use prompt_path instead. System prompt for MCP server config extraction",
282
- )
176
+
283
177
  prompt_path: str | None = Field(
284
178
  default=None,
285
179
  description="Path to custom import MCP system prompt (e.g., 'features/import_mcp')",
286
180
  )
287
- github_fetch_prompt: str = Field(
288
- default="""Fetch the README from this GitHub repository and extract MCP server configuration:
289
-
290
- {github_url}
291
-
292
- If the URL doesn't point directly to a README, try to find and fetch the README.md file.
293
181
 
294
- After reading the documentation, extract the MCP server configuration as a JSON object.""",
295
- description="DEPRECATED: Use github_fetch_prompt_path instead. User prompt template for GitHub import",
296
- )
297
182
  github_fetch_prompt_path: str | None = Field(
298
183
  default=None,
299
184
  description="Path to custom GitHub fetch prompt (e.g., 'features/import_mcp_github')",
300
185
  )
301
- search_fetch_prompt: str = Field(
302
- default="""Search for MCP server: {search_query}
303
-
304
- Find the official documentation or GitHub repository for this MCP server.
305
- Then fetch and read the README or installation docs.
306
186
 
307
- After reading the documentation, extract the MCP server configuration as a JSON object.""",
308
- description="DEPRECATED: Use search_fetch_prompt_path instead. User prompt template for search-based import",
309
- )
310
187
  search_fetch_prompt_path: str | None = Field(
311
188
  default=None,
312
189
  description="Path to custom search fetch prompt (e.g., 'features/import_mcp_search')",
gobby/config/tasks.py CHANGED
@@ -38,14 +38,6 @@ class CompactHandoffConfig(BaseModel):
38
38
  default=True,
39
39
  description="Enable compact handoff context extraction and injection",
40
40
  )
41
- # DEPRECATED: prompt field is no longer used.
42
- # Template is now defined in session-handoff.yaml workflow file.
43
- # Kept for backwards compatibility but will be removed in a future version.
44
- prompt: str | None = Field(
45
- default=None,
46
- description="DEPRECATED: Template moved to session-handoff.yaml workflow. "
47
- "This field is ignored.",
48
- )
49
41
 
50
42
 
51
43
  class PatternCriteriaConfig(BaseModel):
@@ -147,10 +139,7 @@ class TaskExpansionConfig(BaseModel):
147
139
  default="claude-opus-4-5",
148
140
  description="Model to use for expansion",
149
141
  )
150
- prompt: str | None = Field(
151
- default=None,
152
- description="DEPRECATED: Use prompt_path instead. Custom prompt template for task expansion",
153
- )
142
+
154
143
  prompt_path: str | None = Field(
155
144
  default=None,
156
145
  description="Path to custom user prompt template (e.g., 'expansion/user')",
@@ -175,14 +164,7 @@ class TaskExpansionConfig(BaseModel):
175
164
  default="You are a senior developer researching a codebase. Use tools to find relevant code.",
176
165
  description="System prompt for the research agent",
177
166
  )
178
- system_prompt: str | None = Field(
179
- default=None,
180
- description="DEPRECATED: Use system_prompt_path instead. Custom system prompt for task expansion",
181
- )
182
- tdd_prompt: str | None = Field(
183
- default=None,
184
- description="DEPRECATED: TDD instructions are now embedded in task descriptions for code/config categories",
185
- )
167
+
186
168
  web_research_enabled: bool = Field(
187
169
  default=True,
188
170
  description="Enable web research for task expansion using MCP tools",
@@ -228,10 +210,7 @@ class TaskValidationConfig(BaseModel):
228
210
  default="You are a QA validator. Output ONLY valid JSON. No markdown, no explanation, no code blocks. Just the raw JSON object.",
229
211
  description="System prompt for task validation",
230
212
  )
231
- prompt: str | None = Field(
232
- default=None,
233
- description="DEPRECATED: Use prompt_path instead. Custom prompt template for task validation",
234
- )
213
+
235
214
  prompt_path: str | None = Field(
236
215
  default=None,
237
216
  description="Path to custom validation prompt template (e.g., 'validation/validate')",
@@ -260,10 +239,7 @@ class TaskValidationConfig(BaseModel):
260
239
  default="You are a QA engineer writing acceptance criteria. CRITICAL: Only include requirements explicitly stated in the task. Do NOT invent specific values, thresholds, timeouts, or edge cases that aren't mentioned. Vague tasks get vague criteria. Use markdown checkboxes.",
261
240
  description="System prompt for generating validation criteria",
262
241
  )
263
- criteria_prompt: str | None = Field(
264
- default=None,
265
- description="DEPRECATED: Use criteria_prompt_path instead. Custom prompt template for generating validation criteria",
266
- )
242
+
267
243
  # Validation loop control
268
244
  max_iterations: int = Field(
269
245
  default=10,
gobby/hooks/__init__.py CHANGED
@@ -65,14 +65,6 @@ from gobby.hooks.plugins import (
65
65
  from gobby.hooks.session_coordinator import SessionCoordinator
66
66
  from gobby.hooks.webhooks import WebhookDispatcher
67
67
 
68
- # Legacy imports for backward compatibility
69
- from gobby.sessions.manager import SessionManager
70
- from gobby.sessions.summary import SummaryFileGenerator
71
- from gobby.sessions.transcripts.claude import ClaudeTranscriptParser
72
-
73
- # Backward-compatible alias
74
- TranscriptProcessor = ClaudeTranscriptParser
75
-
76
68
  __all__ = [
77
69
  # Core coordinator
78
70
  "HookManager",
@@ -96,9 +88,4 @@ __all__ = [
96
88
  "RegisteredHandler",
97
89
  "hook_handler",
98
90
  "run_plugin_handlers",
99
- # Legacy exports (backward compatibility)
100
- "SessionManager",
101
- "SummaryFileGenerator",
102
- "TranscriptProcessor",
103
- "ClaudeTranscriptParser",
104
91
  ]
@@ -29,6 +29,16 @@ if TYPE_CHECKING:
29
29
  from gobby.workflows.hooks import WorkflowHookHandler
30
30
 
31
31
 
32
+ EDIT_TOOLS = {
33
+ "write_file",
34
+ "replace",
35
+ "edit_file",
36
+ "notebook_edit",
37
+ "edit",
38
+ "write",
39
+ }
40
+
41
+
32
42
  class EventHandlers:
33
43
  """
34
44
  Manages event handler registration and dispatch.
@@ -221,7 +231,12 @@ class EventHandlers:
221
231
  self.logger.warning(f"Workflow error: {e}")
222
232
 
223
233
  # Build system message (terminal display only)
224
- system_message = f"\nGobby Session ID: {session_id}"
234
+ # Display #N format if seq_num available, fallback to UUID
235
+ session_ref = (
236
+ f"#{existing_session.seq_num}" if existing_session.seq_num else session_id
237
+ )
238
+ system_message = f"\nGobby Session Ref: {session_ref}"
239
+ system_message += f"\nGobby Session ID: {session_id}"
225
240
  system_message += f"\nExternal ID: {external_id}"
226
241
  if parent_session_id:
227
242
  context_parts.append(f"Parent session: {parent_session_id}")
@@ -333,7 +348,14 @@ class EventHandlers:
333
348
  context_parts.append(f"Parent session: {parent_session_id}")
334
349
 
335
350
  # Build system message (terminal display only)
336
- system_message = f"\nGobby Session ID: {session_id}"
351
+ # Fetch session to get seq_num for #N display
352
+ session_ref = session_id # fallback
353
+ if session_id and self._session_storage:
354
+ session_obj = self._session_storage.get(session_id)
355
+ if session_obj and session_obj.seq_num:
356
+ session_ref = f"#{session_obj.seq_num}"
357
+ system_message = f"\nGobby Session Ref: {session_ref}"
358
+ system_message += f"\nGobby Session ID: {session_id}"
337
359
  system_message += f"\nExternal ID: {external_id}"
338
360
 
339
361
  # Add active lifecycle workflows
@@ -691,6 +713,27 @@ class EventHandlers:
691
713
  status = "FAIL" if is_failure else "OK"
692
714
  if session_id:
693
715
  self.logger.debug(f"AFTER_TOOL [{status}]: {tool_name}, session {session_id}")
716
+
717
+ # Track edits for session high-water mark
718
+ # Only if tool succeeded, matches edit tools, and session has claimed a task
719
+ if (
720
+ not is_failure
721
+ and tool_name
722
+ and tool_name.lower() in EDIT_TOOLS
723
+ and self._session_storage
724
+ and self._task_manager
725
+ ):
726
+ try:
727
+ # Check if session has any claimed tasks in progress
728
+ claimed_tasks = self._task_manager.list_tasks(
729
+ assignee=session_id, status="in_progress", limit=1
730
+ )
731
+ if claimed_tasks:
732
+ self._session_storage.mark_had_edits(session_id)
733
+ self.logger.debug(f"Marked session {session_id} as had_edits")
734
+ except Exception as e:
735
+ self.logger.warning(f"Failed to track edit history: {e}")
736
+
694
737
  else:
695
738
  self.logger.debug(f"AFTER_TOOL [{status}]: {tool_name}")
696
739
 
@@ -228,7 +228,7 @@ class HookManager:
228
228
  )
229
229
 
230
230
  if not memory_config:
231
- from gobby.config.app import MemoryConfig
231
+ from gobby.config.persistence import MemoryConfig
232
232
 
233
233
  memory_config = MemoryConfig()
234
234
 
@@ -316,7 +316,7 @@ class HookManager:
316
316
  if self._config and hasattr(self._config, "hook_extensions"):
317
317
  webhooks_config = self._config.hook_extensions.webhooks
318
318
  if not webhooks_config:
319
- from gobby.config.app import WebhooksConfig
319
+ from gobby.config.extensions import WebhooksConfig
320
320
 
321
321
  webhooks_config = WebhooksConfig()
322
322
  self._webhook_dispatcher = WebhookDispatcher(webhooks_config)
gobby/hooks/plugins.py CHANGED
@@ -23,7 +23,7 @@ from typing import TYPE_CHECKING, Any
23
23
  from gobby.hooks.events import HookEvent, HookEventType, HookResponse
24
24
 
25
25
  if TYPE_CHECKING:
26
- from gobby.config.app import PluginsConfig
26
+ from gobby.config.extensions import PluginsConfig
27
27
 
28
28
  logger = logging.getLogger(__name__)
29
29
 
gobby/hooks/webhooks.py CHANGED
@@ -20,7 +20,7 @@ from typing import TYPE_CHECKING, Any
20
20
  import httpx
21
21
 
22
22
  if TYPE_CHECKING:
23
- from gobby.config.app import WebhookEndpointConfig, WebhooksConfig
23
+ from gobby.config.extensions import WebhookEndpointConfig, WebhooksConfig
24
24
  from gobby.hooks.events import HookEvent
25
25
 
26
26
  logger = logging.getLogger(__name__)
gobby/llm/resolver.py CHANGED
@@ -18,7 +18,8 @@ from typing import TYPE_CHECKING, Literal
18
18
  from gobby.llm.executor import AgentExecutor
19
19
 
20
20
  if TYPE_CHECKING:
21
- from gobby.config.app import DaemonConfig, LLMProvidersConfig
21
+ from gobby.config.app import DaemonConfig
22
+ from gobby.config.llm_providers import LLMProvidersConfig
22
23
  from gobby.workflows.definitions import WorkflowDefinition
23
24
 
24
25
  logger = logging.getLogger(__name__)
@@ -479,7 +480,7 @@ def _create_codex_executor(
479
480
 
480
481
  # Re-export for TYPE_CHECKING
481
482
  if TYPE_CHECKING:
482
- from gobby.config.app import LLMProviderConfig
483
+ from gobby.config.llm_providers import LLMProviderConfig
483
484
 
484
485
 
485
486
  class ExecutorRegistry: