tasktree-manager 2.18.0__tar.gz → 2.20.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.18.0 → tasktree_manager-2.20.0}/CHANGELOG.md +15 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/PKG-INFO +1 -1
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/README.md +83 -58
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/docs/configuration.md +21 -1
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/docs/user-guide.md +120 -33
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/pyproject.toml +1 -1
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/_version.py +2 -2
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/app.py +431 -45
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/cli.py +66 -21
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/commands.py +5 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/agent_sessions.py +40 -15
- tasktree_manager-2.20.0/tasktree_manager/services/claude_bg.py +138 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/claude_sessions.py +26 -22
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/config.py +34 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/epic_ask.py +26 -22
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/git_ops.py +1 -1
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/models.py +4 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/task_manager.py +37 -9
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/create_modal.py +6 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/conftest.py +14 -1
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_agent_sessions.py +20 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_app.py +1 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_app_review_fixes.py +45 -6
- tasktree_manager-2.20.0/tests/test_claude_bg.py +533 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_epic_ask.py +6 -4
- tasktree_manager-2.20.0/tests/test_review_findings.py +208 -0
- tasktree_manager-2.20.0/tests/test_terminal_tabs.py +225 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/SKILL.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/assets/README.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/assets/dashboard_app.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/assets/data_viewer.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/assets/todo_app.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/assets/worker_demo.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/references/layouts.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/references/official-guides-index.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/references/styling.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.claude/skills/textual-tui/references/widgets.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.github/templates/CHANGELOG.md.j2 +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.github/workflows/ci.yml +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.github/workflows/release.yml +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/.gitignore +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/CONTRIBUTING.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/LICENSE +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/ROADMAP.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/docs/claude-code-integration-spec.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/docs/installation.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/docs/troubleshooting.md +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/mise.toml +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/scripts/bump_version.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/__init__.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/__init__.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/claude_hooks.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/epic_log.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/services/forge.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/themes.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/__init__.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/app_header.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/messages_panel.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/setup_modal.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/status_panel.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/task_list.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tasktree_manager/widgets/worktree_list.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/__init__.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_agent_sessions_decode.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_bump_version.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_claude_hooks.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_claude_sessions.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_cli.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_commands.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_config.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_epic_claude_md.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_epic_log.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_epic_tui.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_epics.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_forge.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_git_ops.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_integration_git.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_list_selection.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_medium_fixes.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_memory.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_messages_panel.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_modals.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_safety_fixes.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_setup_modal.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_status_panel.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.0}/tests/test_task_manager.py +0 -0
- {tasktree_manager-2.18.0 → tasktree_manager-2.20.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.20.0] - 2026-10-29
|
|
19
|
+
|
|
20
|
+
### Added
|
|
21
|
+
- Keep Claude running in the background when its tab closes (#17)
|
|
22
|
+
|
|
23
|
+
|
|
24
|
+
## [2.19.0] - 2026-10-29
|
|
25
|
+
|
|
26
|
+
### Added
|
|
27
|
+
- Open zellij tabs that survive a terminal restart, and review fixes (#16)
|
|
28
|
+
|
|
29
|
+
### Changed
|
|
30
|
+
- Split the headless CLI and epic sections into short parts (#15)
|
|
31
|
+
|
|
32
|
+
|
|
18
33
|
## [2.18.0] - 2026-10-20
|
|
19
34
|
|
|
20
35
|
### Added
|
|
@@ -23,6 +23,8 @@
|
|
|
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
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))
|
|
27
|
+
- 💤 **Background Claude** - `c` runs Claude as a background session and the tab only shows it: close the tab (`x`) and Claude keeps working, press `c` to come back to the same conversation
|
|
26
28
|
- 📦 **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
29
|
|
|
28
30
|
## 📊 Status Indicators
|
|
@@ -76,72 +78,93 @@ For detailed workflows and examples, see the [User Guide](docs/user-guide.md).
|
|
|
76
78
|
|
|
77
79
|
### Headless CLI
|
|
78
80
|
|
|
79
|
-
Running `tasktree-manager` with arguments skips the TUI
|
|
80
|
-
|
|
81
|
+
Running `tasktree-manager` with arguments skips the TUI. Use it from scripts and AI agents,
|
|
82
|
+
for example a skill that creates a Jira ticket and then the matching task.
|
|
83
|
+
|
|
84
|
+
#### Tasks
|
|
81
85
|
|
|
82
86
|
```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
|
|
87
|
+
tasktree-manager create DIC-1901-argocd-tls --repos backend,frontend # --base sets the base branch
|
|
86
88
|
tasktree-manager add-repo DIC-1901-argocd-tls infra
|
|
87
|
-
tasktree-manager
|
|
88
|
-
tasktree-manager
|
|
89
|
-
tasktree-manager
|
|
89
|
+
tasktree-manager list --json # tasks, repos and state: clean / dirty / error
|
|
90
|
+
tasktree-manager repos # repos available in REPOS_DIR
|
|
91
|
+
tasktree-manager status # task of the current folder; --json, --oneline, --forge
|
|
92
|
+
tasktree-manager finish DIC-1901-argocd-tls # safety check, archive, delete; --push, --no-archive
|
|
93
|
+
tasktree-manager delete DIC-1901-argocd-tls # archive, delete; refuses unfinished work
|
|
90
94
|
```
|
|
91
95
|
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
96
|
+
`status --oneline` prints a compact `TASK repoA✓ repoB●2↑1` line for a Claude Code
|
|
97
|
+
statusline or a shell prompt.
|
|
98
|
+
|
|
99
|
+
#### Epics
|
|
100
|
+
|
|
101
|
+
An epic groups related tasks, for example a Jira epic and its child tasks. It is a task
|
|
102
|
+
folder too, so it can hold notes, a Claude session and worktrees. Tasks stay in their own
|
|
103
|
+
folders; a marker file names their epic. Epics don't nest.
|
|
95
104
|
|
|
96
105
|
```bash
|
|
97
|
-
tasktree-manager epic create DIC-2466-pcaps-epic
|
|
106
|
+
tasktree-manager epic create DIC-2466-pcaps-epic # repos are optional for an epic
|
|
98
107
|
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 ask DIC-2862-pcaps-s3 "which bucket?" # a read-only copy of that task's latest session answers
|
|
107
|
-
tasktree-manager epic sync # refresh the CLAUDE.md epic block after an upgrade
|
|
108
|
+
tasktree-manager epic add DIC-2466-pcaps-epic DIC-2862-pcaps-s3 # attach or move tasks
|
|
109
|
+
tasktree-manager epic remove DIC-2862-pcaps-s3 # detach
|
|
110
|
+
tasktree-manager epic mark DIC-2466-pcaps-epic # make an existing task an epic; unmark reverts
|
|
111
|
+
tasktree-manager epic list # epics and their tasks; --json
|
|
108
112
|
```
|
|
109
113
|
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
task's
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
114
|
+
`list --json` and `status --json` show each task's `kind` (`task` or `epic`) and its `epic`.
|
|
115
|
+
`delete` and `finish` refuse an epic that still has tasks, even with `--force`.
|
|
116
|
+
|
|
117
|
+
#### Sharing context inside an epic
|
|
118
|
+
|
|
119
|
+
The Claude sessions of one epic can learn from each other:
|
|
120
|
+
|
|
121
|
+
| Command | What it does |
|
|
122
|
+
| --- | --- |
|
|
123
|
+
| `epic note "text"` | Adds a note to this task's file in the epic log (`-` reads stdin) |
|
|
124
|
+
| `epic log [TASK]` | Shows each task's notes and the recap of its latest Claude session; `--json` |
|
|
125
|
+
| `epic ask TASK "question"` | A read-only copy of that task's latest session answers |
|
|
126
|
+
| `epic sync` | Refreshes the epic block in existing tasks' `CLAUDE.md` after an upgrade |
|
|
127
|
+
|
|
128
|
+
Each task's `CLAUDE.md` gets a managed block that explains these commands to its session.
|
|
129
|
+
|
|
130
|
+
- **Scope:** inside a task folder, the commands reach only that task's epic.
|
|
131
|
+
- **Running sessions:** `epic ask` exits with code 3 when the task's session is running and
|
|
132
|
+
prints its name; the asking session then sends it a message with SendMessage.
|
|
133
|
+
- **Read-only:** the copy that answers can read files but not change them, can't read
|
|
134
|
+
credential files, and leaves the asked task's session untouched.
|
|
135
|
+
- **Cost:** each turn of the copy is a model call on that session's context, 8 turns at
|
|
136
|
+
most (`--max-turns`); `--model sonnet` makes it cheaper.
|
|
137
|
+
|
|
138
|
+
The [User Guide](docs/user-guide.md#epics) has the details.
|
|
139
|
+
|
|
140
|
+
#### Exit codes
|
|
141
|
+
|
|
142
|
+
| Code | Meaning |
|
|
143
|
+
| --- | --- |
|
|
144
|
+
| 0 | Success |
|
|
145
|
+
| 1 | Failure; the reason is on stderr |
|
|
146
|
+
| 3 | `epic ask` only: the task's session is running; its name is on stdout |
|
|
147
|
+
|
|
148
|
+
#### Safe delete and archive
|
|
149
|
+
|
|
150
|
+
`delete` and `finish` run the same safety check as the TUI: uncommitted, unpushed or
|
|
151
|
+
unmerged work blocks deletion unless `--force`. With `glab` or `gh` installed, squash and
|
|
152
|
+
rebase merges count as merged.
|
|
153
|
+
|
|
154
|
+
Before deleting, the CLI archives the task's remaining diff as a patch and copies the files
|
|
155
|
+
in the task folder outside the worktrees to `<task>-<timestamp>.files/` next to it
|
|
156
|
+
(`finish --no-archive` skips both):
|
|
157
|
+
|
|
158
|
+
- **Skipped:** hidden files, symlinks, `node_modules`, `vendor` and `.terraform` folders,
|
|
159
|
+
and an unedited generated `CLAUDE.md`.
|
|
160
|
+
- **Left out with a warning:** key material (`*.pem`, `*.key`, `id_rsa`, kubeconfigs,
|
|
161
|
+
`*.tfstate`, `credentials*.json`), files over 10 MB, and files past 100 MB in total.
|
|
162
|
+
- **Always stops the delete:** a diff that cannot be archived; the CLI prints the partial
|
|
163
|
+
archive's path.
|
|
164
|
+
- **Stops the delete unless `--force`:** a task file that cannot be read or copied.
|
|
165
|
+
|
|
166
|
+
In both cases the TUI stops too, names what was left out in the messages panel, and asks
|
|
167
|
+
again before it deletes.
|
|
145
168
|
|
|
146
169
|
## 📖 Documentation
|
|
147
170
|
|
|
@@ -161,6 +184,7 @@ a Claude Code statusline or shell prompt.
|
|
|
161
184
|
| `p` | Push all | `o` | Open folder |
|
|
162
185
|
| `P` | Pull all | `y` | Clone task |
|
|
163
186
|
| `c` | Claude (resume) | `C` | Claude (new) |
|
|
187
|
+
| `x` | Close Claude tab | | |
|
|
164
188
|
| `b` | Dispatch agent | `D` | Delete worktree |
|
|
165
189
|
| `r` | Refresh | `s` | Sort tasks |
|
|
166
190
|
| `S` | Group worktrees | `m` | Messages |
|
|
@@ -227,8 +251,9 @@ Contributions welcome! See [CONTRIBUTING.md](CONTRIBUTING.md) for guidelines.
|
|
|
227
251
|
- Git 2.0+
|
|
228
252
|
- 256-color terminal
|
|
229
253
|
- Unix-like OS (macOS, Linux, WSL2). Opening a folder, editor or Claude session in a
|
|
230
|
-
new terminal tab (`o`, `e`, `c`)
|
|
231
|
-
|
|
254
|
+
new terminal tab (`o`, `e`, `c`) opens a zellij tab when the TUI runs inside zellij,
|
|
255
|
+
on any OS. Otherwise it drives Ghostty via AppleScript and is macOS-only; elsewhere
|
|
256
|
+
those keys show a notice
|
|
232
257
|
|
|
233
258
|
See [Installation Guide](docs/installation.md) for detailed requirements and setup.
|
|
234
259
|
|
|
@@ -202,6 +202,12 @@ claude_repo_memory = true
|
|
|
202
202
|
# Default: true
|
|
203
203
|
claude_recap = true
|
|
204
204
|
|
|
205
|
+
# Run the `c` key's Claude as a background session (`claude --bg`) and show it
|
|
206
|
+
# in a tab running `claude attach`: closing the tab leaves Claude working, and
|
|
207
|
+
# `c` again reopens the same conversation. false runs Claude inside the tab.
|
|
208
|
+
# Default: true
|
|
209
|
+
claude_background = true
|
|
210
|
+
|
|
205
211
|
# Path to glab executable (GitLab CLI, used for MR/CI status)
|
|
206
212
|
# Default: "glab" (searches PATH)
|
|
207
213
|
glab_path = "glab"
|
|
@@ -210,6 +216,14 @@ glab_path = "glab"
|
|
|
210
216
|
# Default: "gh" (searches PATH)
|
|
211
217
|
gh_path = "gh"
|
|
212
218
|
|
|
219
|
+
# zellij: o/e/c open zellij tabs whenever the TUI runs inside zellij. With
|
|
220
|
+
# autostart, a TUI started outside zellij re-launches itself inside session
|
|
221
|
+
# zellij_session, so its tabs survive a terminal restart (see the user guide).
|
|
222
|
+
# Defaults: "zellij", false, "tasktree" (letters, digits, '.', '_', '-')
|
|
223
|
+
zellij_path = "zellij"
|
|
224
|
+
zellij_autostart = false
|
|
225
|
+
zellij_session = "tasktree"
|
|
226
|
+
|
|
213
227
|
# ============================================================================
|
|
214
228
|
# Forge (MR/PR state via glab/gh)
|
|
215
229
|
# ============================================================================
|
|
@@ -260,6 +274,7 @@ refresh = "r" # Refresh git status
|
|
|
260
274
|
|
|
261
275
|
# Claude Code integration
|
|
262
276
|
open_claude_resume = "c" # Open Claude CLI (resume if a session exists, else new)
|
|
277
|
+
close_claude_tab = "x" # Close the Claude tab (zellij); Claude keeps running
|
|
263
278
|
open_claude_gui_code = "C" # Open Claude desktop on Code page in task folder (shift+c)
|
|
264
279
|
dispatch_agent = "b" # Dispatch background Claude agent in selected worktree
|
|
265
280
|
|
|
@@ -419,6 +434,10 @@ refresh_interval = 15 # Refresh every 15 seconds
|
|
|
419
434
|
| `hunk_path` | string | `"hunk"` | - | Path to hunk diff-viewer executable |
|
|
420
435
|
| `glab_path` | string | `"glab"` | - | Path to GitLab CLI (MR/CI status) |
|
|
421
436
|
| `gh_path` | string | `"gh"` | - | Path to GitHub CLI (PR/CI status) |
|
|
437
|
+
| `claude_background` | bool | `true` | - | `c` runs Claude in the background |
|
|
438
|
+
| `zellij_path` | string | `"zellij"` | - | Path to zellij (tabs and autostart) |
|
|
439
|
+
| `zellij_autostart` | bool | `false` | - | Re-launch the TUI inside zellij |
|
|
440
|
+
| `zellij_session` | string | `"tasktree"` | - | zellij session for autostart |
|
|
422
441
|
|
|
423
442
|
## Forge Settings
|
|
424
443
|
|
|
@@ -593,7 +612,7 @@ blocklist = ["*"]
|
|
|
593
612
|
|
|
594
613
|
## Keybindings Reference
|
|
595
614
|
|
|
596
|
-
All
|
|
615
|
+
All 28 customizable keybindings with descriptions:
|
|
597
616
|
|
|
598
617
|
### Application Control
|
|
599
618
|
|
|
@@ -631,6 +650,7 @@ All 27 customizable keybindings with descriptions:
|
|
|
631
650
|
| Action | Default | Description | Customization Example |
|
|
632
651
|
|-----------------------|---------|------------------------------------------------------|--------------------------------------|
|
|
633
652
|
| `open_claude_resume` | `c` | Open Claude CLI (resume if session exists, else new) | `open_claude_resume = "ctrl+c"` |
|
|
653
|
+
| `close_claude_tab` | `x` | Close the Claude tab (zellij); Claude keeps running | `close_claude_tab = "ctrl+x"` |
|
|
634
654
|
| `open_claude_gui_code`| `C` | Open Claude desktop on Code page in task folder | `open_claude_gui_code = "ctrl+shift+c"` |
|
|
635
655
|
| `toggle_messages` | `m` | Show/hide activity messages panel | `toggle_messages = "ctrl+m"` |
|
|
636
656
|
| `dispatch_agent` | `b` | Dispatch a background Claude agent into the worktree | `dispatch_agent = "ctrl+b"` |
|
|
@@ -85,35 +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
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
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.
|
|
117
132
|
|
|
118
133
|
### Worktrees
|
|
119
134
|
|
|
@@ -286,6 +301,8 @@ terraform edits sit unstaged. Next, decide whether to hand-create the group.
|
|
|
286
301
|
- **Title**: the session name (`/rename`), else Claude's own title, else the session slug
|
|
287
302
|
- **Turn line**: duration of the last turn and when it finished; `busy`/`idle` mirrors the task's Claude status indicator
|
|
288
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
|
|
289
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`
|
|
290
307
|
|
|
291
308
|
**Git status codes:**
|
|
@@ -434,13 +451,29 @@ Useful when you're spinning up several similar tasks that share the same set of
|
|
|
434
451
|
|
|
435
452
|
| Key | Action | Description |
|
|
436
453
|
|---------|-------------------------|------------------------------------------------------------|
|
|
437
|
-
| `c` | Open Claude CLI |
|
|
454
|
+
| `c` | Open Claude CLI | Open the task's Claude session in a tab: reattach, resume the last one, or start a new one |
|
|
455
|
+
| `x` | Close Claude tab | Close the Claude tab (zellij only); Claude keeps working in the background |
|
|
438
456
|
| `C` | Open Claude desktop | Open the Claude desktop app on the Code page at the task folder |
|
|
439
457
|
| `b` | Dispatch agent | Run a background Claude agent (`claude --bg`) in the selected worktree |
|
|
440
458
|
|
|
441
459
|
**How it works:**
|
|
442
|
-
- `c`
|
|
443
|
-
|
|
460
|
+
- `c` runs Claude as a background session (`claude --bg`) in the task folder and opens a
|
|
461
|
+
terminal tab that only shows it (`claude attach`). A zellij tab inside zellij, else a
|
|
462
|
+
Ghostty tab; see [zellij](#zellij). Closing a zellij tab leaves Claude working; the
|
|
463
|
+
same with a Ghostty tab is not tested yet.
|
|
464
|
+
- A background session already in the task folder is attached, also a finished one.
|
|
465
|
+
- Otherwise the folder's last session is resumed in the background (`claude --bg
|
|
466
|
+
--resume`), or a new one starts. It waits for your first message; nothing runs before.
|
|
467
|
+
- With the worktree panel focused, `c` opens the agent `b` dispatched to that worktree,
|
|
468
|
+
if one exists.
|
|
469
|
+
- Claude already open in the task folder in another terminal is left alone.
|
|
470
|
+
- When `claude agents` or `claude --bg` fails (for example in an untrusted folder),
|
|
471
|
+
or with `claude_background = false`, Claude runs inside the tab: `claude -r` when
|
|
472
|
+
the folder has transcripts, else `claude`.
|
|
473
|
+
- Deleting a task asks first while a background session in it is working or waiting for
|
|
474
|
+
you, then stops and removes its sessions (`claude stop`, `claude rm`) before the
|
|
475
|
+
archive. Transcripts stay, so cancelling the delete later still lets `c` resume. A
|
|
476
|
+
session that will not stop keeps the task (the CLI goes on with `--force`).
|
|
444
477
|
- `C` opens the Claude desktop app via the `claude://code/new?folder=<task-folder>` URL scheme.
|
|
445
478
|
- 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.
|
|
446
479
|
- Session status (`⟳` running, `!` waiting, `✓` ended) appears next to the task name
|
|
@@ -840,9 +873,9 @@ npm i -g hunkdiff
|
|
|
840
873
|
|
|
841
874
|
**Direct editor integration:**
|
|
842
875
|
1. Highlight task or worktree
|
|
843
|
-
2. Press `e` to open your configured editor in a new
|
|
844
|
-
3. tasktree-manager keeps running alongside the editor (
|
|
845
|
-
|
|
876
|
+
2. Press `e` to open your configured editor in a new terminal tab (`$EDITOR .`)
|
|
877
|
+
3. tasktree-manager keeps running alongside the editor (a zellij tab inside zellij,
|
|
878
|
+
otherwise a Ghostty tab on macOS; see [zellij](#zellij))
|
|
846
879
|
|
|
847
880
|
**Configure your editor** in `~/.config/tasktree-manager/config.toml`:
|
|
848
881
|
```toml
|
|
@@ -873,6 +906,60 @@ code ~/tasks/FEAT-123 # Open entire task as workspace
|
|
|
873
906
|
- Use "Open Folder" or equivalent
|
|
874
907
|
- Git integration works normally
|
|
875
908
|
|
|
909
|
+
### zellij
|
|
910
|
+
|
|
911
|
+
`o`, `e` and `c` open a new terminal tab. Where the tab lives depends on where
|
|
912
|
+
tasktree-manager runs:
|
|
913
|
+
|
|
914
|
+
- Inside a zellij session (`ZELLIJ_SESSION_NAME` is set), each key opens a zellij tab
|
|
915
|
+
named after the folder and what runs in it: `TASK · shell`, `TASK/repo · editor`,
|
|
916
|
+
`TASK · claude`. The tab runs in the zellij server, so it keeps running when you close
|
|
917
|
+
or restart the terminal. Pressing the key again while that tab is open switches to it
|
|
918
|
+
instead of opening a second one.
|
|
919
|
+
- Anywhere else, each key opens a Ghostty tab via AppleScript (macOS only).
|
|
920
|
+
|
|
921
|
+
To run the TUI in zellij every time, set this in `config.toml`:
|
|
922
|
+
|
|
923
|
+
```toml
|
|
924
|
+
[tools]
|
|
925
|
+
zellij_autostart = true
|
|
926
|
+
zellij_session = "tasktree" # the default
|
|
927
|
+
```
|
|
928
|
+
|
|
929
|
+
Plain `tasktree-manager` then re-launches itself as
|
|
930
|
+
`zellij attach -c tasktree -- python -m tasktree_manager.app`. Without the setting, start
|
|
931
|
+
it that way yourself: `zellij attach -c tasktree -- tasktree-manager`.
|
|
932
|
+
|
|
933
|
+
After a terminal restart, run `tasktree-manager` (with autostart) or
|
|
934
|
+
`zellij attach tasktree`. Either brings back the TUI and every tab it opened, Claude
|
|
935
|
+
sessions included. The command after `--` runs only when the session is created, so a
|
|
936
|
+
second `tasktree-manager` in another terminal tab shows the same session.
|
|
937
|
+
|
|
938
|
+
**Too many tabs.** The `c` tab only shows a background Claude session, so it can close
|
|
939
|
+
while Claude keeps working:
|
|
940
|
+
|
|
941
|
+
1. Close the tab with `x` in tasktree-manager, or with zellij's own close-tab key.
|
|
942
|
+
2. The task row keeps its Claude status (`⟳` running, `!` waiting). When a turn finishes
|
|
943
|
+
while the tab is closed, a notice says so.
|
|
944
|
+
3. Press `c` on the task again: the tab reopens on the same conversation.
|
|
945
|
+
|
|
946
|
+
`x` closes only a tab whose panes run `claude attach` (zellij's pane list shows each
|
|
947
|
+
pane's launch command). A tab that runs Claude itself
|
|
948
|
+
(`claude_background = false`, or a tab from an older version) stays open, since closing
|
|
949
|
+
it would stop Claude.
|
|
950
|
+
|
|
951
|
+
- A tab that runs a command (`e`, `c`) closes when the command exits.
|
|
952
|
+
- The zellij tab runs the command with `sh -c`, so `editor` and `claude_path` must name
|
|
953
|
+
programs on `PATH`. A shell alias or fish function works only in the Ghostty tab.
|
|
954
|
+
- A zellij session does not survive a reboot. Attaching afterwards (or autostart) makes
|
|
955
|
+
zellij resurrect the saved layout, and each tab waits for ENTER before its command runs
|
|
956
|
+
again; tasktree-manager does not test that path.
|
|
957
|
+
- Autostart applies only when the TUI starts in a terminal outside zellij, never to a
|
|
958
|
+
piped run or to the headless CLI.
|
|
959
|
+
- zellij's default keybindings take Ctrl+P, Ctrl+T, Ctrl+O and other keys before the TUI
|
|
960
|
+
or Claude Code sees them. Pick zellij's "Unlock First (non-colliding)" preset or Alt-based
|
|
961
|
+
bindings, so Ctrl+P still opens the command palette.
|
|
962
|
+
|
|
876
963
|
### CI/CD
|
|
877
964
|
|
|
878
965
|
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.20.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.20.0'
|
|
22
|
+
__version_tuple__ = version_tuple = (2, 20, 0)
|
|
23
23
|
|
|
24
24
|
__commit_id__ = commit_id = None
|