@uiid/bertrand 0.10.0
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.
- package/LICENSE +21 -0
- package/README.md +200 -0
- package/dist/bertrand.js +7327 -0
- package/dist/migrations/0000_last_nitro.sql +104 -0
- package/dist/migrations/0001_melted_lady_ursula.sql +23 -0
- package/dist/migrations/0002_omniscient_speedball.sql +3 -0
- package/dist/migrations/meta/0000_snapshot.json +753 -0
- package/dist/migrations/meta/0001_snapshot.json +753 -0
- package/dist/migrations/meta/0002_snapshot.json +777 -0
- package/dist/migrations/meta/_journal.json +27 -0
- package/dist/run-screen.js +48976 -0
- package/package.json +61 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 uiid
|
|
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 all
|
|
13
|
+
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 THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,200 @@
|
|
|
1
|
+
# bertrand
|
|
2
|
+
|
|
3
|
+
Multi-session workflow manager for Claude Code. Tracks concurrent Claude Code sessions, captures their timelines into a local database, and surfaces them in a dashboard for review.
|
|
4
|
+
|
|
5
|
+
> **Status:** TypeScript rebuild. The previous Go release (v0.9.1) is still on Homebrew but no longer developed against this branch.
|
|
6
|
+
|
|
7
|
+
## How it works
|
|
8
|
+
|
|
9
|
+
Bertrand wraps Claude Code with two pieces:
|
|
10
|
+
|
|
11
|
+
1. **A system-prompt contract** that tells the agent to call `AskUserQuestion` every turn with concrete, actionable options.
|
|
12
|
+
2. **Claude Code hooks** that observe tool calls and lifecycle events (`PreToolUse`, `PostToolUse`, `UserPromptSubmit`, `Stop`, `PermissionRequest`) and write structured events into a local SQLite database.
|
|
13
|
+
|
|
14
|
+
The agent never knows bertrand exists. Hooks fire, scripts call `bertrand update`, rows land in the DB, the dashboard reads them.
|
|
15
|
+
|
|
16
|
+
When a session calls `AskUserQuestion`, bertrand marks it `waiting`, sets a Wave Terminal badge, and sends a notification. When you answer, the badge clears and the session moves to `active`.
|
|
17
|
+
|
|
18
|
+
## Prerequisites
|
|
19
|
+
|
|
20
|
+
- **[Claude Code](https://code.claude.com/docs/en/overview)** — `--append-system-prompt` and hooks support required.
|
|
21
|
+
- **[Bun](https://bun.sh/)** ≥ 1.3 — runtime for bertrand and the dashboard.
|
|
22
|
+
- **[Wave Terminal](https://www.waveterm.dev/)** — optional, but the only supported terminal for badges/notifications. Without it, bertrand still tracks state; you just don't get focus management.
|
|
23
|
+
|
|
24
|
+
## Install
|
|
25
|
+
|
|
26
|
+
```sh
|
|
27
|
+
bun i -g @uiid/bertrand # or: npm i -g @uiid/bertrand
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
The first run of `bertrand` auto-runs `init`; you can also invoke `bertrand init` explicitly.
|
|
31
|
+
|
|
32
|
+
### From source
|
|
33
|
+
|
|
34
|
+
```sh
|
|
35
|
+
git clone https://github.com/uiid-systems/bertrand.git
|
|
36
|
+
cd bertrand
|
|
37
|
+
bun install
|
|
38
|
+
bun run src/index.ts init
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Invoke via `bun run src/index.ts <command>` while developing.
|
|
42
|
+
|
|
43
|
+
## Setup
|
|
44
|
+
|
|
45
|
+
```sh
|
|
46
|
+
bertrand init
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
This:
|
|
50
|
+
|
|
51
|
+
1. Creates `~/.bertrand/` with `config.json` and `bertrand.db`.
|
|
52
|
+
2. Installs hook scripts to `~/.bertrand/hooks/`.
|
|
53
|
+
3. Registers them in `~/.claude/settings.json`.
|
|
54
|
+
4. Writes shell completions to `~/.bertrand/completions/`.
|
|
55
|
+
|
|
56
|
+
Re-run `init` whenever bertrand updates — hook scripts are versioned and may need refreshing.
|
|
57
|
+
|
|
58
|
+
## Usage
|
|
59
|
+
|
|
60
|
+
### Launch a new session
|
|
61
|
+
|
|
62
|
+
```sh
|
|
63
|
+
bertrand
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
Opens an Ink TUI to type a session name (e.g. `bertrand/fix-recap-render`, `frontend/ENG-142-auth`). Slashes nest the session under group folders. Claude Code launches with the bertrand contract applied.
|
|
67
|
+
|
|
68
|
+
### Resume
|
|
69
|
+
|
|
70
|
+
```sh
|
|
71
|
+
bertrand <group/session>
|
|
72
|
+
```
|
|
73
|
+
|
|
74
|
+
Shows a picker: start a fresh Claude conversation, or resume one of the prior conversations on this session. Either way, bertrand re-injects the session timeline and any sibling-session context.
|
|
75
|
+
|
|
76
|
+
### List
|
|
77
|
+
|
|
78
|
+
```sh
|
|
79
|
+
bertrand list
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
Interactive picker showing all sessions with status badges.
|
|
83
|
+
|
|
84
|
+
### Other commands
|
|
85
|
+
|
|
86
|
+
| Command | Purpose |
|
|
87
|
+
|---|---|
|
|
88
|
+
| `bertrand log <session>` | Print the timeline event log for a session. |
|
|
89
|
+
| `bertrand stats <session>` | Print materialized stats (duration, work/wait split, lines changed). |
|
|
90
|
+
| `bertrand archive <name>` | Archive or unarchive a session. |
|
|
91
|
+
| `bertrand serve` | Start the dashboard HTTP API on `:5200`. |
|
|
92
|
+
| `bertrand backfill-stats` | Re-compute stats for older sessions after schema changes. |
|
|
93
|
+
| `bertrand update` | Hook-facing event writer. Internal — don't call directly. |
|
|
94
|
+
|
|
95
|
+
## Dashboard
|
|
96
|
+
|
|
97
|
+
A Vite + React + TanStack Router app at `dashboard/`. Renders timelines (assistant text, thinking, code diffs, permissions, Q&A pairs, context snapshots), engagement stats, and a session sidebar.
|
|
98
|
+
|
|
99
|
+
Run both the API and the dev server:
|
|
100
|
+
|
|
101
|
+
```sh
|
|
102
|
+
cd dashboard
|
|
103
|
+
bun run dev
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
This spawns `bertrand serve` (API on `:5200`) and `vite` (dashboard on `:5199`). Visit [http://localhost:5199](http://localhost:5199). The dashboard proxies `/api` to `:5200`.
|
|
107
|
+
|
|
108
|
+
> The dashboard is currently dev-mode only. There's no production build/serve path yet.
|
|
109
|
+
|
|
110
|
+
## Session states
|
|
111
|
+
|
|
112
|
+
| Status | Meaning |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `active` | Agent is generating a response. |
|
|
115
|
+
| `waiting` | Agent called `AskUserQuestion`, blocked on user input. |
|
|
116
|
+
| `paused` | Session ended (Claude Code exited). |
|
|
117
|
+
| `archived` | Manually archived; hidden from default views. |
|
|
118
|
+
|
|
119
|
+
## Focus management (Wave)
|
|
120
|
+
|
|
121
|
+
When a session enters `waiting`, hooks call `wsh badge` to mark the block tab and `wsh notify` to send a notification. When it returns to `active`, the badge clears.
|
|
122
|
+
|
|
123
|
+
Other terminals fall back to no-ops; the session state is still tracked.
|
|
124
|
+
|
|
125
|
+
## Architecture
|
|
126
|
+
|
|
127
|
+
```
|
|
128
|
+
Claude Code hook → ~/.bertrand/hooks/*.sh → `bertrand update --event …` → SQLite (events table)
|
|
129
|
+
↓
|
|
130
|
+
/api/events/:sessionId
|
|
131
|
+
↓
|
|
132
|
+
dashboard timeline
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
Key tables ([`src/db/schema.ts`](src/db/schema.ts)):
|
|
136
|
+
|
|
137
|
+
- **`groups`** — nestable session containers.
|
|
138
|
+
- **`sessions`** — named workspaces, status-tracked.
|
|
139
|
+
- **`conversations`** — Claude conversations within a session (claude_id UUIDs).
|
|
140
|
+
- **`events`** — every hook firing and lifecycle moment (`session.waiting`, `session.answered`, `tool.applied`, `context.snapshot`, `session.recap`, etc.). Free-form `meta` JSON column.
|
|
141
|
+
- **`session_stats`** — materialized stats, refreshed at session end.
|
|
142
|
+
- **`worktree_associations`** — tracked worktree branches per session.
|
|
143
|
+
|
|
144
|
+
Stats are computed live for `active`/`waiting` sessions and read from the materialized row otherwise — see [`src/server/index.ts`](src/server/index.ts).
|
|
145
|
+
|
|
146
|
+
## File layout
|
|
147
|
+
|
|
148
|
+
### Repo
|
|
149
|
+
|
|
150
|
+
```
|
|
151
|
+
src/
|
|
152
|
+
cli/ # Command router and command handlers
|
|
153
|
+
contract/ # System-prompt contract (AskUserQuestion loop, sibling context)
|
|
154
|
+
db/ # Drizzle schema, migrations, query functions
|
|
155
|
+
engine/ # Session lifecycle (launch, resume, finalize)
|
|
156
|
+
hooks/ # Hook script generation (bash templates)
|
|
157
|
+
lib/ # Timing FSM, diff stats, engagement, formatting, tests
|
|
158
|
+
server/ # Bun HTTP server (/api/*)
|
|
159
|
+
terminal/ # Terminal adapters (Wave, Noop)
|
|
160
|
+
tui/ # Ink-based TUI screens
|
|
161
|
+
dashboard/
|
|
162
|
+
src/
|
|
163
|
+
api/ # Typed TanStack Query hooks
|
|
164
|
+
components/ # Timeline content renderers, sidebar, markdown
|
|
165
|
+
lib/ # Event categories, transforms, formatting
|
|
166
|
+
routes/ # TanStack Router pages
|
|
167
|
+
schema/ # Drizzle migration SQL
|
|
168
|
+
```
|
|
169
|
+
|
|
170
|
+
### Runtime
|
|
171
|
+
|
|
172
|
+
```
|
|
173
|
+
~/.bertrand/
|
|
174
|
+
config.json # Terminal + bertrand settings
|
|
175
|
+
bertrand.db # SQLite (sessions, events, stats)
|
|
176
|
+
hooks/
|
|
177
|
+
on-waiting.sh # PreToolUse AskUserQuestion → session.waiting
|
|
178
|
+
on-answered.sh # PostToolUse AskUserQuestion → session.answered
|
|
179
|
+
on-active.sh # PreToolUse catch-all → session.active
|
|
180
|
+
on-permission-wait.sh # PermissionRequest → permission.request
|
|
181
|
+
on-permission-done.sh # PostToolUse catch-all → permission.resolve
|
|
182
|
+
on-user-prompt.sh # UserPromptSubmit → user.prompt
|
|
183
|
+
on-done.sh # Stop → session.paused
|
|
184
|
+
completions/ # Shell completion scripts
|
|
185
|
+
```
|
|
186
|
+
|
|
187
|
+
## Development
|
|
188
|
+
|
|
189
|
+
```sh
|
|
190
|
+
bun run typecheck # Type-check src/
|
|
191
|
+
bun test # Run backend tests
|
|
192
|
+
bun run db:generate # Generate Drizzle migration after schema change
|
|
193
|
+
bun run db:migrate # Apply migrations to ~/.bertrand/bertrand.db
|
|
194
|
+
```
|
|
195
|
+
|
|
196
|
+
The dashboard has its own `tsc -b` typecheck — run from `dashboard/`.
|
|
197
|
+
|
|
198
|
+
## License
|
|
199
|
+
|
|
200
|
+
MIT
|