gobby 0.2.5__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 (244) hide show
  1. gobby/__init__.py +1 -1
  2. gobby/adapters/__init__.py +2 -1
  3. gobby/adapters/claude_code.py +13 -4
  4. gobby/adapters/codex_impl/__init__.py +28 -0
  5. gobby/adapters/codex_impl/adapter.py +722 -0
  6. gobby/adapters/codex_impl/client.py +679 -0
  7. gobby/adapters/codex_impl/protocol.py +20 -0
  8. gobby/adapters/codex_impl/types.py +68 -0
  9. gobby/agents/definitions.py +11 -1
  10. gobby/agents/isolation.py +395 -0
  11. gobby/agents/runner.py +8 -0
  12. gobby/agents/sandbox.py +261 -0
  13. gobby/agents/spawn.py +42 -287
  14. gobby/agents/spawn_executor.py +385 -0
  15. gobby/agents/spawners/__init__.py +24 -0
  16. gobby/agents/spawners/command_builder.py +189 -0
  17. gobby/agents/spawners/embedded.py +21 -2
  18. gobby/agents/spawners/headless.py +21 -2
  19. gobby/agents/spawners/prompt_manager.py +125 -0
  20. gobby/cli/__init__.py +6 -0
  21. gobby/cli/clones.py +419 -0
  22. gobby/cli/conductor.py +266 -0
  23. gobby/cli/install.py +4 -4
  24. gobby/cli/installers/antigravity.py +3 -9
  25. gobby/cli/installers/claude.py +15 -9
  26. gobby/cli/installers/codex.py +2 -8
  27. gobby/cli/installers/gemini.py +8 -8
  28. gobby/cli/installers/shared.py +175 -13
  29. gobby/cli/sessions.py +1 -1
  30. gobby/cli/skills.py +858 -0
  31. gobby/cli/tasks/ai.py +0 -440
  32. gobby/cli/tasks/crud.py +44 -6
  33. gobby/cli/tasks/main.py +0 -4
  34. gobby/cli/tui.py +2 -2
  35. gobby/cli/utils.py +12 -5
  36. gobby/clones/__init__.py +13 -0
  37. gobby/clones/git.py +547 -0
  38. gobby/conductor/__init__.py +16 -0
  39. gobby/conductor/alerts.py +135 -0
  40. gobby/conductor/loop.py +164 -0
  41. gobby/conductor/monitors/__init__.py +11 -0
  42. gobby/conductor/monitors/agents.py +116 -0
  43. gobby/conductor/monitors/tasks.py +155 -0
  44. gobby/conductor/pricing.py +234 -0
  45. gobby/conductor/token_tracker.py +160 -0
  46. gobby/config/__init__.py +12 -97
  47. gobby/config/app.py +69 -91
  48. gobby/config/extensions.py +2 -2
  49. gobby/config/features.py +7 -130
  50. gobby/config/search.py +110 -0
  51. gobby/config/servers.py +1 -1
  52. gobby/config/skills.py +43 -0
  53. gobby/config/tasks.py +9 -41
  54. gobby/hooks/__init__.py +0 -13
  55. gobby/hooks/event_handlers.py +188 -2
  56. gobby/hooks/hook_manager.py +50 -4
  57. gobby/hooks/plugins.py +1 -1
  58. gobby/hooks/skill_manager.py +130 -0
  59. gobby/hooks/webhooks.py +1 -1
  60. gobby/install/claude/hooks/hook_dispatcher.py +4 -4
  61. gobby/install/codex/hooks/hook_dispatcher.py +1 -1
  62. gobby/install/gemini/hooks/hook_dispatcher.py +87 -12
  63. gobby/llm/claude.py +22 -34
  64. gobby/llm/claude_executor.py +46 -256
  65. gobby/llm/codex_executor.py +59 -291
  66. gobby/llm/executor.py +21 -0
  67. gobby/llm/gemini.py +134 -110
  68. gobby/llm/litellm_executor.py +143 -6
  69. gobby/llm/resolver.py +98 -35
  70. gobby/mcp_proxy/importer.py +62 -4
  71. gobby/mcp_proxy/instructions.py +56 -0
  72. gobby/mcp_proxy/models.py +15 -0
  73. gobby/mcp_proxy/registries.py +68 -8
  74. gobby/mcp_proxy/server.py +33 -3
  75. gobby/mcp_proxy/services/recommendation.py +43 -11
  76. gobby/mcp_proxy/services/tool_proxy.py +81 -1
  77. gobby/mcp_proxy/stdio.py +2 -1
  78. gobby/mcp_proxy/tools/__init__.py +0 -2
  79. gobby/mcp_proxy/tools/agent_messaging.py +317 -0
  80. gobby/mcp_proxy/tools/agents.py +31 -731
  81. gobby/mcp_proxy/tools/clones.py +518 -0
  82. gobby/mcp_proxy/tools/memory.py +3 -26
  83. gobby/mcp_proxy/tools/metrics.py +65 -1
  84. gobby/mcp_proxy/tools/orchestration/__init__.py +3 -0
  85. gobby/mcp_proxy/tools/orchestration/cleanup.py +151 -0
  86. gobby/mcp_proxy/tools/orchestration/wait.py +467 -0
  87. gobby/mcp_proxy/tools/sessions/__init__.py +14 -0
  88. gobby/mcp_proxy/tools/sessions/_commits.py +232 -0
  89. gobby/mcp_proxy/tools/sessions/_crud.py +253 -0
  90. gobby/mcp_proxy/tools/sessions/_factory.py +63 -0
  91. gobby/mcp_proxy/tools/sessions/_handoff.py +499 -0
  92. gobby/mcp_proxy/tools/sessions/_messages.py +138 -0
  93. gobby/mcp_proxy/tools/skills/__init__.py +616 -0
  94. gobby/mcp_proxy/tools/spawn_agent.py +417 -0
  95. gobby/mcp_proxy/tools/task_orchestration.py +7 -0
  96. gobby/mcp_proxy/tools/task_readiness.py +14 -0
  97. gobby/mcp_proxy/tools/task_sync.py +1 -1
  98. gobby/mcp_proxy/tools/tasks/_context.py +0 -20
  99. gobby/mcp_proxy/tools/tasks/_crud.py +91 -4
  100. gobby/mcp_proxy/tools/tasks/_expansion.py +348 -0
  101. gobby/mcp_proxy/tools/tasks/_factory.py +6 -16
  102. gobby/mcp_proxy/tools/tasks/_lifecycle.py +110 -45
  103. gobby/mcp_proxy/tools/tasks/_lifecycle_validation.py +18 -29
  104. gobby/mcp_proxy/tools/workflows.py +1 -1
  105. gobby/mcp_proxy/tools/worktrees.py +0 -338
  106. gobby/memory/backends/__init__.py +6 -1
  107. gobby/memory/backends/mem0.py +6 -1
  108. gobby/memory/extractor.py +477 -0
  109. gobby/memory/ingestion/__init__.py +5 -0
  110. gobby/memory/ingestion/multimodal.py +221 -0
  111. gobby/memory/manager.py +73 -285
  112. gobby/memory/search/__init__.py +10 -0
  113. gobby/memory/search/coordinator.py +248 -0
  114. gobby/memory/services/__init__.py +5 -0
  115. gobby/memory/services/crossref.py +142 -0
  116. gobby/prompts/loader.py +5 -2
  117. gobby/runner.py +37 -16
  118. gobby/search/__init__.py +48 -6
  119. gobby/search/backends/__init__.py +159 -0
  120. gobby/search/backends/embedding.py +225 -0
  121. gobby/search/embeddings.py +238 -0
  122. gobby/search/models.py +148 -0
  123. gobby/search/unified.py +496 -0
  124. gobby/servers/http.py +24 -12
  125. gobby/servers/routes/admin.py +294 -0
  126. gobby/servers/routes/mcp/endpoints/__init__.py +61 -0
  127. gobby/servers/routes/mcp/endpoints/discovery.py +405 -0
  128. gobby/servers/routes/mcp/endpoints/execution.py +568 -0
  129. gobby/servers/routes/mcp/endpoints/registry.py +378 -0
  130. gobby/servers/routes/mcp/endpoints/server.py +304 -0
  131. gobby/servers/routes/mcp/hooks.py +1 -1
  132. gobby/servers/routes/mcp/tools.py +48 -1317
  133. gobby/servers/websocket.py +2 -2
  134. gobby/sessions/analyzer.py +2 -0
  135. gobby/sessions/lifecycle.py +1 -1
  136. gobby/sessions/processor.py +10 -0
  137. gobby/sessions/transcripts/base.py +2 -0
  138. gobby/sessions/transcripts/claude.py +79 -10
  139. gobby/skills/__init__.py +91 -0
  140. gobby/skills/loader.py +685 -0
  141. gobby/skills/manager.py +384 -0
  142. gobby/skills/parser.py +286 -0
  143. gobby/skills/search.py +463 -0
  144. gobby/skills/sync.py +119 -0
  145. gobby/skills/updater.py +385 -0
  146. gobby/skills/validator.py +368 -0
  147. gobby/storage/clones.py +378 -0
  148. gobby/storage/database.py +1 -1
  149. gobby/storage/memories.py +43 -13
  150. gobby/storage/migrations.py +162 -201
  151. gobby/storage/sessions.py +116 -7
  152. gobby/storage/skills.py +782 -0
  153. gobby/storage/tasks/_crud.py +4 -4
  154. gobby/storage/tasks/_lifecycle.py +57 -7
  155. gobby/storage/tasks/_manager.py +14 -5
  156. gobby/storage/tasks/_models.py +8 -3
  157. gobby/sync/memories.py +40 -5
  158. gobby/sync/tasks.py +83 -6
  159. gobby/tasks/__init__.py +1 -2
  160. gobby/tasks/external_validator.py +1 -1
  161. gobby/tasks/validation.py +46 -35
  162. gobby/tools/summarizer.py +91 -10
  163. gobby/tui/api_client.py +4 -7
  164. gobby/tui/app.py +5 -3
  165. gobby/tui/screens/orchestrator.py +1 -2
  166. gobby/tui/screens/tasks.py +2 -4
  167. gobby/tui/ws_client.py +1 -1
  168. gobby/utils/daemon_client.py +2 -2
  169. gobby/utils/project_context.py +2 -3
  170. gobby/utils/status.py +13 -0
  171. gobby/workflows/actions.py +221 -1135
  172. gobby/workflows/artifact_actions.py +31 -0
  173. gobby/workflows/autonomous_actions.py +11 -0
  174. gobby/workflows/context_actions.py +93 -1
  175. gobby/workflows/detection_helpers.py +115 -31
  176. gobby/workflows/enforcement/__init__.py +47 -0
  177. gobby/workflows/enforcement/blocking.py +269 -0
  178. gobby/workflows/enforcement/commit_policy.py +283 -0
  179. gobby/workflows/enforcement/handlers.py +269 -0
  180. gobby/workflows/{task_enforcement_actions.py → enforcement/task_policy.py} +29 -388
  181. gobby/workflows/engine.py +13 -2
  182. gobby/workflows/git_utils.py +106 -0
  183. gobby/workflows/lifecycle_evaluator.py +29 -1
  184. gobby/workflows/llm_actions.py +30 -0
  185. gobby/workflows/loader.py +19 -6
  186. gobby/workflows/mcp_actions.py +20 -1
  187. gobby/workflows/memory_actions.py +154 -0
  188. gobby/workflows/safe_evaluator.py +183 -0
  189. gobby/workflows/session_actions.py +44 -0
  190. gobby/workflows/state_actions.py +60 -1
  191. gobby/workflows/stop_signal_actions.py +55 -0
  192. gobby/workflows/summary_actions.py +111 -1
  193. gobby/workflows/task_sync_actions.py +347 -0
  194. gobby/workflows/todo_actions.py +34 -1
  195. gobby/workflows/webhook_actions.py +185 -0
  196. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/METADATA +87 -21
  197. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/RECORD +201 -172
  198. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/WHEEL +1 -1
  199. gobby/adapters/codex.py +0 -1292
  200. gobby/install/claude/commands/gobby/bug.md +0 -51
  201. gobby/install/claude/commands/gobby/chore.md +0 -51
  202. gobby/install/claude/commands/gobby/epic.md +0 -52
  203. gobby/install/claude/commands/gobby/eval.md +0 -235
  204. gobby/install/claude/commands/gobby/feat.md +0 -49
  205. gobby/install/claude/commands/gobby/nit.md +0 -52
  206. gobby/install/claude/commands/gobby/ref.md +0 -52
  207. gobby/install/codex/prompts/forget.md +0 -7
  208. gobby/install/codex/prompts/memories.md +0 -7
  209. gobby/install/codex/prompts/recall.md +0 -7
  210. gobby/install/codex/prompts/remember.md +0 -13
  211. gobby/llm/gemini_executor.py +0 -339
  212. gobby/mcp_proxy/tools/session_messages.py +0 -1056
  213. gobby/mcp_proxy/tools/task_expansion.py +0 -591
  214. gobby/prompts/defaults/expansion/system.md +0 -119
  215. gobby/prompts/defaults/expansion/user.md +0 -48
  216. gobby/prompts/defaults/external_validation/agent.md +0 -72
  217. gobby/prompts/defaults/external_validation/external.md +0 -63
  218. gobby/prompts/defaults/external_validation/spawn.md +0 -83
  219. gobby/prompts/defaults/external_validation/system.md +0 -6
  220. gobby/prompts/defaults/features/import_mcp.md +0 -22
  221. gobby/prompts/defaults/features/import_mcp_github.md +0 -17
  222. gobby/prompts/defaults/features/import_mcp_search.md +0 -16
  223. gobby/prompts/defaults/features/recommend_tools.md +0 -32
  224. gobby/prompts/defaults/features/recommend_tools_hybrid.md +0 -35
  225. gobby/prompts/defaults/features/recommend_tools_llm.md +0 -30
  226. gobby/prompts/defaults/features/server_description.md +0 -20
  227. gobby/prompts/defaults/features/server_description_system.md +0 -6
  228. gobby/prompts/defaults/features/task_description.md +0 -31
  229. gobby/prompts/defaults/features/task_description_system.md +0 -6
  230. gobby/prompts/defaults/features/tool_summary.md +0 -17
  231. gobby/prompts/defaults/features/tool_summary_system.md +0 -6
  232. gobby/prompts/defaults/research/step.md +0 -58
  233. gobby/prompts/defaults/validation/criteria.md +0 -47
  234. gobby/prompts/defaults/validation/validate.md +0 -38
  235. gobby/storage/migrations_legacy.py +0 -1359
  236. gobby/tasks/context.py +0 -747
  237. gobby/tasks/criteria.py +0 -342
  238. gobby/tasks/expansion.py +0 -626
  239. gobby/tasks/prompts/expand.py +0 -327
  240. gobby/tasks/research.py +0 -421
  241. gobby/tasks/tdd.py +0 -352
  242. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/entry_points.txt +0 -0
  243. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/licenses/LICENSE.md +0 -0
  244. {gobby-0.2.5.dist-info → gobby-0.2.7.dist-info}/top_level.txt +0 -0
