vibecore 0.4.2__tar.gz → 0.6.0__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.

Potentially problematic release.


This version of vibecore might be problematic. Click here for more details.

Files changed (90) hide show
  1. {vibecore-0.4.2 → vibecore-0.6.0}/PKG-INFO +91 -31
  2. {vibecore-0.4.2 → vibecore-0.6.0}/README.md +90 -30
  3. {vibecore-0.4.2 → vibecore-0.6.0}/pyproject.toml +2 -2
  4. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/agents/default.py +3 -3
  5. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/agents/task.py +3 -3
  6. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/cli.py +68 -43
  7. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/context.py +41 -15
  8. vibecore-0.6.0/src/vibecore/flow.py +367 -0
  9. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/handlers/stream_handler.py +0 -10
  10. vibecore-0.6.0/src/vibecore/main.py +300 -0
  11. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/session/jsonl_session.py +3 -1
  12. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/session/loader.py +2 -2
  13. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/file/executor.py +13 -5
  14. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/file/tools.py +5 -5
  15. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/python/helpers.py +2 -2
  16. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/python/tools.py +2 -2
  17. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/shell/executor.py +5 -5
  18. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/shell/tools.py +5 -5
  19. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/task/executor.py +2 -2
  20. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/task/tools.py +2 -2
  21. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/todo/tools.py +3 -3
  22. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/webfetch/tools.py +1 -4
  23. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/websearch/tools.py +1 -4
  24. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/core.py +2 -9
  25. vibecore-0.4.2/src/vibecore/flow.py +0 -105
  26. vibecore-0.4.2/src/vibecore/main.py +0 -526
  27. {vibecore-0.4.2 → vibecore-0.6.0}/.gitignore +0 -0
  28. {vibecore-0.4.2 → vibecore-0.6.0}/LICENSE +0 -0
  29. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/__init__.py +0 -0
  30. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/agents/prompts.py +0 -0
  31. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/__init__.py +0 -0
  32. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/config.py +0 -0
  33. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/interceptor.py +0 -0
  34. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/manager.py +0 -0
  35. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/models.py +0 -0
  36. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/oauth_flow.py +0 -0
  37. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/pkce.py +0 -0
  38. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/storage.py +0 -0
  39. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/auth/token_manager.py +0 -0
  40. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/handlers/__init__.py +0 -0
  41. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/main.tcss +0 -0
  42. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/mcp/__init__.py +0 -0
  43. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/mcp/manager.py +0 -0
  44. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/mcp/server_wrapper.py +0 -0
  45. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/models/__init__.py +0 -0
  46. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/models/anthropic.py +0 -0
  47. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/models/anthropic_auth.py +0 -0
  48. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/prompts/common_system_prompt.txt +0 -0
  49. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/py.typed +0 -0
  50. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/session/__init__.py +0 -0
  51. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/session/file_lock.py +0 -0
  52. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/session/path_utils.py +0 -0
  53. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/settings.py +0 -0
  54. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/__init__.py +0 -0
  55. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/base.py +0 -0
  56. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/file/__init__.py +0 -0
  57. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/file/utils.py +0 -0
  58. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/path_validator.py +0 -0
  59. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/python/__init__.py +0 -0
  60. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/python/backends/__init__.py +0 -0
  61. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/python/backends/terminal_backend.py +0 -0
  62. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/python/manager.py +0 -0
  63. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/shell/__init__.py +0 -0
  64. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/task/__init__.py +0 -0
  65. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/todo/__init__.py +0 -0
  66. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/todo/manager.py +0 -0
  67. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/todo/models.py +0 -0
  68. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/webfetch/__init__.py +0 -0
  69. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/webfetch/executor.py +0 -0
  70. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/webfetch/models.py +0 -0
  71. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/websearch/__init__.py +0 -0
  72. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/websearch/base.py +0 -0
  73. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/websearch/ddgs/__init__.py +0 -0
  74. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/websearch/ddgs/backend.py +0 -0
  75. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/websearch/executor.py +0 -0
  76. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/tools/websearch/models.py +0 -0
  77. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/utils/__init__.py +0 -0
  78. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/utils/text.py +0 -0
  79. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/core.tcss +0 -0
  80. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/expandable.py +0 -0
  81. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/expandable.tcss +0 -0
  82. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/feedback.py +0 -0
  83. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/feedback.tcss +0 -0
  84. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/info.py +0 -0
  85. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/info.tcss +0 -0
  86. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/messages.py +0 -0
  87. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/messages.tcss +0 -0
  88. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/tool_message_factory.py +0 -0
  89. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/tool_messages.py +0 -0
  90. {vibecore-0.4.2 → vibecore-0.6.0}/src/vibecore/widgets/tool_messages.tcss +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: vibecore
