tasktree-manager 2.17.0__tar.gz → 2.19.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.
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/CHANGELOG.md +15 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/PKG-INFO +1 -1
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/README.md +82 -50
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/docs/configuration.md +11 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/docs/user-guide.md +89 -22
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/pyproject.toml +1 -1
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/_version.py +2 -2
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/app.py +193 -36
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/cli.py +162 -17
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/agent_sessions.py +13 -4
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/claude_sessions.py +35 -19
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/config.py +22 -0
- tasktree_manager-2.19.0/tasktree_manager/services/epic_ask.py +246 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/epic_log.py +21 -2
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/git_ops.py +1 -1
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/models.py +4 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/task_manager.py +47 -7
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_app.py +1 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_app_review_fixes.py +45 -6
- tasktree_manager-2.19.0/tests/test_epic_ask.py +402 -0
- tasktree_manager-2.19.0/tests/test_review_findings.py +208 -0
- tasktree_manager-2.19.0/tests/test_terminal_tabs.py +225 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/SKILL.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/assets/README.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/assets/dashboard_app.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/assets/data_viewer.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/assets/todo_app.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/assets/worker_demo.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/references/layouts.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/references/official-guides-index.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/references/styling.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.claude/skills/textual-tui/references/widgets.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.github/templates/CHANGELOG.md.j2 +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.github/workflows/ci.yml +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.github/workflows/release.yml +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/.gitignore +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/CONTRIBUTING.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/LICENSE +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/ROADMAP.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/docs/claude-code-integration-spec.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/docs/installation.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/docs/troubleshooting.md +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/mise.toml +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/scripts/bump_version.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/__init__.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/commands.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/__init__.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/claude_hooks.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/services/forge.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/themes.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/__init__.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/app_header.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/create_modal.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/messages_panel.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/setup_modal.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/status_panel.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/task_list.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tasktree_manager/widgets/worktree_list.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/__init__.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/conftest.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_agent_sessions.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_agent_sessions_decode.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_bump_version.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_claude_hooks.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_claude_sessions.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_cli.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_commands.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_config.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_epic_claude_md.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_epic_log.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_epic_tui.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_epics.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_forge.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_git_ops.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_integration_git.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_list_selection.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_medium_fixes.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_memory.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_messages_panel.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_modals.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_safety_fixes.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_setup_modal.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_status_panel.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_task_manager.py +0 -0
- {tasktree_manager-2.17.0 → tasktree_manager-2.19.0}/tests/test_worktree_badges.py +0 -0
|
@@ -15,6 +15,21 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
15
15
|
- Git hooks support
|
|
16
16
|
- Custom task metadata
|
|
17
17
|
|
|
18
|
+
## [2.19.0] - 2026-10-29
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- Open zellij tabs that survive a terminal restart, and review fixes (#16)
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- Split the headless CLI and epic sections into short parts (#15)
|
|
25
|
+
|
|
26
|
+
|
|
27
|
+
## [2.18.0] - 2026-10-20
|
|
28
|
+
|
|
29
|
+
### Added
|
|
30
|
+
- **epic**: Ask another task's session with epic ask (#14)
|
|
31
|
+
|
|
32
|
+
|
|
18
33
|
## [2.17.0] - 2026-10-20
|
|
19
34
|
|
|
20
35
|
### Added
|
|
@@ -22,7 +22,8 @@
|
|
|
22
22
|
- 🛰️ **Agent Dashboard** - Live Claude Code session state per worktree (from `claude agents`), plus one-key background-agent dispatch — the multi-repo agent view Claude Code lacks natively
|
|
23
23
|
- ✻ **Session Recap** - The Info panel shows each task's latest Claude Code session: title, last turn duration, and Claude's own idle recap of what was done and what comes next — read straight from the transcript, no CLI call
|
|
24
24
|
- 🔀 **Forge-Aware Safety** - MR/PR and CI state via `glab`/`gh`; squash- and rebase-merged branches count as merged instead of blocking deletion forever
|
|
25
|
-
- 🗂️ **Epics** - Group related tasks under an epic: a foldable row with rolled-up dirty and Claude state, `E` to attach tasks, and an epic log
|
|
25
|
+
- 🗂️ **Epics** - Group related tasks under an epic: a foldable row with rolled-up dirty and Claude state, `E` to attach tasks, and an epic log and `epic ask` so the Claude sessions of one epic share what they know
|
|
26
|
+
- 🧷 **zellij Tabs** - Run the TUI inside zellij (or set `zellij_autostart`) and `o`/`e`/`c` open zellij tabs that keep running across a terminal restart; pressing the key again jumps to the open tab ([details](docs/user-guide.md#zellij))
|
|
26
27
|
- 📦 **Finish Flow with Archives** - Ending a task saves its combined diff (committed-but-unmerged + uncommitted) and the task-folder files outside the worktrees (plans, ADRs, notes) to an archive before deleting
|
|
27
28
|
|
|
28
29
|
## 📊 Status Indicators
|
|
@@ -76,63 +77,93 @@ For detailed workflows and examples, see the [User Guide](docs/user-guide.md).
|
|
|
76
77
|
|
|
77
78
|
### Headless CLI
|
|
78
79
|
|
|
79
|
-
Running `tasktree-manager` with arguments skips the TUI
|
|
80
|
-
|
|
80
|
+
Running `tasktree-manager` with arguments skips the TUI. Use it from scripts and AI agents,
|
|
81
|
+
for example a skill that creates a Jira ticket and then the matching task.
|
|
82
|
+
|
|
83
|
+
#### Tasks
|
|
81
84
|
|
|
82
85
|
```bash
|
|
83
|
-
tasktree-manager create DIC-1901-argocd-tls --repos backend,frontend # --base
|
|
84
|
-
tasktree-manager list --json # tasks with repos and state: clean / dirty / error (plain text without --json)
|
|
85
|
-
tasktree-manager repos # available repos in REPOS_DIR
|
|
86
|
+
tasktree-manager create DIC-1901-argocd-tls --repos backend,frontend # --base sets the base branch
|
|
86
87
|
tasktree-manager add-repo DIC-1901-argocd-tls infra
|
|
87
|
-
tasktree-manager
|
|
88
|
-
tasktree-manager
|
|
89
|
-
tasktree-manager
|
|
88
|
+
tasktree-manager list --json # tasks, repos and state: clean / dirty / error
|
|
89
|
+
tasktree-manager repos # repos available in REPOS_DIR
|
|
90
|
+
tasktree-manager status # task of the current folder; --json, --oneline, --forge
|
|
91
|
+
tasktree-manager finish DIC-1901-argocd-tls # safety check, archive, delete; --push, --no-archive
|
|
92
|
+
tasktree-manager delete DIC-1901-argocd-tls # archive, delete; refuses unfinished work
|
|
90
93
|
```
|
|
91
94
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
+
`status --oneline` prints a compact `TASK repoA✓ repoB●2↑1` line for a Claude Code
|
|
96
|
+
statusline or a shell prompt.
|
|
97
|
+
|
|
98
|
+
#### Epics
|
|
99
|
+
|
|
100
|
+
An epic groups related tasks, for example a Jira epic and its child tasks. It is a task
|
|
101
|
+
folder too, so it can hold notes, a Claude session and worktrees. Tasks stay in their own
|
|
102
|
+
folders; a marker file names their epic. Epics don't nest.
|
|
95
103
|
|
|
96
104
|
```bash
|
|
97
|
-
tasktree-manager epic create DIC-2466-pcaps-epic
|
|
105
|
+
tasktree-manager epic create DIC-2466-pcaps-epic # repos are optional for an epic
|
|
98
106
|
tasktree-manager create DIC-2861-pcaps-logs --repos infra --epic DIC-2466-pcaps-epic
|
|
99
|
-
tasktree-manager epic add DIC-2466-pcaps-epic DIC-2862-pcaps-s3
|
|
100
|
-
tasktree-manager epic remove DIC-2862-pcaps-s3
|
|
101
|
-
tasktree-manager epic mark DIC-2466-pcaps-epic
|
|
102
|
-
tasktree-manager epic list
|
|
103
|
-
tasktree-manager epic note "chose layout A for the S3 keys" # add a note to this task's file in the epic log
|
|
104
|
-
tasktree-manager epic log # notes and latest session recap of every task in the epic
|
|
105
|
-
tasktree-manager epic log DIC-2862-pcaps-s3 --json # one task (or a whole epic by its name), as JSON
|
|
106
|
-
tasktree-manager epic sync # refresh the CLAUDE.md epic block after an upgrade
|
|
107
|
+
tasktree-manager epic add DIC-2466-pcaps-epic DIC-2862-pcaps-s3 # attach or move tasks
|
|
108
|
+
tasktree-manager epic remove DIC-2862-pcaps-s3 # detach
|
|
109
|
+
tasktree-manager epic mark DIC-2466-pcaps-epic # make an existing task an epic; unmark reverts
|
|
110
|
+
tasktree-manager epic list # epics and their tasks; --json
|
|
107
111
|
```
|
|
108
112
|
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
`epic`
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
-
|
|
129
|
-
|
|
130
|
-
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
113
|
+
`list --json` and `status --json` show each task's `kind` (`task` or `epic`) and its `epic`.
|
|
114
|
+
`delete` and `finish` refuse an epic that still has tasks, even with `--force`.
|
|
115
|
+
|
|
116
|
+
#### Sharing context inside an epic
|
|
117
|
+
|
|
118
|
+
The Claude sessions of one epic can learn from each other:
|
|
119
|
+
|
|
120
|
+
| Command | What it does |
|
|
121
|
+
| --- | --- |
|
|
122
|
+
| `epic note "text"` | Adds a note to this task's file in the epic log (`-` reads stdin) |
|
|
123
|
+
| `epic log [TASK]` | Shows each task's notes and the recap of its latest Claude session; `--json` |
|
|
124
|
+
| `epic ask TASK "question"` | A read-only copy of that task's latest session answers |
|
|
125
|
+
| `epic sync` | Refreshes the epic block in existing tasks' `CLAUDE.md` after an upgrade |
|
|
126
|
+
|
|
127
|
+
Each task's `CLAUDE.md` gets a managed block that explains these commands to its session.
|
|
128
|
+
|
|
129
|
+
- **Scope:** inside a task folder, the commands reach only that task's epic.
|
|
130
|
+
- **Running sessions:** `epic ask` exits with code 3 when the task's session is running and
|
|
131
|
+
prints its name; the asking session then sends it a message with SendMessage.
|
|
132
|
+
- **Read-only:** the copy that answers can read files but not change them, can't read
|
|
133
|
+
credential files, and leaves the asked task's session untouched.
|
|
134
|
+
- **Cost:** each turn of the copy is a model call on that session's context, 8 turns at
|
|
135
|
+
most (`--max-turns`); `--model sonnet` makes it cheaper.
|
|
136
|
+
|
|
137
|
+
The [User Guide](docs/user-guide.md#epics) has the details.
|
|
138
|
+
|
|
139
|
+
#### Exit codes
|
|
140
|
+
|
|
141
|
+
| Code | Meaning |
|
|
142
|
+
| --- | --- |
|
|
143
|
+
| 0 | Success |
|
|
144
|
+
| 1 | Failure; the reason is on stderr |
|
|
145
|
+
| 3 | `epic ask` only: the task's session is running; its name is on stdout |
|
|
146
|
+
|
|
147
|
+
#### Safe delete and archive
|
|
148
|
+
|
|
149
|
+
`delete` and `finish` run the same safety check as the TUI: uncommitted, unpushed or
|
|
150
|
+
unmerged work blocks deletion unless `--force`. With `glab` or `gh` installed, squash and
|
|
151
|
+
rebase merges count as merged.
|
|
152
|
+
|
|
153
|
+
Before deleting, the CLI archives the task's remaining diff as a patch and copies the files
|
|
154
|
+
in the task folder outside the worktrees to `<task>-<timestamp>.files/` next to it
|
|
155
|
+
(`finish --no-archive` skips both):
|
|
156
|
+
|
|
157
|
+
- **Skipped:** hidden files, symlinks, `node_modules`, `vendor` and `.terraform` folders,
|
|
158
|
+
and an unedited generated `CLAUDE.md`.
|
|
159
|
+
- **Left out with a warning:** key material (`*.pem`, `*.key`, `id_rsa`, kubeconfigs,
|
|
160
|
+
`*.tfstate`, `credentials*.json`), files over 10 MB, and files past 100 MB in total.
|
|
161
|
+
- **Always stops the delete:** a diff that cannot be archived; the CLI prints the partial
|
|
162
|
+
archive's path.
|
|
163
|
+
- **Stops the delete unless `--force`:** a task file that cannot be read or copied.
|
|
164
|
+
|
|
165
|
+
In both cases the TUI stops too, names what was left out in the messages panel, and asks
|
|
166
|
+
again before it deletes.
|
|
136
167
|
|
|
137
168
|
## 📖 Documentation
|
|
138
169
|
|
|
@@ -218,8 +249,9 @@ Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
|
218
249
|
- Git 2.0+
|
|
219
250
|
- 256-color terminal
|
|
220
251
|
- Unix-like OS (macOS, Linux, WSL2). Opening a folder, editor or Claude session in a
|
|
221
|
-
new terminal tab (`o`, `e`, `c`)
|
|
222
|
-
|
|
252
|
+
new terminal tab (`o`, `e`, `c`) opens a zellij tab when the TUI runs inside zellij,
|
|
253
|
+
on any OS. Otherwise it drives Ghostty via AppleScript and is macOS-only; elsewhere
|
|
254
|
+
those keys show a notice
|
|
223
255
|
|
|
224
256
|
See [Installation Guide](docs/installation.md) for detailed requirements and setup.
|
|
225
257
|
|
|
@@ -210,6 +210,14 @@ glab_path = "glab"
|
|
|
210
210
|
# Default: "gh" (searches PATH)
|
|
211
211
|
gh_path = "gh"
|
|
212
212
|
|
|
213
|
+
# zellij: o/e/c open zellij tabs whenever the TUI runs inside zellij. With
|
|
214
|
+
# autostart, a TUI started outside zellij re-launches itself inside session
|
|
215
|
+
# zellij_session, so its tabs survive a terminal restart (see the user guide).
|
|
216
|
+
# Defaults: "zellij", false, "tasktree" (letters, digits, '.', '_', '-')
|
|
217
|
+
zellij_path = "zellij"
|
|
218
|
+
zellij_autostart = false
|
|
219
|
+
zellij_session = "tasktree"
|
|
220
|
+
|
|
213
221
|
# ============================================================================
|
|
214
222
|
# Forge (MR/PR state via glab/gh)
|
|
215
223
|
# ============================================================================
|
|
@@ -419,6 +427,9 @@ refresh_interval = 15 # Refresh every 15 seconds
|
|
|
419
427
|
| `hunk_path` | string | `"hunk"` | - | Path to hunk diff-viewer executable |
|
|
420
428
|
| `glab_path` | string | `"glab"` | - | Path to GitLab CLI (MR/CI status) |
|
|
421
429
|
| `gh_path` | string | `"gh"` | - | Path to GitHub CLI (PR/CI status) |
|
|
430
|
+
| `zellij_path` | string | `"zellij"` | - | Path to zellij (tabs and autostart) |
|
|
431
|
+
| `zellij_autostart` | bool | `false` | - | Re-launch the TUI inside zellij |
|
|
432
|
+
| `zellij_session` | string | `"tasktree"` | - | zellij session for autostart |
|
|
422
433
|
|
|
423
434
|
## Forge Settings
|
|
424
435
|
|
|
@@ -85,26 +85,50 @@ names their epic, so nothing moves on disk.
|
|
|
85
85
|
- `enter` or `space` folds an epic. A folded epic row still shows the dirty
|
|
86
86
|
count and the most urgent Claude state of its tasks.
|
|
87
87
|
- Epics don't nest. An epic that still has tasks can't be deleted.
|
|
88
|
-
- Each task's `CLAUDE.md` gets a short block between `<!-- tasktree:epic -->` markers
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
88
|
+
- Each task's `CLAUDE.md` gets a short block between `<!-- tasktree:epic -->` markers.
|
|
89
|
+
It names the epic folder, explains how to find sibling tasks and how to share context
|
|
90
|
+
with them. It updates on every epic change; text outside the markers is never touched.
|
|
91
|
+
- From scripts: `tasktree-manager epic create/add/remove/mark/unmark/list/note/log/ask/sync`.
|
|
92
|
+
|
|
93
|
+
#### Sharing context between sessions
|
|
94
|
+
|
|
95
|
+
The Claude sessions of one epic can learn from each other. The `CLAUDE.md` block tells
|
|
96
|
+
each session to try these in order:
|
|
97
|
+
|
|
98
|
+
1. **Read the epic log.** `tasktree-manager epic log` shows every task's notes and the
|
|
99
|
+
recap of its latest Claude session. `epic log TASK` shows one task.
|
|
100
|
+
2. **Ask the task.** `tasktree-manager epic ask TASK "question"` resumes a read-only copy
|
|
101
|
+
of that task's latest session, which answers the question.
|
|
102
|
+
3. **Message a running session.** If the task's session is running, `epic ask` exits
|
|
103
|
+
with code 3 and prints the session name. The asking session sends it a message with
|
|
104
|
+
SendMessage instead. `--fork` asks a copy anyway.
|
|
105
|
+
|
|
106
|
+
Sessions add to the log with `tasktree-manager epic note "..."`: decisions, interfaces,
|
|
107
|
+
open questions, finished work that other tasks depend on.
|
|
108
|
+
|
|
109
|
+
**Notes:**
|
|
110
|
+
|
|
111
|
+
- Notes go to `epic-log/<task>.md` in the epic folder, one file per task.
|
|
99
112
|
- A session writes only its own task's notes. From a terminal outside any task,
|
|
100
113
|
`epic note --task NAME` writes for a task and marks the entry as written outside it.
|
|
101
|
-
- Notes stay
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
114
|
+
- Notes stay after their task is finished, moved or deleted; `epic log` lists them as
|
|
115
|
+
"no longer in the epic".
|
|
116
|
+
- A note is at most 16 KB. `epic log` shows the newest 64 KB of each task's notes.
|
|
117
|
+
- Notes and answers come from other sessions: they are information, not instructions.
|
|
118
|
+
|
|
119
|
+
**`epic ask`:**
|
|
120
|
+
|
|
121
|
+
- Only tasks of the same epic and the epic folder can be asked. A session in a task
|
|
122
|
+
outside any epic cannot ask.
|
|
123
|
+
- The copy can read files but not change them. It can't read credential files (forge CLI
|
|
124
|
+
tokens, `.env` files anywhere, the key material the archive leaves out).
|
|
125
|
+
Nothing is saved in the asked task, and its session stays untouched.
|
|
126
|
+
- Each turn of the copy is a model call on the size of that session's context, 8 turns
|
|
127
|
+
at most (`--max-turns`). `--model sonnet` makes it cheaper.
|
|
128
|
+
|
|
129
|
+
**After an upgrade:** run `tasktree-manager epic sync` to refresh the block in existing
|
|
130
|
+
tasks. The TUI also refreshes it when it starts a Claude session. Folders without a
|
|
131
|
+
`CLAUDE.md` yet are counted and skipped.
|
|
108
132
|
|
|
109
133
|
### Worktrees
|
|
110
134
|
|
|
@@ -277,6 +301,8 @@ terraform edits sit unstaged. Next, decide whether to hand-create the group.
|
|
|
277
301
|
- **Title**: the session name (`/rename`), else Claude's own title, else the session slug
|
|
278
302
|
- **Turn line**: duration of the last turn and when it finished; `busy`/`idle` mirrors the task's Claude status indicator
|
|
279
303
|
- **Recap**: the summary Claude writes a few minutes after a turn when the session idles. Until one exists, the dim `last prompt:` line shows what was asked last
|
|
304
|
+
- The session is the newest one started in the task folder or one of its worktrees, as in
|
|
305
|
+
`epic log`. Headless `claude -p` runs, such as commit-message helpers, are skipped
|
|
280
306
|
- Nothing is shown for tasks without a session. The block refreshes as you move the cursor and every 5 seconds while a transcript changes. Disable with `claude_recap = false` under `[tools]` in `config.toml`
|
|
281
307
|
|
|
282
308
|
**Git status codes:**
|
|
@@ -430,7 +456,7 @@ Useful when you're spinning up several similar tasks that share the same set of
|
|
|
430
456
|
| `b` | Dispatch agent | Run a background Claude agent (`claude --bg`) in the selected worktree |
|
|
431
457
|
|
|
432
458
|
**How it works:**
|
|
433
|
-
- `c` opens Claude Code CLI in a new
|
|
459
|
+
- `c` opens Claude Code CLI in a new terminal tab at the task directory (a zellij tab inside zellij, see [zellij](#zellij)).
|
|
434
460
|
- If `~/.claude/projects/<task-folder>/` already has session transcripts, runs `claude -r` to pick from them; otherwise runs `claude` to start fresh.
|
|
435
461
|
- `C` opens the Claude desktop app via the `claude://code/new?folder=<task-folder>` URL scheme.
|
|
436
462
|
- The CLI variant (`c`) generates a task-level `CLAUDE.md` with task/worktree context, copies each repo's own `CLAUDE.md` into worktrees whose branch predates it (never generating stub content), and installs hooks that report session status back to tasktree-manager.
|
|
@@ -831,9 +857,9 @@ npm i -g hunkdiff
|
|
|
831
857
|
|
|
832
858
|
**Direct editor integration:**
|
|
833
859
|
1. Highlight task or worktree
|
|
834
|
-
2. Press `e` to open your configured editor in a new
|
|
835
|
-
3. tasktree-manager keeps running alongside the editor (
|
|
836
|
-
|
|
860
|
+
2. Press `e` to open your configured editor in a new terminal tab (`$EDITOR .`)
|
|
861
|
+
3. tasktree-manager keeps running alongside the editor (a zellij tab inside zellij,
|
|
862
|
+
otherwise a Ghostty tab on macOS; see [zellij](#zellij))
|
|
837
863
|
|
|
838
864
|
**Configure your editor** in `~/.config/tasktree-manager/config.toml`:
|
|
839
865
|
```toml
|
|
@@ -864,6 +890,47 @@ code ~/tasks/FEAT-123 # Open entire task as workspace
|
|
|
864
890
|
- Use "Open Folder" or equivalent
|
|
865
891
|
- Git integration works normally
|
|
866
892
|
|
|
893
|
+
### zellij
|
|
894
|
+
|
|
895
|
+
`o`, `e` and `c` open a new terminal tab. Where the tab lives depends on where
|
|
896
|
+
tasktree-manager runs:
|
|
897
|
+
|
|
898
|
+
- Inside a zellij session (`ZELLIJ_SESSION_NAME` is set), each key opens a zellij tab
|
|
899
|
+
named after the folder and what runs in it: `TASK · shell`, `TASK/repo · editor`,
|
|
900
|
+
`TASK · claude`. The tab runs in the zellij server, so it keeps running when you close
|
|
901
|
+
or restart the terminal. Pressing the key again while that tab is open switches to it
|
|
902
|
+
instead of opening a second one.
|
|
903
|
+
- Anywhere else, each key opens a Ghostty tab via AppleScript (macOS only).
|
|
904
|
+
|
|
905
|
+
To run the TUI in zellij every time, set this in `config.toml`:
|
|
906
|
+
|
|
907
|
+
```toml
|
|
908
|
+
[tools]
|
|
909
|
+
zellij_autostart = true
|
|
910
|
+
zellij_session = "tasktree" # the default
|
|
911
|
+
```
|
|
912
|
+
|
|
913
|
+
Plain `tasktree-manager` then re-launches itself as
|
|
914
|
+
`zellij attach -c tasktree -- python -m tasktree_manager.app`. Without the setting, start
|
|
915
|
+
it that way yourself: `zellij attach -c tasktree -- tasktree-manager`.
|
|
916
|
+
|
|
917
|
+
After a terminal restart, run `tasktree-manager` (with autostart) or
|
|
918
|
+
`zellij attach tasktree`. Either brings back the TUI and every tab it opened, Claude
|
|
919
|
+
sessions included. The command after `--` runs only when the session is created, so a
|
|
920
|
+
second `tasktree-manager` in another terminal tab shows the same session.
|
|
921
|
+
|
|
922
|
+
- A tab that runs a command (`e`, `c`) closes when the command exits.
|
|
923
|
+
- The zellij tab runs the command with `sh -c`, so `editor` and `claude_path` must name
|
|
924
|
+
programs on `PATH`. A shell alias or fish function works only in the Ghostty tab.
|
|
925
|
+
- A zellij session does not survive a reboot. Attaching afterwards (or autostart) makes
|
|
926
|
+
zellij resurrect the saved layout, and each tab waits for ENTER before its command runs
|
|
927
|
+
again; tasktree-manager does not test that path.
|
|
928
|
+
- Autostart applies only when the TUI starts in a terminal outside zellij, never to a
|
|
929
|
+
piped run or to the headless CLI.
|
|
930
|
+
- zellij's default keybindings take Ctrl+P, Ctrl+T, Ctrl+O and other keys before the TUI
|
|
931
|
+
or Claude Code sees them. Pick zellij's "Unlock First (non-colliding)" preset or Alt-based
|
|
932
|
+
bindings, so Ctrl+P still opens the command palette.
|
|
933
|
+
|
|
867
934
|
### CI/CD
|
|
868
935
|
|
|
869
936
|
tasktree-manager creates normal git branches, so CI/CD works seamlessly:
|
|
@@ -71,7 +71,7 @@ version-file = "tasktree_manager/_version.py"
|
|
|
71
71
|
# Semantic Release Configuration
|
|
72
72
|
[tool.semantic_release]
|
|
73
73
|
version_toml = ["pyproject.toml:tool.semantic_release.version"]
|
|
74
|
-
version = "2.
|
|
74
|
+
version = "2.19.0"
|
|
75
75
|
tag_format = "v{version}"
|
|
76
76
|
branch = "main"
|
|
77
77
|
commit_message = "chore(release): {version} [skip ci]"
|
|
@@ -18,7 +18,7 @@ version_tuple: tuple[int | str, ...]
|
|
|
18
18
|
commit_id: str | None
|
|
19
19
|
__commit_id__: str | None
|
|
20
20
|
|
|
21
|
-
__version__ = version = '2.
|
|
22
|
-
__version_tuple__ = version_tuple = (2,
|
|
21
|
+
__version__ = version = '2.19.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 19, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|