gobby/tools/summarizer.py CHANGED
@@ -11,7 +11,8 @@ import logging
11
11
  from typing import TYPE_CHECKING, Any
12
12
 
13
13
  if TYPE_CHECKING:
14
- from gobby.config.app import ToolSummarizerConfig
14
+ from gobby.config.features import ToolSummarizerConfig
15
+ from gobby.prompts import PromptLoader
15
16
 
16
17
  logger = logging.getLogger(__name__)
17
18
 
@@ -20,12 +21,42 @@ MAX_DESCRIPTION_LENGTH = 200
20
21
 
21
22
  # Module-level config reference (set by init_summarizer_config)
22
23
  _config: ToolSummarizerConfig | None = None
24
+ _loader: PromptLoader | None = None
23
25
 
26
+ DEFAULT_SUMMARY_PROMPT = """Summarize this MCP tool description in 180 characters or less.
27
+ Keep it to three sentences or less. Be concise and preserve the key functionality.
28
+ Do not add quotes, extra formatting, or code examples.
24
29
 
25
- def init_summarizer_config(config: ToolSummarizerConfig) -> None:
30
+ Description: {description}
31
+
32
+ Summary:"""
33
+
34
+ DEFAULT_SUMMARY_SYSTEM_PROMPT = "You are a technical summarizer. Create concise tool descriptions."
35
+
36
+ DEFAULT_SERVER_DESC_PROMPT = """Write a single concise sentence describing what the '{server_name}' MCP server does based on its tools.
37
+
38
+ Tools:
39
+ {tools_list}
40
+
41
+ Description (1 sentence, try to keep under 100 characters):"""
42
+
43
+ DEFAULT_SERVER_DESC_SYSTEM_PROMPT = "You write concise technical descriptions."
44
+
45
+
46
+ def init_summarizer_config(config: ToolSummarizerConfig, project_dir: str | None = None) -> None:
26
47
  """Initialize the summarizer with configuration."""