3
- Version: 0.4.2
3
+ Version: 0.6.0
4
4
  Summary: Build your own AI-powered automation tools in the terminal with this extensible agent framework
5
5
  Project-URL: Homepage, https://github.com/serialx/vibecore
6
6
  Project-URL: Repository, https://github.com/serialx/vibecore
@@ -158,7 +158,6 @@ Once vibecore is running, you can:
158
158
  ### Commands
159
159
 
160
160
  - `/help` - Show help and keyboard shortcuts
161
- - `/clear` - Clear the current session and start a new one
162
161
 
163
162
  ## Flow Mode (Experimental)
164
163
 
@@ -177,37 +176,56 @@ Flow Mode allows you to:
177
176
 
178
177
  ```python
179
178
  import asyncio
180
- from agents import Agent, Runner
181
- from vibecore.flow import flow, UserInputFunc
179
+ from agents import Agent
180
+ from vibecore.flow import Vibecore, VibecoreRunnerBase
182
181
  from vibecore.context import VibecoreContext
182
+ from vibecore.settings import settings
183
183
 
184
184
  # Define your agent with tools
185
185
  agent = Agent[VibecoreContext](
186
186
  name="Assistant",
187
187
  instructions="You are a helpful assistant",
188
188
  tools=[...], # Your tools here
189
+ model=settings.model,
189
190
  )
190
191
 
191
- # Define your conversation logic
192
- async def logic(app, ctx: VibecoreContext, user_input: UserInputFunc):
192
+ # Create Vibecore instance
193
+ vibecore = Vibecore[VibecoreContext, str]()
194
+
195
+ # Define your conversation logic with decorator
196
+ @vibecore.workflow()
197
+ async def logic(
198
+ runner: VibecoreRunnerBase[VibecoreContext, str],
199
+ ) -> str:
193
200
  # Get user input programmatically
194
- user_message = await user_input("What would you like to do?")
195
-
196
- # Process with agent
197
- result = Runner.run_streamed(
201
+ user_message = await runner.user_input("What would you like to do?")
202
+
203
+ # Print status updates
204
+ await runner.print(f"Processing: {user_message}")
205
+
206
+ # Process with agent (handles streaming automatically)
207
+ result = await runner.run_agent(
198
208
  agent,
199
209
  input=user_message,
200
- context=ctx,
201
- session=app.session,
210
+ context=runner.context,
211
+ session=runner.session,
202
212
  )
203
-
204
- # Handle the response
205
- app.current_worker = app.handle_streamed_response(result)
206
- await app.current_worker.wait()
207
213
 
208
- # Run the flow
214
+ await runner.print("Done!")
215
+ return result.final_output
216
+
217
+ # Run the flow in different modes
209
218
  async def main():
210
- await flow(agent, logic)
219
+ # Option 1: TUI mode (full terminal interface)
220
+ result = await vibecore.run_textual(shutdown=False)
221
+
222
+ # Option 2: CLI mode (simple stdin/stdout)
223
+ # result = await vibecore.run_cli()
224
+
225
+ # Option 3: Static mode (programmatic, for testing)
226
+ # result = await vibecore.run("Calculate 2+2")
227
+
228
+ print(f"Final output: {result}")
211
229
 
212
230
  if __name__ == "__main__":
213
231
  asyncio.run(main())
@@ -225,11 +243,53 @@ Flow Mode shines when building complex multi-agent systems. See `examples/custom
225
243
 
226
244
  ### Key Components
227
245
 
