sabbatical 0.1.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.
Files changed (46) hide show
  1. sabbatical-0.1.0/LICENSE +21 -0
  2. sabbatical-0.1.0/PKG-INFO +312 -0
  3. sabbatical-0.1.0/README.md +257 -0
  4. sabbatical-0.1.0/pyproject.toml +48 -0
  5. sabbatical-0.1.0/src/sabbatical/__init__.py +1 -0
  6. sabbatical-0.1.0/src/sabbatical/__main__.py +4 -0
  7. sabbatical-0.1.0/src/sabbatical/api/__init__.py +1 -0
  8. sabbatical-0.1.0/src/sabbatical/api/app.py +107 -0
  9. sabbatical-0.1.0/src/sabbatical/api/broadcast.py +51 -0
  10. sabbatical-0.1.0/src/sabbatical/api/dependencies.py +20 -0
  11. sabbatical-0.1.0/src/sabbatical/api/routers/__init__.py +1 -0
  12. sabbatical-0.1.0/src/sabbatical/api/routers/agents.py +317 -0
  13. sabbatical-0.1.0/src/sabbatical/api/routers/organizations.py +182 -0
  14. sabbatical-0.1.0/src/sabbatical/api/routers/runs.py +133 -0
  15. sabbatical-0.1.0/src/sabbatical/api/routers/status.py +48 -0
  16. sabbatical-0.1.0/src/sabbatical/api/routers/tasks.py +469 -0
  17. sabbatical-0.1.0/src/sabbatical/api/schemas.py +220 -0
  18. sabbatical-0.1.0/src/sabbatical/cli/__init__.py +1 -0
  19. sabbatical-0.1.0/src/sabbatical/cli/agent_cmds.py +168 -0
  20. sabbatical-0.1.0/src/sabbatical/cli/formatters.py +108 -0
  21. sabbatical-0.1.0/src/sabbatical/cli/main.py +25 -0
  22. sabbatical-0.1.0/src/sabbatical/cli/org_cmds.py +131 -0
  23. sabbatical-0.1.0/src/sabbatical/cli/run_cmds.py +81 -0
  24. sabbatical-0.1.0/src/sabbatical/cli/server_cmds.py +123 -0
  25. sabbatical-0.1.0/src/sabbatical/cli/task_cmds.py +203 -0
  26. sabbatical-0.1.0/src/sabbatical/core/__init__.py +0 -0
  27. sabbatical-0.1.0/src/sabbatical/core/agent/__init__.py +1 -0
  28. sabbatical-0.1.0/src/sabbatical/core/agent/runtime.py +60 -0
  29. sabbatical-0.1.0/src/sabbatical/core/agent/tools.py +301 -0
  30. sabbatical-0.1.0/src/sabbatical/core/config.py +69 -0
  31. sabbatical-0.1.0/src/sabbatical/core/context_builder.py +207 -0
  32. sabbatical-0.1.0/src/sabbatical/core/cost.py +54 -0
  33. sabbatical-0.1.0/src/sabbatical/core/db.py +177 -0
  34. sabbatical-0.1.0/src/sabbatical/core/description_generator.py +100 -0
  35. sabbatical-0.1.0/src/sabbatical/core/dispatcher.py +258 -0
  36. sabbatical-0.1.0/src/sabbatical/core/logging_setup.py +35 -0
  37. sabbatical-0.1.0/src/sabbatical/core/tag_parser.py +26 -0
  38. sabbatical-0.1.0/src/sabbatical/core/worker.py +472 -0
  39. sabbatical-0.1.0/src/sabbatical/mcp/__init__.py +0 -0
  40. sabbatical-0.1.0/src/sabbatical/mcp/server.py +303 -0
  41. sabbatical-0.1.0/src/sabbatical/migrations/README +1 -0
  42. sabbatical-0.1.0/src/sabbatical/migrations/env.py +80 -0
  43. sabbatical-0.1.0/src/sabbatical/migrations/script.py.mako +28 -0
  44. sabbatical-0.1.0/src/sabbatical/migrations/versions/a1b2c3d4e5f6_remove_sessions.py +52 -0
  45. sabbatical-0.1.0/src/sabbatical/migrations/versions/b569fc0a5c4c_initial.py +103 -0
  46. sabbatical-0.1.0/src/sabbatical/migrations/versions/d47fbc9edd39_add_model_column_to_agents.py +32 -0
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2011-2026 The Bootstrap Authors
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in
13
+ all copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
21
+ THE SOFTWARE.
@@ -0,0 +1,312 @@
1
+ Metadata-Version: 2.4
2
+ Name: sabbatical
3
+ Version: 0.1.0
4
+ Summary: Local AI agent orchestration CLI — async task collaboration for developers
5
+ License: The MIT License (MIT)
6
+
7
+ Copyright (c) 2011-2026 The Bootstrap Authors
8
+
9
+ Permission is hereby granted, free of charge, to any person obtaining a copy
10
+ of this software and associated documentation files (the "Software"), to deal
11
+ in the Software without restriction, including without limitation the rights
12
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13
+ copies of the Software, and to permit persons to whom the Software is
14
+ furnished to do so, subject to the following conditions:
15
+
16
+ The above copyright notice and this permission notice shall be included in
17
+ all copies or substantial portions of the Software.
18
+
19
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25
+ THE SOFTWARE.
26
+ License-File: LICENSE
27
+ Keywords: ai,agents,cli,orchestration,llm,automation
28
+ Author: elpapi42
29
+ Requires-Python: >=3.12,<4.0
30
+ Classifier: Development Status :: 3 - Alpha
31
+ Classifier: Environment :: Console
32
+ Classifier: Intended Audience :: Developers
33
+ Classifier: License :: OSI Approved :: MIT License
34
+ Classifier: Operating System :: OS Independent
35
+ Classifier: Programming Language :: Python :: 3
36
+ Classifier: Programming Language :: Python :: 3.12
37
+ Classifier: Topic :: Software Development :: Libraries
38
+ Classifier: Topic :: Utilities
39
+ Requires-Dist: alembic (>=1.13.0)
40
+ Requires-Dist: databases[aiosqlite] (>=0.9.0)
41
+ Requires-Dist: fastapi (>=0.111.0)
42
+ Requires-Dist: google-adk[extensions] (>=0.1.0)
43
+ Requires-Dist: httpx (>=0.27.0)
44
+ Requires-Dist: mcp (>=1.26.0)
45
+ Requires-Dist: pydantic (>=2.7.0)
46
+ Requires-Dist: sqlalchemy (>=2.0.0)
47
+ Requires-Dist: sse-starlette (>=2.1.0)
48
+ Requires-Dist: typer[all] (>=0.12.0)
49
+ Requires-Dist: uvicorn[standard] (>=0.30.0)
50
+ Project-URL: Homepage, https://github.com/elpapi42/sabbatical
51
+ Project-URL: Issues, https://github.com/elpapi42/sabbatical/issues
52
+ Project-URL: Repository, https://github.com/elpapi42/sabbatical
53
+ Description-Content-Type: text/markdown
54
+
55
+ # Sabbatical
56
+
57
+ **A local AI agent orchestration system built around async task collaboration — not chat sessions.**
58
+
59
+ ---
60
+
61
+ Most people use AI by opening a chat window, typing a request, and waiting. The AI responds. You react. It's a conversation — synchronous, serial, one thing at a time. You're blocked until it finishes, and it's blocked until you respond.
62
+
63
+ Sabbatical is a different model. You write a task spec. You assign it to an agent. The agent picks it up, does the work using real tools in your actual codebase, hands it off to another agent via an `@mention`, and those agents keep working until the task surfaces back to you — done, blocked, or ready for review. Meanwhile, you're working on something else.
64
+
65
+ It's the difference between pair programming on a video call and managing a team through tasks. The team model scales. The call doesn't.
66
+
67
+ ---
68
+
69
+ ## How It Works
70
+
71
+ Sabbatical runs a **local API server** on your machine. The server manages a **database-as-queue**: it continuously polls for tasks assigned to agents, spins up worker threads, runs agents against real tools (file reads, file writes, shell commands), and processes their output. There is no cloud dependency. Everything — the database, the agent workspace, the execution — lives on your machine.
72
+
73
+ ### The Core Concepts
74
+
75
+ **Organizations** are isolated workspaces. Each organization has a `workspace_path` (a directory on your machine) and a roster of agents. Agents in different organizations cannot interact.
76
+
77
+ **Agents** are stateless worker profiles defined by a `.md` instruction file. The instruction file is the agent's identity: its expertise, its working style, its persona. Agents don't persist state between executions — their only context is the task description and the comment thread.
78
+
79
+ **Tasks** are the unit of work. Each task has a title, a detailed description (the spec), a status, an assignee, and a **comment thread**. The thread is the shared memory of the task: every agent that works on it leaves a comment, and every future agent reads the full thread before picking up where the previous one left off.
80
+
81
+ **The Comment Thread** is what makes multi-agent collaboration coherent. Agents can't see each other's internal reasoning or tool calls — those are private to each run. But they see every comment in the thread. When an agent hands off to another with `@agent_name`, the next agent receives the full thread context including that handoff message. No context is lost between agents.
82
+
83
+ **The Dispatcher** is the always-on polling loop that drives everything. It claims dispatchable tasks atomically (preventing double-execution), spins up a worker thread per task, and processes the agent's final output to determine routing. It runs inside the API server — `server up` starts it, `server down` gracefully stops it.
84
+
85
+ ### The Handoff Protocol
86
+
87
+ When an agent finishes its work, it writes a final message. That message becomes a permanent comment on the task thread. The system reads the **first valid `@tag`** in that message to determine where the task goes next:
88
+
89
+ - `@agent_name` → task is routed to that agent, queued for dispatch
90
+ - `@user` → task returns to you for review or input
91
+ - No valid tag → task escalates to the agent's boss; if no boss, it goes to you
92
+
93
+ This is how agents collaborate without you in the loop. A `lead_dev` agent can delegate a specific problem to a `frontend_dev`, who can hand the result back to `lead_dev` for review, who can then return it to `@user`. Three agents, zero interruptions for you.
94
+
95
+ ### The Hierarchy
96
+
97
+ Agents can have a **boss** — another agent in the same organization. The hierarchy is informational, not restrictive: any agent can tag any other agent in the organization. But the hierarchy powers smart escalation: if an agent fails to route properly (no valid tag in its output), the dispatcher automatically escalates to its boss. This gives you a safety net and a natural review chain.
98
+
99
+ ---
100
+
101
+ ## A Real Workflow
102
+
103
+ You're building a React app. You have an organization `react_app` with three agents: `lead_dev` (root), `frontend_dev` (reports to `lead_dev`), and `test_writer` (reports to `lead_dev`).
104
+
105
+ You write a task spec and kick it off:
106
+
107
+ ```bash
108
+ sabbatical task create "Add dark mode toggle to the header" \
109
+ --organization react_app \
110
+ --description "Implement a dark/light mode toggle in the header component. Use Tailwind's dark: prefix classes. The toggle should persist preference in localStorage. Existing header is at src/components/Header.tsx." \
111
+ --assign lead_dev
112
+ ```
113
+
114
+ `lead_dev` picks it up. It reads the spec, inspects the codebase with `read_file` and `list_directory`, and decides this is UI work for `frontend_dev`. It writes a detailed handoff comment explaining the approach and tags `@frontend_dev`. You're not involved.
115
+
116
+ `frontend_dev` picks up the task. It reads the thread — including `lead_dev`'s briefing — modifies `Header.tsx`, adds a `ThemeToggle` component, and updates the Tailwind config. It finishes and tags `@test_writer` with a summary of what was changed.
117
+
118
+ `test_writer` reads the thread, understands the full context of what was built, and writes tests for the toggle behavior. It tags `@lead_dev` for a final review pass.
119
+
120
+ `lead_dev` reviews everything, requests a small change via a comment, tags `@frontend_dev` again. `frontend_dev` makes the fix, tags `@lead_dev`. `lead_dev` approves and tags `@user`.
121
+
122
+ You get a notification. You check the thread with `task view`, see the full history of what every agent did, review the code changes in your editor, and run `task done REAC-0012`.
123
+
124
+ While all of that was happening, you were working on three other tasks.
125
+
126
+ ---
127
+
128
+ ## The Assistant
129
+
130
+ Sabbatical includes a conversational planning copilot — **The Assistant** — for when you want help structuring work before delegating it.
131
+
132
+ ```bash
133
+ sabbatical chat new --organization react_app
134
+ ```
135
+
136
+ The Assistant knows your organization's agents and hierarchy. It helps you break down high-level goals into atomic tasks, writes detailed task specs that stateless agents can execute without ambiguity, and assigns tasks to the right agents. It can also bootstrap entire organizations from scratch — proposing agent names, hierarchies, and instruction files — if you're starting a new project.
137
+
138
+ The Assistant never executes technical work. It is a planning layer, not a worker. Workers are agents.
139
+
140
+ ---
141
+
142
+ ## Setup
143
+
144
+ ### Prerequisites
145
+
146
+ - Python 3.12+
147
+ - Poetry
148
+ - An [OpenRouter](https://openrouter.ai) API key (Open to contributions to make more providers available, even Claude Code, Codex, Gemini adapters)
149
+
150
+ ### Install
151
+
152
+ ```bash
153
+ git clone https://github.com/elpapi42/sabbatical.git
154
+ cd sabbatical
155
+ poetry install
156
+ ```
157
+
158
+ ### Configure
159
+
160
+ ```bash
161
+ export OPENROUTER_API_KEY="sk-or-your-key-here"
162
+ ```
163
+
164
+ The config file is auto-generated at `~/.sabbatical/config.toml` on first run. Edit it to change the default model, concurrency limit, or server port.
165
+
166
+ ### Start the Server
167
+
168
+ ```bash
169
+ poetry run sabbatical server up
170
+ ```
171
+
172
+ The server starts in the background. The dispatcher begins polling immediately. Any tasks already queued in the database from a previous session are picked up automatically.
173
+
174
+ ```bash
175
+ poetry run sabbatical server status # snapshot: task counts, active workers, total cost
176
+ poetry run sabbatical server down # graceful shutdown; active runs finish before stopping
177
+ ```
178
+
179
+ ---
180
+
181
+ ## CLI Reference
182
+
183
+ ### Organizations
184
+
185
+ ```bash
186
+ sabbatical organization create <name> --workspace-path <path> --description "<text>"
187
+ sabbatical organization list
188
+ sabbatical organization view <name> # hierarchy tree
189
+ sabbatical organization delete <name> # cascade deletes all agents, tasks, runs
190
+ ```
191
+
192
+ ### Agents
193
+
194
+ ```bash
195
+ sabbatical agent add <name> --organization <org> --instructions <path.md>
196
+ sabbatical agent add <name> --organization <org> --instructions <path.md> --boss <boss_name> --description "<one-liner>"
197
+ sabbatical agent list --organization <org>
198
+ sabbatical agent view <name> --organization <org>
199
+ sabbatical agent edit <name> --organization <org> --boss <name>
200
+ sabbatical agent remove <name> --organization <org> # soft-delete; history preserved
201
+ ```
202
+
203
+ ### Tasks
204
+
205
+ ```bash
206
+ sabbatical task create "<title>" --organization <org> --assign <agent|user> --description "<spec>"
207
+ sabbatical task list --organization <org> --status <open|in_progress|failed|done|canceled>
208
+ sabbatical task view <id> # full thread: comments + run summaries interleaved
209
+ sabbatical task comment <id> "<message>" # @mention an agent to delegate/unblock
210
+ sabbatical task preempt <id> # interrupt an in-progress task
211
+ sabbatical task done <id> # you verify and close
212
+ sabbatical task cancel <id>
213
+ sabbatical task reopen <id>
214
+ ```
215
+
216
+ ### Runs
217
+
218
+ ```bash
219
+ sabbatical run view <run-id> # full step-by-step: tool calls, arguments, stdout/stderr
220
+ sabbatical run list --task <id>
221
+ ```
222
+
223
+ ### Chat (The Assistant)
224
+
225
+ ```bash
226
+ sabbatical chat new [--organization <org>]
227
+ sabbatical chat list
228
+ sabbatical chat resume <session-id>
229
+ ```
230
+
231
+ ---
232
+
233
+ ## Writing Agent Instructions
234
+
235
+ An agent's identity lives in a `.md` file referenced by `--instructions`. This file is its character sheet: who it is, what it knows, how it works. Write it as if describing a real team member.
236
+
237
+ ```markdown
238
+ # lead_dev
239
+
240
+ You are the lead developer for this project. You own overall code quality and architecture decisions.
241
+
242
+ When a task comes to you, your first job is to understand the full scope, then either execute it yourself or break it into focused sub-problems and delegate to the right specialist on your team.
243
+
244
+ Your team:
245
+ - @frontend_dev — React, TypeScript, UI/UX
246
+ - @test_writer — unit tests, integration tests, coverage
247
+
248
+ When delegating, write a clear briefing in your handoff: what you've already done, what you need from them, and any constraints or decisions they should know about. The next agent's only context is this thread.
249
+ ```
250
+
251
+ The instruction file is injected into every run as part of the agent's context. Keep it specific. Generic instructions produce generic agents.
252
+
253
+ ---
254
+
255
+ ## Architecture
256
+
257
+ ```
258
+ ┌─────────────────────────────────────────────────────┐
259
+ │ Local API Server │
260
+ │ │
261
+ │ ┌─────────────┐ ┌────────────────────────────┐ │
262
+ │ │ Dispatcher │ │ Worker Threads │ │
263
+ │ │ (polling │───▶│ Agent + ADK Runner │ │
264
+ │ │ loop) │ │ Tools: read/write/shell │ │
265
+ │ └─────────────┘ └────────────────────────────┘ │
266
+ │ │ │ │
267
+ │ ▼ ▼ │
268
+ │ ┌──────────────────────────────────────────────┐ │
269
+ │ │ SQLite Database │ │
270
+ │ │ organizations · agents · tasks · comments │ │
271
+ │ │ runs · sessions │ │
272
+ │ └──────────────────────────────────────────────┘ │
273
+ └─────────────────────────────────────────────────────┘
274
+
275
+ │ HTTP
276
+
277
+ ┌──────────┐
278
+ │ Thin CLI │ (sabbatical <command>)
279
+ └──────────┘
280
+ ```
281
+
282
+ - **Database-as-queue**: no in-memory event bus. The dispatcher polls SQLite directly. Crash recovery is zero-effort — on `server up`, the dispatcher resumes polling and picks up any open tasks.
283
+ - **LLM provider**: all calls route through [OpenRouter](https://openrouter.ai), giving you access to any model.
284
+ - **Agent runtime**: built on [Google ADK](https://google.github.io/adk-docs/) with LiteLLM for model routing.
285
+ - **Stateless workers**: each run is a fresh agent instance. Context is injected entirely through the system prompt and the task thread.
286
+
287
+ ---
288
+
289
+ ## Development
290
+
291
+ ```bash
292
+ # Generate a new DB migration after changing the schema
293
+ poetry run alembic revision --autogenerate -m "describe_the_change"
294
+
295
+ # Apply migrations manually
296
+ poetry run alembic upgrade head
297
+ ```
298
+
299
+ Migrations run automatically on `server up`. The database lives at `~/.sabbatical/sabbatical.db`.
300
+
301
+ ---
302
+
303
+ ## Status
304
+
305
+ Sabbatical is under active development. V1 is focused on establishing the core execution model: local multi-agent task collaboration with a stable state machine, real tool access, and cost tracking. Planned for future iterations: context window management (thread summarization), richer task decomposition primitives, and broader LLM provider support.
306
+
307
+ ---
308
+
309
+ ## Contributing
310
+
311
+ Issues and PRs are welcome. If you're building something with Sabbatical or have feedback on the agent collaboration model, open a discussion.
312
+
@@ -0,0 +1,257 @@
1
+ # Sabbatical
2
+
3
+ **A local AI agent orchestration system built around async task collaboration — not chat sessions.**
4
+
5
+ ---
6
+
7
+ Most people use AI by opening a chat window, typing a request, and waiting. The AI responds. You react. It's a conversation — synchronous, serial, one thing at a time. You're blocked until it finishes, and it's blocked until you respond.
8
+
9
+ Sabbatical is a different model. You write a task spec. You assign it to an agent. The agent picks it up, does the work using real tools in your actual codebase, hands it off to another agent via an `@mention`, and those agents keep working until the task surfaces back to you — done, blocked, or ready for review. Meanwhile, you're working on something else.
10
+
11
+ It's the difference between pair programming on a video call and managing a team through tasks. The team model scales. The call doesn't.
12
+
13
+ ---
14
+
15
+ ## How It Works
16
+
17
+ Sabbatical runs a **local API server** on your machine. The server manages a **database-as-queue**: it continuously polls for tasks assigned to agents, spins up worker threads, runs agents against real tools (file reads, file writes, shell commands), and processes their output. There is no cloud dependency. Everything — the database, the agent workspace, the execution — lives on your machine.
18
+
19
+ ### The Core Concepts
20
+
21
+ **Organizations** are isolated workspaces. Each organization has a `workspace_path` (a directory on your machine) and a roster of agents. Agents in different organizations cannot interact.
22
+
23
+ **Agents** are stateless worker profiles defined by a `.md` instruction file. The instruction file is the agent's identity: its expertise, its working style, its persona. Agents don't persist state between executions — their only context is the task description and the comment thread.
24
+
25
+ **Tasks** are the unit of work. Each task has a title, a detailed description (the spec), a status, an assignee, and a **comment thread**. The thread is the shared memory of the task: every agent that works on it leaves a comment, and every future agent reads the full thread before picking up where the previous one left off.
26
+
27
+ **The Comment Thread** is what makes multi-agent collaboration coherent. Agents can't see each other's internal reasoning or tool calls — those are private to each run. But they see every comment in the thread. When an agent hands off to another with `@agent_name`, the next agent receives the full thread context including that handoff message. No context is lost between agents.
28
+
29
+ **The Dispatcher** is the always-on polling loop that drives everything. It claims dispatchable tasks atomically (preventing double-execution), spins up a worker thread per task, and processes the agent's final output to determine routing. It runs inside the API server — `server up` starts it, `server down` gracefully stops it.
30
+
31
+ ### The Handoff Protocol
32
+
33
+ When an agent finishes its work, it writes a final message. That message becomes a permanent comment on the task thread. The system reads the **first valid `@tag`** in that message to determine where the task goes next:
34
+
35
+ - `@agent_name` → task is routed to that agent, queued for dispatch
36
+ - `@user` → task returns to you for review or input
37
+ - No valid tag → task escalates to the agent's boss; if no boss, it goes to you
38
+
39
+ This is how agents collaborate without you in the loop. A `lead_dev` agent can delegate a specific problem to a `frontend_dev`, who can hand the result back to `lead_dev` for review, who can then return it to `@user`. Three agents, zero interruptions for you.
40
+
41
+ ### The Hierarchy
42
+
43
+ Agents can have a **boss** — another agent in the same organization. The hierarchy is informational, not restrictive: any agent can tag any other agent in the organization. But the hierarchy powers smart escalation: if an agent fails to route properly (no valid tag in its output), the dispatcher automatically escalates to its boss. This gives you a safety net and a natural review chain.
44
+
45
+ ---
46
+
47
+ ## A Real Workflow
48
+
49
+ You're building a React app. You have an organization `react_app` with three agents: `lead_dev` (root), `frontend_dev` (reports to `lead_dev`), and `test_writer` (reports to `lead_dev`).
50
+
51
+ You write a task spec and kick it off:
52
+
53
+ ```bash
54
+ sabbatical task create "Add dark mode toggle to the header" \
55
+ --organization react_app \
56
+ --description "Implement a dark/light mode toggle in the header component. Use Tailwind's dark: prefix classes. The toggle should persist preference in localStorage. Existing header is at src/components/Header.tsx." \
57
+ --assign lead_dev
58
+ ```
59
+
60
+ `lead_dev` picks it up. It reads the spec, inspects the codebase with `read_file` and `list_directory`, and decides this is UI work for `frontend_dev`. It writes a detailed handoff comment explaining the approach and tags `@frontend_dev`. You're not involved.
61
+
62
+ `frontend_dev` picks up the task. It reads the thread — including `lead_dev`'s briefing — modifies `Header.tsx`, adds a `ThemeToggle` component, and updates the Tailwind config. It finishes and tags `@test_writer` with a summary of what was changed.
63
+
64
+ `test_writer` reads the thread, understands the full context of what was built, and writes tests for the toggle behavior. It tags `@lead_dev` for a final review pass.
65
+
66
+ `lead_dev` reviews everything, requests a small change via a comment, tags `@frontend_dev` again. `frontend_dev` makes the fix, tags `@lead_dev`. `lead_dev` approves and tags `@user`.
67
+
68
+ You get a notification. You check the thread with `task view`, see the full history of what every agent did, review the code changes in your editor, and run `task done REAC-0012`.
69
+
70
+ While all of that was happening, you were working on three other tasks.
71
+
72
+ ---
73
+
74
+ ## The Assistant
75
+
76
+ Sabbatical includes a conversational planning copilot — **The Assistant** — for when you want help structuring work before delegating it.
77
+
78
+ ```bash
79
+ sabbatical chat new --organization react_app
80
+ ```
81
+
82
+ The Assistant knows your organization's agents and hierarchy. It helps you break down high-level goals into atomic tasks, writes detailed task specs that stateless agents can execute without ambiguity, and assigns tasks to the right agents. It can also bootstrap entire organizations from scratch — proposing agent names, hierarchies, and instruction files — if you're starting a new project.
83
+
84
+ The Assistant never executes technical work. It is a planning layer, not a worker. Workers are agents.
85
+
86
+ ---
87
+
88
+ ## Setup
89
+
90
+ ### Prerequisites
91
+
92
+ - Python 3.12+
93
+ - Poetry
94
+ - An [OpenRouter](https://openrouter.ai) API key (Open to contributions to make more providers available, even Claude Code, Codex, Gemini adapters)
95
+
96
+ ### Install
97
+
98
+ ```bash
99
+ git clone https://github.com/elpapi42/sabbatical.git
100
+ cd sabbatical
101
+ poetry install
102
+ ```
103
+
104
+ ### Configure
105
+
106
+ ```bash
107
+ export OPENROUTER_API_KEY="sk-or-your-key-here"
108
+ ```
109
+
110
+ The config file is auto-generated at `~/.sabbatical/config.toml` on first run. Edit it to change the default model, concurrency limit, or server port.
111
+
112
+ ### Start the Server
113
+
114
+ ```bash
115
+ poetry run sabbatical server up
116
+ ```
117
+
118
+ The server starts in the background. The dispatcher begins polling immediately. Any tasks already queued in the database from a previous session are picked up automatically.
119
+
120
+ ```bash
121
+ poetry run sabbatical server status # snapshot: task counts, active workers, total cost
122
+ poetry run sabbatical server down # graceful shutdown; active runs finish before stopping
123
+ ```
124
+
125
+ ---
126
+
127
+ ## CLI Reference
128
+
129
+ ### Organizations
130
+
131
+ ```bash
132
+ sabbatical organization create <name> --workspace-path <path> --description "<text>"
133
+ sabbatical organization list
134
+ sabbatical organization view <name> # hierarchy tree
135
+ sabbatical organization delete <name> # cascade deletes all agents, tasks, runs
136
+ ```
137
+
138
+ ### Agents
139
+
140
+ ```bash
141
+ sabbatical agent add <name> --organization <org> --instructions <path.md>
142
+ sabbatical agent add <name> --organization <org> --instructions <path.md> --boss <boss_name> --description "<one-liner>"
143
+ sabbatical agent list --organization <org>
144
+ sabbatical agent view <name> --organization <org>
145
+ sabbatical agent edit <name> --organization <org> --boss <name>
146
+ sabbatical agent remove <name> --organization <org> # soft-delete; history preserved
147
+ ```
148
+
149
+ ### Tasks
150
+
151
+ ```bash
152
+ sabbatical task create "<title>" --organization <org> --assign <agent|user> --description "<spec>"
153
+ sabbatical task list --organization <org> --status <open|in_progress|failed|done|canceled>
154
+ sabbatical task view <id> # full thread: comments + run summaries interleaved
155
+ sabbatical task comment <id> "<message>" # @mention an agent to delegate/unblock
156
+ sabbatical task preempt <id> # interrupt an in-progress task
157
+ sabbatical task done <id> # you verify and close
158
+ sabbatical task cancel <id>
159
+ sabbatical task reopen <id>
160
+ ```
161
+
162
+ ### Runs
163
+
164
+ ```bash
165
+ sabbatical run view <run-id> # full step-by-step: tool calls, arguments, stdout/stderr
166
+ sabbatical run list --task <id>
167
+ ```
168
+
169
+ ### Chat (The Assistant)
170
+
171
+ ```bash
172
+ sabbatical chat new [--organization <org>]
173
+ sabbatical chat list
174
+ sabbatical chat resume <session-id>
175
+ ```
176
+
177
+ ---
178
+
179
+ ## Writing Agent Instructions
180
+
181
+ An agent's identity lives in a `.md` file referenced by `--instructions`. This file is its character sheet: who it is, what it knows, how it works. Write it as if describing a real team member.
182
+
183
+ ```markdown
184
+ # lead_dev
185
+
186
+ You are the lead developer for this project. You own overall code quality and architecture decisions.
187
+
188
+ When a task comes to you, your first job is to understand the full scope, then either execute it yourself or break it into focused sub-problems and delegate to the right specialist on your team.
189
+
190
+ Your team:
191
+ - @frontend_dev — React, TypeScript, UI/UX
192
+ - @test_writer — unit tests, integration tests, coverage
193
+
194
+ When delegating, write a clear briefing in your handoff: what you've already done, what you need from them, and any constraints or decisions they should know about. The next agent's only context is this thread.
195
+ ```
196
+
197
+ The instruction file is injected into every run as part of the agent's context. Keep it specific. Generic instructions produce generic agents.
198
+
199
+ ---
200
+
201
+ ## Architecture
202
+
203
+ ```
204
+ ┌─────────────────────────────────────────────────────┐
205
+ │ Local API Server │
206
+ │ │
207
+ │ ┌─────────────┐ ┌────────────────────────────┐ │
208
+ │ │ Dispatcher │ │ Worker Threads │ │
209
+ │ │ (polling │───▶│ Agent + ADK Runner │ │
210
+ │ │ loop) │ │ Tools: read/write/shell │ │
211
+ │ └─────────────┘ └────────────────────────────┘ │
212
+ │ │ │ │
213
+ │ ▼ ▼ │
214
+ │ ┌──────────────────────────────────────────────┐ │
215
+ │ │ SQLite Database │ │
216
+ │ │ organizations · agents · tasks · comments │ │
217
+ │ │ runs · sessions │ │
218
+ │ └──────────────────────────────────────────────┘ │
219
+ └─────────────────────────────────────────────────────┘
220
+
221
+ │ HTTP
222
+
223
+ ┌──────────┐
224
+ │ Thin CLI │ (sabbatical <command>)
225
+ └──────────┘
226
+ ```
227
+
228
+ - **Database-as-queue**: no in-memory event bus. The dispatcher polls SQLite directly. Crash recovery is zero-effort — on `server up`, the dispatcher resumes polling and picks up any open tasks.
229
+ - **LLM provider**: all calls route through [OpenRouter](https://openrouter.ai), giving you access to any model.
230
+ - **Agent runtime**: built on [Google ADK](https://google.github.io/adk-docs/) with LiteLLM for model routing.
231
+ - **Stateless workers**: each run is a fresh agent instance. Context is injected entirely through the system prompt and the task thread.
232
+
233
+ ---
234
+
235
+ ## Development
236
+
237
+ ```bash
238
+ # Generate a new DB migration after changing the schema
239
+ poetry run alembic revision --autogenerate -m "describe_the_change"
240
+
241
+ # Apply migrations manually
242
+ poetry run alembic upgrade head
243
+ ```
244
+
245
+ Migrations run automatically on `server up`. The database lives at `~/.sabbatical/sabbatical.db`.
246
+
247
+ ---
248
+
249
+ ## Status
250
+
251
+ Sabbatical is under active development. V1 is focused on establishing the core execution model: local multi-agent task collaboration with a stable state machine, real tool access, and cost tracking. Planned for future iterations: context window management (thread summarization), richer task decomposition primitives, and broader LLM provider support.
252
+
253
+ ---
254
+
255
+ ## Contributing
256
+
257
+ Issues and PRs are welcome. If you're building something with Sabbatical or have feedback on the agent collaboration model, open a discussion.
@@ -0,0 +1,48 @@
1
+ [project]
2
+ name = "sabbatical"
3
+ version = "0.1.0"
4
+ description = "Local AI agent orchestration CLI — async task collaboration for developers"
5
+ readme = "README.md"
6
+ license = { file = "LICENSE" }
7
+ requires-python = ">=3.12,<4.0"
8
+ authors = [
9
+ { name = "elpapi42" }
10
+ ]
11
+ keywords = ["ai", "agents", "cli", "orchestration", "llm", "automation"]
12
+ classifiers = [
13
+ "Development Status :: 3 - Alpha",
14
+ "Environment :: Console",
15
+ "Intended Audience :: Developers",
16
+ "License :: OSI Approved :: MIT License",
17
+ "Operating System :: OS Independent",
18
+ "Programming Language :: Python :: 3",
19
+ "Programming Language :: Python :: 3.12",
20
+ "Topic :: Software Development :: Libraries",
21
+ "Topic :: Utilities",
22
+ ]
23
+ dependencies = [
24
+ "fastapi>=0.111.0",
25
+ "uvicorn[standard]>=0.30.0",
26
+ "databases[aiosqlite]>=0.9.0",
27
+ "sqlalchemy>=2.0.0",
28
+ "alembic>=1.13.0",
29
+ "pydantic>=2.7.0",
30
+ "typer[all]>=0.12.0",
31
+ "httpx>=0.27.0",
32
+ "sse-starlette>=2.1.0",
33
+ "google-adk[extensions]>=0.1.0",
34
+ "mcp>=1.26.0",
35
+ ]
36
+
37
+ [project.urls]
38
+ Homepage = "https://github.com/elpapi42/sabbatical"
39
+ Repository = "https://github.com/elpapi42/sabbatical"
40
+ Issues = "https://github.com/elpapi42/sabbatical/issues"
41
+
42
+ [project.scripts]
43
+ sabbatical = "sabbatical.cli.main:app"
44
+ sabbatical-mcp = "sabbatical.mcp.server:main"
45
+
46
+ [build-system]
47
+ requires = ["poetry-core>=2.0.0"]
48
+ build-backend = "poetry.core.masonry.api"
@@ -0,0 +1 @@
1
+ """Sabbatical - AI Agent Orchestration CLI"""
@@ -0,0 +1,4 @@
1
+ from sabbatical.cli.main import app
2
+
3
+ if __name__ == "__main__":
4
+ app()
@@ -0,0 +1 @@
1
+ """Server package."""