27
- global _config
48
+ from pathlib import Path
49
+
50
+ global _config, _loader
28
51
  _config = config
52
+ _loader = PromptLoader(project_dir=Path(project_dir) if project_dir else None)
53
+ # Register fallbacks
54
+ _loader.register_fallback("features/tool_summary", lambda: DEFAULT_SUMMARY_PROMPT)
55
+ _loader.register_fallback("features/tool_summary_system", lambda: DEFAULT_SUMMARY_SYSTEM_PROMPT)
56
+ _loader.register_fallback("features/server_description", lambda: DEFAULT_SERVER_DESC_PROMPT)
57
+ _loader.register_fallback(
58
+ "features/server_description_system", lambda: DEFAULT_SERVER_DESC_SYSTEM_PROMPT
59
+ )
29
60
 
30
61
 
31
62
  def _get_config() -> ToolSummarizerConfig:
@@ -33,7 +64,12 @@ def _get_config() -> ToolSummarizerConfig:
33
64
  if _config is not None:
34
65
  return _config
35
66
  # Import here to avoid circular imports
36
- from gobby.config.app import ToolSummarizerConfig
67
+ from gobby.config.features import ToolSummarizerConfig
68
+
69
+ # Ensure loader defaults exist even if init wasn't called
70
+ global _loader
71
+ if _loader is None:
72
+ _loader = PromptLoader()
37
73
 