228
- - **`flow()`**: Entry point that sets up the Vibecore app with your custom logic
229
- - **`logic()`**: Your async function that controls the conversation flow
230
- - **`UserInputFunc`**: Provides programmatic user input collection
231
- - **`VibecoreContext`**: Shared state across tools and agents
232
- - **Agent Handoffs**: Transfer control between specialized agents
246
+ - **`Vibecore` class**: Main entry point that orchestrates your workflow
247
+ - **`@vibecore.workflow()` decorator**: Defines your conversation logic function
248
+ - **Runner argument**: Every workflow receives a runner instance for user input, printing, and agent execution
249
+ - **`runner.user_input()`**: Programmatically collect user input
250
+ - **`runner.print()`**: Display status messages to the user
251
+ - **`runner.run_agent()`**: Execute agent with automatic streaming handling
252
+ - **`runner.context`**: Shared state (VibecoreContext) across tools and agents
253
+ - **`runner.session`**: Conversation history and persistence
254
+ - **Multiple execution modes**:
255
+ - `run_textual()`: Full TUI with streaming (original behavior)
256
+ - `run_cli()`: Simple CLI with stdin/stdout
257
+ - `run()`: Static mode with predefined inputs (perfect for testing)
258
+ - **Agent Handoffs**: Transfer control between specialized agents with context preservation
259
+
260
+ > 🛠️ Upgrading from an older release? Read the [Runner Migration Guide](docs/runner_migration.md) for step-by-step instructions.
261
+
262
+ ### Multi-Mode Execution
263
+
264
+ One of vibecore's key strengths is the ability to run the **same workflow code** in different execution modes without modification:
265
+
266
+ #### TUI Mode (Textual User Interface)
267
+ Full-featured terminal interface with streaming responses, tool visualization, and interactive controls:
268
+ ```python
269
+ result = await vibecore.run_textual(shutdown=False)
270
+ ```
271
+
272
+ #### CLI Mode (Command-Line Interface)
273
+ Simple stdin/stdout interaction for scripting and automation:
274
+ ```python
275
+ result = await vibecore.run_cli()
276
+ ```
277
+
278
+ #### Static Mode (Programmatic)
279
+ Execute with predefined inputs, perfect for testing and batch processing:
280
+ ```python
281
+ # Single input
282
+ result = await vibecore.run("Calculate 2+2")
283
+
284
+ # Multiple inputs (for multi-turn workflows)
285
+ result = await vibecore.run(["First query", "Follow-up", "Final question"])
286
+ ```
287
+
288
+ This unified interface means you can:
289
+ - **Develop once, deploy anywhere**: Write your workflow logic once and run it in any mode
290
+ - **Test easily**: Use static mode for automated testing with predefined inputs
291
+ - **Choose the right interface**: TUI for development, CLI for scripts, static for tests
292
+ - **Extend to new modes**: Add custom runners (HTTP API, Discord bot, etc.) by implementing the runner interface
233
293
 
234
294
  ### Use Cases
235
295
 
@@ -446,11 +506,6 @@ When enabled, the path confinement system:
446
506
  - Resolves symlinks to prevent escapes
447
507
  - Blocks access to files outside allowed directories
448
508
 
449
- ### Reasoning Effort
450
-
451
- - Set default via env var: `VIBECORE_REASONING_EFFORT` (minimal | low | medium | high)
452
- - Keyword triggers: `think` → low, `think hard` → medium, `ultrathink` → high
453
-
454
509
  ### Environment Variables
455
510
 
456
511
  ```bash
@@ -507,10 +562,15 @@ vibecore is built with a modular, extensible architecture:
507
562
 
508
563
  ## Recent Updates
509
564
 
510
- - **Path Confinement**: New security feature to restrict file and shell operations to specified directories
511
- - **Reasoning View**: New ReasoningMessage widget with live reasoning summaries during streaming
565
+ - **Flow Mode Refactor (v0.5.0)**: Complete redesign with multi-mode execution support
566
+ - New `Vibecore` class with decorator-based workflow definition
567
+ - Unified interface: `user_input()`, `print()`, `run_agent()`
568
+ - Three execution modes: TUI, CLI, and static (perfect for testing)
569
+ - Cleaner API with less boilerplate and better type safety
570
+ - **Path Confinement**: Security feature to restrict file and shell operations to specified directories
571
+ - **Reasoning View**: ReasoningMessage widget with live reasoning summaries during streaming
512
572
  - **Context Usage Bar & CWD**: Footer shows token usage progress and current working directory
513
- - **Keyboard & Commands**: Ctrl+Shift+D toggles theme, Esc cancels, Ctrl+D double-press to exit, `/help` and `/clear` commands
573
+ - **Keyboard & Commands**: Ctrl+Shift+D toggles theme, Esc cancels, Ctrl+D double-press to exit, `/help` command
514
574
  - **MCP Tool Output**: Improved rendering with Markdown and JSON prettification
515
575
  - **MCP Support**: Full integration with Model Context Protocol for external tool connections
516
576
  - **Print Mode**: `-p` flag to print response and exit for pipes/automation
@@ -119,7 +119,6 @@ Once vibecore is running, you can:
119
119
  ### Commands
120
120
 
121
121
  - `/help` - Show help and keyboard shortcuts
122
- - `/clear` - Clear the current session and start a new one
123
122
 
124
123
  ## Flow Mode (Experimental)
125
124
 
@@ -138,37 +137,56 @@ Flow Mode allows you to:
138
137
 
139
138
  ```python