38
74
  return ToolSummarizerConfig()
39
75
 
@@ -53,11 +89,30 @@ async def _summarize_description_with_claude(description: str) -> str:
53
89
  try:
54
90
  from claude_agent_sdk import AssistantMessage, ClaudeAgentOptions, TextBlock, query
55
91
 
56
- prompt = config.prompt.format(description=description)
92
+ # Get summary prompt
93
+ prompt_path = config.prompt_path or "features/tool_summary"
94
+ try:
95
+ # We assume _loader is initialized by _get_config() logic or init
96
+ if _loader is None:
97
+ raise RuntimeError("Summarizer not initialized")
98
+ prompt = _loader.render(prompt_path, {"description": description})
99
+ except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
100
+ logger.debug(f"Failed to load prompt from {prompt_path}: {e}, using default")
101
+ prompt = DEFAULT_SUMMARY_PROMPT.format(description=description)
102
+
103
+ # Get system prompt
104
+ sys_prompt_path = config.system_prompt_path or "features/tool_summary_system"
105
+ try:
106
+ if _loader is None:
107
+ raise RuntimeError("Summarizer not initialized")
108
+ system_prompt = _loader.render(sys_prompt_path, {})
109
+ except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
110
+ logger.debug(f"Failed to load system prompt from {sys_prompt_path}: {e}, using default")
111
+ system_prompt = DEFAULT_SUMMARY_SYSTEM_PROMPT
57
112
 
58
113
  # Configure for single-turn completion
59
114
  options = ClaudeAgentOptions(
60
- system_prompt=config.system_prompt,
115
+ system_prompt=system_prompt,
61
116
  max_turns=1,
62
117
  model=config.model,
63
118
  allowed_tools=[],
@@ -137,14 +192,40 @@ async def generate_server_description(
137
192
  # Build tools list for prompt
138
193
  tools_list = "\n".join([f"- {t['name']}: {t['description']}" for t in tool_summaries])
139
194
 
140
- prompt = config.server_description_prompt.format(
141
- server_name=server_name,
142
- tools_list=tools_list,
195
+ # Build prompt
196
+ prompt_path = config.server_description_prompt_path or "features/server_description"
197
+ context = {
198
+ "server_name": server_name,
199
+ "tools_list": tools_list,
200
+ }
201
+ try:
202
+ if _loader is None:
203
+ _get_config() # force init
204
+ if _loader is None:
205
+ # Still None after _get_config, use default
206
+ prompt = DEFAULT_SERVER_DESC_PROMPT.format(**context)
207
+ else:
208
+ prompt = _loader.render(prompt_path, context)
209
+ except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
210
+ logger.debug(f"Failed to load prompt from {prompt_path}: {e}, using default")
211
+ prompt = DEFAULT_SERVER_DESC_PROMPT.format(**context)
212
+
213
+ # Get system prompt
214
+ sys_prompt_path = (
215
+ config.server_description_system_prompt_path or "features/server_description_system"
143
216
  )
217
+ try:
218
+ if _loader is None:
219
+ system_prompt = DEFAULT_SERVER_DESC_SYSTEM_PROMPT
220
+ else:
221
+ system_prompt = _loader.render(sys_prompt_path, {})
222
+ except (FileNotFoundError, OSError, KeyError, ValueError, RuntimeError) as e:
223
+ logger.debug(f"Failed to load system prompt from {sys_prompt_path}: {e}, using default")
224
+ system_prompt = DEFAULT_SERVER_DESC_SYSTEM_PROMPT
144
225
 
145
226
  # Configure for single-turn completion
146
227
  options = ClaudeAgentOptions(
147
- system_prompt=config.server_description_system_prompt,
228
+ system_prompt=system_prompt,
148
229
  max_turns=1,
149
230
  model=config.model,
150
231
  allowed_tools=[],
gobby/tui/api_client.py CHANGED
@@ -10,7 +10,7 @@ import httpx
10
10
  class GobbyAPIClient:
11
11
  """HTTP client for communicating with Gobby daemon."""
12
12
 
13
- def __init__(self, base_url: str = "http://localhost:8765") -> None:
13
+ def __init__(self, base_url: str = "http://localhost:60887") -> None:
14
14
  self.base_url = base_url.rstrip("/")
15
15
  self._client: httpx.AsyncClient | None = None
16
16
 
@@ -177,17 +177,14 @@ class GobbyAPIClient:
177
177
  self,
178
178
  task_id: str,
179
179
  commit_sha: str | None = None,
180
- no_commit_needed: bool = False,
181
- override_justification: str | None = None,
180
+ reason: str | None = None,
182
181
  ) -> dict[str, Any]:
183
182
  """Close a task."""
184
183
  args: dict[str, Any] = {"task_id": task_id}
185
184
  if commit_sha:
186
185
  args["commit_sha"] = commit_sha
187
- if no_commit_needed:
188
- args["no_commit_needed"] = True
189
- if override_justification:
190
- args["override_justification"] = override_justification
186
+ if reason:
187
+ args["reason"] = reason
191
188
  return await self.call_tool("gobby-tasks", "close_task", args)
192
189
 
193
190
  async def suggest_next_task(self) -> dict[str, Any]:
gobby/tui/app.py CHANGED
@@ -158,8 +158,8 @@ class GobbyApp(App[None]):
158
158
 
159
159
  def __init__(
160
160
  self,
161
- daemon_url: str = "http://localhost:8765",
162
- ws_url: str = "ws://localhost:8766",
161
+ daemon_url: str = "http://localhost:60887",
162
+ ws_url: str = "ws://localhost:60888",
163
163
  ) -> None:
164
164
  super().__init__()
165
165
  self.daemon_url = daemon_url
@@ -321,7 +321,9 @@ class GobbyApp(App[None]):
321
321
  await self.ws_client.disconnect()
322
322
 
323
323
 
324
- def run_tui(daemon_url: str = "http://localhost:8765", ws_url: str = "ws://localhost:8766") -> None:
324
+ def run_tui(
325
+ daemon_url: str = "http://localhost:60887", ws_url: str = "ws://localhost:60888"
326
+ ) -> None:
325
327
  """Entry point for the TUI application."""
326
328
  app = GobbyApp(daemon_url=daemon_url, ws_url=ws_url)
327
329
  app.run()
@@ -826,8 +826,7 @@ class OrchestratorScreen(Widget):
826
826
  return
827
827
  await self.api_client.close_task(
828
828
  task_id,
829
- no_commit_needed=True,
830
- override_justification="Orchestrator approval - manual user review",
829
+ reason="completed",
831
830
  )
832
831
  self.notify(f"Approved: {task.get('ref', task_id)}")
833
832
 
@@ -403,16 +403,14 @@ class TasksScreen(Widget):
403
403
  # Note: In real usage, this would need a commit SHA
404
404
  await client.close_task(
405
405
  task_id,
406
- no_commit_needed=True,
407
- override_justification="TUI completion - manual user action",
406
+ reason="obsolete",
408
407
  )
409
408
  self.notify(f"Task completed: {task_id}")
410
409
 
411
410
  elif button_id == "btn-approve":
412
411
  await client.close_task(
413
412
  task_id,
414
- no_commit_needed=True,
415
- override_justification="TUI approval - manual user review",
413
+ reason="obsolete",
416
414
  )
417
415
  self.notify(f"Task approved: {task_id}")
418
416
 
gobby/tui/ws_client.py CHANGED
@@ -19,7 +19,7 @@ class GobbyWebSocketClient:
19
19
 
20
20
  def __init__(
21
21
  self,
22
- ws_url: str = "ws://localhost:8766",
22
+ ws_url: str = "ws://localhost:60888",
23
23
  reconnect_interval: float = 5.0,
24
24
  max_reconnect_attempts: int = 10,
25
25
  ) -> None:
@@ -11,7 +11,7 @@ Example:
11
11
  ```python
12
12
  from gobby.utils.daemon_client import DaemonClient
13
13
 
14
- client = DaemonClient(host="localhost", port=8765)
14
+ client = DaemonClient(host="localhost", port=60887)
15
15
 
16
16
  # Check daemon health
17
17
  is_healthy, error = client.check_health()
@@ -57,7 +57,7 @@ class DaemonClient:
57
57
  def __init__(
58
58
  self,
59
59
  host: str = "localhost",
60
- port: int = 8765,
60
+ port: int = 60887,
61
61
  timeout: float = 5.0,
62
62
  logger: logging.Logger | None = None,
63
63
  ):
@@ -10,8 +10,7 @@ from pathlib import Path
10
10
  from typing import TYPE_CHECKING, Any, cast
11
11
 
12
12
  if TYPE_CHECKING:
13
- from gobby.config.app import ProjectVerificationConfig
14
- from gobby.config.features import HooksConfig
13
+ from gobby.config.features import HooksConfig, ProjectVerificationConfig
15
14
 
16
15
  logger = logging.getLogger(__name__)
17
16
 
@@ -138,7 +137,7 @@ def get_verification_config(cwd: Path | None = None) -> ProjectVerificationConfi
138
137
  Returns:
139
138
  ProjectVerificationConfig if verification section exists, None otherwise.
140
139
  """
141
- from gobby.config.app import ProjectVerificationConfig
140
+ from gobby.config.features import ProjectVerificationConfig
142
141
 
143
142
  context = get_project_context(cwd)
144
143
  if not context:
gobby/utils/status.py CHANGED
@@ -79,6 +79,11 @@ def fetch_rich_status(http_port: int, timeout: float = 2.0) -> dict[str, Any]:
79
79
  status_kwargs["memories_count"] = memory.get("count", 0)
80
80
  status_kwargs["memories_avg_importance"] = memory.get("avg_importance", 0.0)
81
81
 
82
+ # Skills
83
+ skills_data = data.get("skills", {})
84
+ if skills_data:
85
+ status_kwargs["skills_total"] = skills_data.get("total", 0)
86
+
82
87
  except (httpx.ConnectError, httpx.TimeoutException):
83
88
  # Daemon not responding - return empty
84
89
  pass
@@ -117,6 +122,8 @@ def format_status_message(
117
122
  # Memory
118
123
  memories_count: int | None = None,
119
124
  memories_avg_importance: float | None = None,
125
+ # Skills
126
+ skills_total: int | None = None,
120
127
  **kwargs: Any,
121
128
  ) -> str:
122
129
  """
@@ -202,6 +209,12 @@ def format_status_message(
202
209
  lines.append(f" Unhealthy: {unhealthy_str}")
203
210
  lines.append("")
204
211
 
212
+ # Skills section (only show if we have data)
213
+ if skills_total is not None:
214
+ lines.append("Skills:")
215
+ lines.append(f" Loaded: {skills_total}")
216
+ lines.append("")
217
+
205
218
  # Sessions section (only show if we have data)
206
219
  if sessions_active is not None or sessions_paused is not None:
207
220
  lines.append("Sessions:")