140
139
  import asyncio
141
- from agents import Agent, Runner
142
- from vibecore.flow import flow, UserInputFunc
140
+ from agents import Agent
141
+ from vibecore.flow import Vibecore, VibecoreRunnerBase
143
142
  from vibecore.context import VibecoreContext
143
+ from vibecore.settings import settings
144
144
 
145
145
  # Define your agent with tools
146
146
  agent = Agent[VibecoreContext](
147
147
  name="Assistant",
148
148
  instructions="You are a helpful assistant",
149
149
  tools=[...], # Your tools here
150
+ model=settings.model,
150
151
  )
151
152
 
152
- # Define your conversation logic
153
- async def logic(app, ctx: VibecoreContext, user_input: UserInputFunc):
153
+ # Create Vibecore instance
154
+ vibecore = Vibecore[VibecoreContext, str]()
155
+
156
+ # Define your conversation logic with decorator
157
+ @vibecore.workflow()
158
+ async def logic(
159
+ runner: VibecoreRunnerBase[VibecoreContext, str],
160
+ ) -> str:
154
161
  # Get user input programmatically
155
- user_message = await user_input("What would you like to do?")
156
-
157
- # Process with agent
158
- result = Runner.run_streamed(
162
+ user_message = await runner.user_input("What would you like to do?")
163
+
164
+ # Print status updates
165
+ await runner.print(f"Processing: {user_message}")
166
+
167
+ # Process with agent (handles streaming automatically)
168
+ result = await runner.run_agent(
159
169
  agent,
160
170
  input=user_message,
161
- context=ctx,
162
- session=app.session,
171
+ context=runner.context,
172
+ session=runner.session,
163
173
  )
164
-
165
- # Handle the response
166
- app.current_worker = app.handle_streamed_response(result)
167
- await app.current_worker.wait()
168
174
 
169
- # Run the flow
175
+ await runner.print("Done!")
176
+ return result.final_output
177
+
178
+ # Run the flow in different modes
170
179
  async def main():
171
- await flow(agent, logic)
180
+ # Option 1: TUI mode (full terminal interface)
181
+ result = await vibecore.run_textual(shutdown=False)
182
+
183
+ # Option 2: CLI mode (simple stdin/stdout)
184
+ # result = await vibecore.run_cli()
185
+
186
+ # Option 3: Static mode (programmatic, for testing)
187
+ # result = await vibecore.run("Calculate 2+2")
188
+
189
+ print(f"Final output: {result}")
172
190
 
173
191
  if __name__ == "__main__":
174
192
  asyncio.run(main())
@@ -186,11 +204,53 @@ Flow Mode shines when building complex multi-agent systems. See `examples/custom
186
204
 
187
205
  ### Key Components
188
206
 
189
- - **`flow()`**: Entry point that sets up the Vibecore app with your custom logic
190
- - **`logic()`**: Your async function that controls the conversation flow
191
- - **`UserInputFunc`**: Provides programmatic user input collection
192
- - **`VibecoreContext`**: Shared state across tools and agents
193
- - **Agent Handoffs**: Transfer control between specialized agents
207
+ - **`Vibecore` class**: Main entry point that orchestrates your workflow
208
+ - **`@vibecore.workflow()` decorator**: Defines your conversation logic function
209
+ - **Runner argument**: Every workflow receives a runner instance for user input, printing, and agent execution
210
+ - **`runner.user_input()`**: Programmatically collect user input
211
+ - **`runner.print()`**: Display status messages to the user
212
+ - **`runner.run_agent()`**: Execute agent with automatic streaming handling
213
+ - **`runner.context`**: Shared state (VibecoreContext) across tools and agents
214
+ - **`runner.session`**: Conversation history and persistence
215
+ - **Multiple execution modes**:
216
+ - `run_textual()`: Full TUI with streaming (original behavior)
217
+ - `run_cli()`: Simple CLI with stdin/stdout
218
+ - `run()`: Static mode with predefined inputs (perfect for testing)
219
+ - **Agent Handoffs**: Transfer control between specialized agents with context preservation
220
+
221
+ > 🛠️ Upgrading from an older release? Read the [Runner Migration Guide](docs/runner_migration.md) for step-by-step instructions.
222
+
223
+ ### Multi-Mode Execution
224
+
225
+ One of vibecore's key strengths is the ability to run the **same workflow code** in different execution modes without modification:
226
+
227
+ #### TUI Mode (Textual User Interface)
228
+ Full-featured terminal interface with streaming responses, tool visualization, and interactive controls:
229
+ ```python
230
+ result = await vibecore.run_textual(shutdown=False)
231
+ ```
232
+
233
+ #### CLI Mode (Command-Line Interface)
234
+ Simple stdin/stdout interaction for scripting and automation:
235
+ ```python
236
+ result = await vibecore.run_cli()
237
+ ```
238
+
239
+ #### Static Mode (Programmatic)
240
+ Execute with predefined inputs, perfect for testing and batch processing:
241
+ ```python
242
+ # Single input
243
+ result = await vibecore.run("Calculate 2+2")
244
+
245
+ # Multiple inputs (for multi-turn workflows)
246
+ result = await vibecore.run(["First query", "Follow-up", "Final question"])
247
+ ```
248
+
249
+ This unified interface means you can:
250
+ - **Develop once, deploy anywhere**: Write your workflow logic once and run it in any mode
251
+ - **Test easily**: Use static mode for automated testing with predefined inputs
252
+ - **Choose the right interface**: TUI for development, CLI for scripts, static for tests
253
+ - **Extend to new modes**: Add custom runners (HTTP API, Discord bot, etc.) by implementing the runner interface
194
254
 
195
255
  ### Use Cases
196
256
 
@@ -407,11 +467,6 @@ When enabled, the path confinement system:
407
467
  - Resolves symlinks to prevent escapes
408
468
  - Blocks access to files outside allowed directories
409
469
 
410
- ### Reasoning Effort
411
-
412
- - Set default via env var: `VIBECORE_REASONING_EFFORT` (minimal | low | medium | high)
413
- - Keyword triggers: `think` → low, `think hard` → medium, `ultrathink` → high
414
-
415
470
  ### Environment Variables
416
471
 
417
472
  ```bash
@@ -468,10 +523,15 @@ vibecore is built with a modular, extensible architecture:
468
523
 
469
524
  ## Recent Updates
470
525
 
471
- - **Path Confinement**: New security feature to restrict file and shell operations to specified directories
472
- - **Reasoning View**: New ReasoningMessage widget with live reasoning summaries during streaming
526
+ - **Flow Mode Refactor (v0.5.0)**: Complete redesign with multi-mode execution support
527
+ - New `Vibecore` class with decorator-based workflow definition
528
+ - Unified interface: `user_input()`, `print()`, `run_agent()`
529
+ - Three execution modes: TUI, CLI, and static (perfect for testing)
530
+ - Cleaner API with less boilerplate and better type safety
531
+ - **Path Confinement**: Security feature to restrict file and shell operations to specified directories
532
+ - **Reasoning View**: ReasoningMessage widget with live reasoning summaries during streaming
473
533
  - **Context Usage Bar & CWD**: Footer shows token usage progress and current working directory
474
- - **Keyboard & Commands**: Ctrl+Shift+D toggles theme, Esc cancels, Ctrl+D double-press to exit, `/help` and `/clear` commands
534
+ - **Keyboard & Commands**: Ctrl+Shift+D toggles theme, Esc cancels, Ctrl+D double-press to exit, `/help` command
475
535
  - **MCP Tool Output**: Improved rendering with Markdown and JSON prettification
476
536
  - **MCP Support**: Full integration with Model Context Protocol for external tool connections
477
537
  - **Print Mode**: `-p` flag to print response and exit for pipes/automation
@@ -1,6 +1,6 @@
1
1
  [project]
2
2
  name = "vibecore"
3
- version = "0.4.2"
3
+ version = "0.6.0"
4
4
  description = "Build your own AI-powered automation tools in the terminal with this extensible agent framework"
5
5
  readme = "README.md"
6
6
  authors = [
@@ -120,7 +120,7 @@ indent-style = "space"
120
120
 
121
121
  [tool.pyright]
122
122
  include = ["**/*.py"]
123
- exclude = ["**/__pycache__", ".venv", "venv", "build", "dist"]
123
+ exclude = ["**/__pycache__", ".venv", "venv", "build", "dist", ".git"]
124
124
  pythonVersion = "3.11"
125
125
  venvPath = "."
126
126
  venv = ".venv"
@@ -3,7 +3,7 @@ from typing import TYPE_CHECKING
3
3
  from agents import Agent
4
4
  from agents.extensions.handoff_prompt import prompt_with_handoff_instructions
5
5
 
6
- from vibecore.context import VibecoreContext
6
+ from vibecore.context import FullVibecoreContext
7
7
  from vibecore.settings import settings
8
8
  from vibecore.tools.file.tools import edit, multi_edit, read, write
9
9
  from vibecore.tools.python.tools import execute_python
@@ -29,7 +29,7 @@ INSTRUCTIONS = (
29
29
  )
30
30
 
31
31
 
32
- def create_default_agent(mcp_servers: list["MCPServer"] | None = None) -> Agent[VibecoreContext]:
32
+ def create_default_agent(mcp_servers: list["MCPServer"] | None = None) -> Agent[FullVibecoreContext]:
33
33
  """Create the general-purpose agent with appropriate tools.
34
34
 
35
35
  Args:
@@ -58,7 +58,7 @@ def create_default_agent(mcp_servers: list["MCPServer"] | None = None) -> Agent[
58
58
 
59
59
  instructions = prompt_with_handoff_instructions(instructions)
60
60
 
61
- return Agent[VibecoreContext](
61
+ return Agent[FullVibecoreContext](
62
62
  name="Vibecore Agent",
63
63
  handoff_description="A versatile general-purpose assistant",
64
64
  instructions=instructions,
@@ -3,7 +3,7 @@
3
3
  from agents import Agent
4
4
  from agents.extensions.handoff_prompt import prompt_with_handoff_instructions
5
5
 
6
- from vibecore.context import VibecoreContext
6
+ from vibecore.context import FullVibecoreContext
7
7
  from vibecore.settings import settings
8
8
  from vibecore.tools.file.tools import edit, multi_edit, read, write
9
9
  from vibecore.tools.python.tools import execute_python
@@ -13,7 +13,7 @@ from vibecore.tools.todo.tools import todo_read, todo_write
13
13
  from .prompts import COMMON_PROMPT
14
14
 
15
15
 
16
- def create_task_agent(prompt: str) -> Agent[VibecoreContext]:
16
+ def create_task_agent(prompt: str) -> Agent[FullVibecoreContext]:
17
17
  """Create a task agent with all tools except the Task tool.
18
18
 
19
19
  This agent is used by the Task tool to execute specific tasks.
@@ -51,7 +51,7 @@ def create_task_agent(prompt: str) -> Agent[VibecoreContext]:
51
51
 
52
52
  instructions = prompt_with_handoff_instructions(instructions)
53
53
 
54
- return Agent[VibecoreContext](
54
+ return Agent[FullVibecoreContext](
55
55
  name="Task Agent",
56
56
  handoff_description="A task-specific agent",
57
57
  instructions=instructions,
@@ -1,17 +1,21 @@
1
1
  """Vibecore CLI interface using typer."""
2
2
 
3
3
  import asyncio
4
+ import contextlib
5
+ import datetime
4
6
  import logging
7
+ import sys
5
8
  from importlib.metadata import version
6
9
  from pathlib import Path
7
10
 
8
11
  import typer
12
+ from agents.result import RunResultBase
9
13
  from textual.logging import TextualHandler
10
14
 
11
15
  from vibecore.agents.default import create_default_agent
12
- from vibecore.context import VibecoreContext
13
- from vibecore.main import VibecoreApp
16
+ from vibecore.flow import AppIsExiting, Vibecore, VibecoreRunner
14
17
  from vibecore.mcp import MCPManager
18
+ from vibecore.session import JSONLSession
15
19
  from vibecore.settings import settings
16
20
 
17
21
  app = typer.Typer()
@@ -110,49 +114,70 @@ def main(
110
114
  logger = logging.getLogger("openai.agents")
111
115
  logger.addHandler(TextualHandler())
112
116
 
113
- # Create context
114
- vibecore_ctx = VibecoreContext()
115
-
116
- # Initialize MCP manager if configured
117
- mcp_servers = []
118
- if settings.mcp_servers:
119
- # Create MCP manager
120
- mcp_manager = MCPManager(settings.mcp_servers)
121
- vibecore_ctx.mcp_manager = mcp_manager
122
-
123
- # Get the MCP servers from the manager
124
- mcp_servers = mcp_manager.servers
117
+ asyncio.run(
118
+ async_main(continue_session=continue_session, session_id=session_id, prompt=prompt, print_mode=print_mode)
119
+ )
125
120
 
126
- # Create agent with MCP servers
127
- agent = create_default_agent(mcp_servers=mcp_servers)
128
121
 
129
- # Determine session to use
130
- session_to_load = None
131
- if continue_session:
132
- session_to_load = find_latest_session()
133
- if not session_to_load:
134
- typer.echo("No existing sessions found for this project.")
135
- raise typer.Exit(1)
136
- typer.echo(f"Continuing session: {session_to_load}")
137
- elif session_id:
138
- session_to_load = session_id
139
- typer.echo(f"Loading session: {session_to_load}")
140
-
141
- # Create app
142
- app_instance = VibecoreApp(vibecore_ctx, agent, session_id=session_to_load, print_mode=print_mode)
143
-
144
- if print_mode:
145
- # Run in print mode
146
- import asyncio
147
-
148
- # Use provided prompt or None to read from stdin
149
- result = asyncio.run(app_instance.run_print(prompt))
150
- # Print raw output to stdout
151
- if result:
152
- print(result)
153
- else:
154
- # Run normal TUI mode
155
- app_instance.run()
122
+ async def async_main(continue_session: bool, session_id: str | None, prompt: str | None, print_mode: bool):
123
+ # Create MCP manager
124
+ async with MCPManager(settings.mcp_servers) as mcp_manager:
125
+ # Create agent with MCP servers
126
+ agent = create_default_agent(mcp_servers=mcp_manager.servers)
127
+
128
+ # Create Vibecore instance
129
+ from vibecore.context import FullVibecoreContext
130
+
131
+ vibecore = Vibecore[FullVibecoreContext, RunResultBase](disable_user_input=False)
132
+
133
+ # Determine session to use
134
+ session_to_load = None
135
+ if continue_session:
136
+ session_to_load = find_latest_session()
137
+ if not session_to_load:
138
+ typer.echo("No existing sessions found for this project.")
139
+ raise typer.Exit(1)
140
+ typer.echo(f"Continuing session: {session_to_load}")
141
+ elif session_id:
142
+ session_to_load = session_id
143
+ typer.echo(f"Loading session: {session_to_load}")
144
+
145
+ if session_to_load is None:
146
+ # Generate a new session ID based on current date/time
147
+ session_to_load = f"chat-{datetime.datetime.now().strftime('%Y%m%d-%H%M%S')}"
148
+
149
+ session = JSONLSession(
150
+ session_id=session_to_load,
151
+ project_path=None, # Will use current working directory
152
+ base_dir=settings.session.base_dir,
153
+ )
154
+
155
+ # Define workflow logic
156
+ @vibecore.workflow()
157
+ async def workflow(
158
+ runner: VibecoreRunner[FullVibecoreContext, RunResultBase],
159
+ user_message: str,
160
+ ) -> RunResultBase:
161
+ # Run the agent with the input
162
+ return await runner.run_agent(
163
+ agent,
164
+ input=user_message,
165
+ context=runner.context,
166
+ max_turns=settings.max_turns,
167
+ session=runner.session,
168
+ )
169
+
170
+ if print_mode:
171
+ # Use static runner for print mode - pass empty input since we get it in workflow
172
+ input_text = prompt.strip() if prompt else sys.stdin.read().strip()
173
+ result = await vibecore.run(input_text)
174
+ # Print raw output to stdout
175
+ print(result.final_output_as(str))
176
+ else:
177
+ # Run in TUI mode
178
+ with contextlib.suppress(AppIsExiting):
179
+ result = await vibecore.run_textual(prompt, session=session)
180
+ print(result)
156
181
 
157
182
 
158
183
  @auth_app.command("login")
@@ -1,29 +1,61 @@
1
1
  from dataclasses import dataclass, field
2
2
  from pathlib import Path
3
- from typing import TYPE_CHECKING, Optional
3
+ from typing import TYPE_CHECKING, Optional, Protocol, runtime_checkable
4
4
 
5
5
  from vibecore.tools.python.manager import PythonExecutionManager
6
6
  from vibecore.tools.todo.manager import TodoManager
7
7
 
8
8
  if TYPE_CHECKING:
9
9
  from vibecore.main import VibecoreApp
10
- from vibecore.mcp import MCPManager
11
10
  from vibecore.tools.path_validator import PathValidator
12
11
 
13
12
 
13
+ @runtime_checkable
14
+ class TodoToolContext(Protocol):
15
+ """Context required by todo tools."""
16
+
17
+ todo_manager: TodoManager
18
+
19
+
20
+ @runtime_checkable
21
+ class PythonToolContext(Protocol):
22
+ """Context required by Python execution tools."""
23
+
24
+ python_manager: PythonExecutionManager
25
+
26
+
27
+ @runtime_checkable
28
+ class PathValidatorContext(Protocol):
29
+ """Context that provides a path validator for file-system tools."""
30
+
31
+ path_validator: "PathValidator"
32
+
33
+
34
+ @runtime_checkable
35
+ class AppAwareContext(Protocol):
36
+ """Context that exposes the optional Textual app for streaming updates."""
37
+
38
+ app: Optional["VibecoreApp"]
39
+
40
+
41
+ @runtime_checkable
42
+ class FullVibecoreContext(TodoToolContext, PythonToolContext, PathValidatorContext, AppAwareContext, Protocol):
43
+ """Protocol describing the full context required by Vibecore agents."""
44
+
45
+ ...
46
+
47
+
14
48
  @dataclass
15
- class VibecoreContext:
49
+ class DefaultVibecoreContext:
16
50
  todo_manager: TodoManager = field(default_factory=TodoManager)
17
51
  python_manager: PythonExecutionManager = field(default_factory=PythonExecutionManager)
18
52
  app: Optional["VibecoreApp"] = None
19
- context_fullness: float = 0.0
20
- mcp_manager: Optional["MCPManager"] = None
21
53
 
22
54
  # Path confinement configuration
23
55
  allowed_directories: list[Path] = field(default_factory=list)
24
56
  path_validator: "PathValidator" = field(init=False) # Always initialized, never None
25
57
 
26
- def __post_init__(self):
58
+ def __post_init__(self) -> None:
27
59
  """Initialize path validator with allowed directories."""
28
60
  from vibecore.tools.path_validator import PathValidator
29
61
 
@@ -49,13 +81,7 @@ class VibecoreContext:
49
81
 
50
82
  self.path_validator = PathValidator(self.allowed_directories)
51
83
 
52
- def reset_state(self) -> None:
53
- """Reset all context state for a new session."""
54
- self.todo_manager = TodoManager()
55
- self.python_manager = PythonExecutionManager()
56
- self.context_fullness = 0.0
57
- # Preserve allowed_directories across resets
58
- # Re-initialize validator in case directories changed
59
- from vibecore.tools.path_validator import PathValidator
60
84
 
61
- self.path_validator = PathValidator(self.allowed_directories)
85
+ if TYPE_CHECKING:
86
+ # Ensure DefaultVibecoreContext conforms to the VibecoreContext protocol for static analyzers
87
+ _default_context: FullVibecoreContext = DefaultVibecoreContext()