zozul-cli 0.2.1 → 0.2.2
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/README.md +81 -135
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,185 +1,131 @@
|
|
|
1
|
-
# zozul
|
|
1
|
+
# zozul
|
|
2
2
|
|
|
3
|
-
Observability for [Claude Code](https://code.claude.com/)
|
|
3
|
+
Observability for [Claude Code](https://code.claude.com/). Track costs, sessions, and conversations across projects.
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
zozul is a single local process that captures everything Claude Code does. Data flows in from three complementary sources and lands in a SQLite database at `~/.zozul/zozul.db`. A built-in web dashboard and JSON API sit on top of that.
|
|
8
|
-
|
|
9
|
-
| Source | What it provides |
|
|
10
|
-
|---|---|
|
|
11
|
-
| **OTEL receiver** | Token counts, cost (USD), active time, API events, user prompts — streamed from Claude Code every ~60s |
|
|
12
|
-
| **Hooks** | Real-time session lifecycle, tool calls, user prompts — fired synchronously as events happen |
|
|
13
|
-
| **JSONL watcher** | Full turn content, assistant responses, per-turn token detail — read directly from Claude Code's transcript files |
|
|
14
|
-
|
|
15
|
-
Each source has different strengths. OTEL is the authoritative source for **cost and duration**. JSONL is the only source for **full conversation text**. Hooks provide **real-time signals** and trigger transcript ingestion on session end. The `sessions` table is kept in sync from all three.
|
|
5
|
+
Works locally out of the box. Optionally syncs to a remote backend for persistent storage and team visibility.
|
|
16
6
|
|
|
17
7
|
## Quick start
|
|
18
8
|
|
|
19
9
|
```bash
|
|
20
|
-
# Install globally from npm
|
|
21
10
|
npm install -g zozul-cli
|
|
22
11
|
|
|
23
|
-
# Configure Claude Code and
|
|
12
|
+
# Configure Claude Code and run as a background service
|
|
24
13
|
zozul install --service
|
|
25
14
|
|
|
26
15
|
# Open the dashboard
|
|
27
16
|
open http://localhost:7890/dashboard
|
|
28
|
-
|
|
29
|
-
# Use Claude Code normally — data appears automatically
|
|
30
|
-
claude
|
|
31
|
-
```
|
|
32
|
-
|
|
33
|
-
Or if you'd rather manage the process yourself:
|
|
34
|
-
|
|
35
|
-
```bash
|
|
36
|
-
zozul install # Configure Claude Code hooks + OTEL
|
|
37
|
-
zozul serve # Start the server
|
|
38
|
-
open http://localhost:7890/dashboard
|
|
39
17
|
```
|
|
40
18
|
|
|
41
|
-
|
|
19
|
+
That's it. Use Claude Code normally — data appears automatically.
|
|
42
20
|
|
|
43
|
-
|
|
21
|
+
## What you get
|
|
44
22
|
|
|
45
|
-
|
|
23
|
+
A single local process that captures everything Claude Code does via three sources:
|
|
46
24
|
|
|
47
|
-
- **
|
|
48
|
-
- **
|
|
49
|
-
- **
|
|
50
|
-
- **Sessions** — sortable, filterable, paginated session table; click any session for the full conversation with per-turn token counts and expandable tool call inputs/outputs
|
|
25
|
+
- **OTEL** — cost, tokens, active time. Streamed every ~60s. The authoritative source for spend.
|
|
26
|
+
- **Hooks** — session lifecycle, tool calls, user prompts. Real-time.
|
|
27
|
+
- **JSONL** — full conversation text, assistant responses. Read from Claude Code's transcript files.
|
|
51
28
|
|
|
52
|
-
|
|
29
|
+
All data lands in SQLite at `~/.zozul/zozul.db`. A web dashboard and JSON API sit on top.
|
|
53
30
|
|
|
54
|
-
|
|
31
|
+
## Dashboard
|
|
55
32
|
|
|
56
|
-
|
|
33
|
+
`http://localhost:7890/dashboard`
|
|
57
34
|
|
|
58
|
-
|
|
|
35
|
+
| View | What it answers |
|
|
59
36
|
|---|---|
|
|
60
|
-
|
|
|
61
|
-
|
|
|
62
|
-
|
|
|
63
|
-
|
|
|
64
|
-
| `zozul install --restart` | Restart the background service (picks up new builds) |
|
|
65
|
-
| `zozul install --dry-run` | Preview the config that would be installed |
|
|
66
|
-
| `zozul uninstall` | Remove zozul hooks, OTEL config, git hook, and background service |
|
|
67
|
-
| `zozul context <tags...>` | Set active task tags for tagging turns (e.g. `zozul context "UI" "Feature"`) |
|
|
68
|
-
| `zozul context --list` | List all tasks that have been used |
|
|
69
|
-
| `zozul context --clear` | Clear the active task context |
|
|
70
|
-
| `zozul sync` | Sync local data to the remote zozul backend |
|
|
71
|
-
| `zozul sync --dry-run` | Show what would be synced without sending data |
|
|
72
|
-
|
|
73
|
-
## Architecture
|
|
37
|
+
| **Summary** | How much have I spent? Cost chart, project breakdown, totals. |
|
|
38
|
+
| **Tasks** | What did I work on? Groups turns by tag combination, shows cost and time per task. |
|
|
39
|
+
| **Tags** | How much per category? Per-tag stats with drill-down into individual prompts. |
|
|
40
|
+
| **Sessions** | Raw session list. Sortable, filterable, click to see full conversation. |
|
|
74
41
|
|
|
75
|
-
|
|
76
|
-
Claude Code
|
|
77
|
-
|
|
|
78
|
-
+-------------+-------------+
|
|
79
|
-
| | |
|
|
80
|
-
OTEL export Hook POSTs ~/.claude/projects/
|
|
81
|
-
(every ~60s) (real-time) <project>/<uuid>.jsonl
|
|
82
|
-
| | |
|
|
83
|
-
v v v
|
|
84
|
-
/v1/metrics /hook/* fs.watch (live)
|
|
85
|
-
/v1/logs | zozul ingest (manual)
|
|
86
|
-
| | |
|
|
87
|
-
| updateSessionFromOtel |
|
|
88
|
-
| | persistSession
|
|
89
|
-
+------+------+------+------+
|
|
90
|
-
|
|
|
91
|
-
SQLite (WAL)
|
|
92
|
-
~/.zozul/zozul.db
|
|
93
|
-
|
|
|
94
|
-
+------+------+
|
|
95
|
-
| |
|
|
96
|
-
/dashboard /api/*
|
|
97
|
-
(browser) (JSON)
|
|
98
|
-
```
|
|
42
|
+
All views support time filtering (7d / 30d / All). Auto-refreshes every 10s.
|
|
99
43
|
|
|
100
|
-
|
|
44
|
+
When a remote backend is configured, the dashboard auto-detects it via health check and uses it as the data source. Falls back to local if unavailable.
|
|
101
45
|
|
|
102
|
-
|
|
46
|
+
## Task tagging
|
|
103
47
|
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
| Field | Owner | Notes |
|
|
107
|
-
|---|---|---|
|
|
108
|
-
| `id`, `started_at`, `project_path`, `model` | JSONL | Set from transcript filename and content |
|
|
109
|
-
| `total_turns` | JSONL | Count of turns parsed from transcript |
|
|
110
|
-
| `total_cost_usd` | OTEL | JSONL transcripts do not include cost data |
|
|
111
|
-
| `total_duration_ms` | OTEL | Accumulated from `claude_code.active_time.total` |
|
|
112
|
-
| `total_*_tokens` (session level) | OTEL (preferred) | JSONL provides seeds; OTEL accumulates via `MAX()` |
|
|
113
|
-
| `ended_at` | Both | OTEL keeps it current as batches arrive; JSONL sets it at ingest |
|
|
48
|
+
Tag your work so costs are attributed to what you're building:
|
|
114
49
|
|
|
115
|
-
|
|
50
|
+
```bash
|
|
51
|
+
zozul context "auth" "backend" # Set active tags
|
|
52
|
+
# ... use Claude Code ...
|
|
53
|
+
git commit # Tags auto-clear on commit
|
|
54
|
+
```
|
|
116
55
|
|
|
117
|
-
|
|
56
|
+
Tags appear in the Tasks and Tags views. Turns are grouped by their tag combination.
|
|
118
57
|
|
|
119
|
-
|
|
58
|
+
## Remote sync
|
|
120
59
|
|
|
121
|
-
|
|
122
|
-
2. Watches that directory for changes via `fs.watch` (recursive, FSEvents on macOS)
|
|
123
|
-
3. Debounces per-file at 500ms and calls `ingestSessionFile` on each change
|
|
60
|
+
Optionally push data to a remote backend:
|
|
124
61
|
|
|
125
|
-
|
|
62
|
+
```bash
|
|
63
|
+
# Set in .env or environment
|
|
64
|
+
ZOZUL_API_URL=https://your-backend.example.com
|
|
65
|
+
ZOZUL_API_KEY=your-key
|
|
126
66
|
|
|
127
|
-
|
|
67
|
+
zozul sync
|
|
68
|
+
```
|
|
128
69
|
|
|
129
|
-
|
|
70
|
+
Sync is incremental (watermark-based) and also runs automatically on session end when the service is running. The dashboard switches to the remote API when available.
|
|
130
71
|
|
|
131
|
-
|
|
72
|
+
## Commands
|
|
132
73
|
|
|
133
|
-
|
|
74
|
+
| Command | Description |
|
|
75
|
+
|---|---|
|
|
76
|
+
| `zozul serve` | Start the server on port 7890 |
|
|
77
|
+
| `zozul install` | Configure Claude Code hooks and OTEL |
|
|
78
|
+
| `zozul install --service` | Also install as a background service (auto-starts on login) |
|
|
79
|
+
| `zozul install --status` | Check if the service is running |
|
|
80
|
+
| `zozul install --restart` | Restart the service after code changes |
|
|
81
|
+
| `zozul uninstall` | Remove all hooks, config, and service |
|
|
82
|
+
| `zozul context <tags...>` | Set active task tags |
|
|
83
|
+
| `zozul context --clear` | Clear tags |
|
|
84
|
+
| `zozul sync` | Push local data to remote backend |
|
|
85
|
+
|
|
86
|
+
## How it works
|
|
134
87
|
|
|
135
|
-
|
|
88
|
+
```
|
|
89
|
+
Claude Code
|
|
90
|
+
|
|
|
91
|
+
+--- OTEL export (every ~60s) ---> /v1/metrics, /v1/logs
|
|
92
|
+
+--- Hook POSTs (real-time) -----> /hook/*
|
|
93
|
+
+--- JSONL transcripts ----------> fs.watch
|
|
94
|
+
|
|
|
95
|
+
v
|
|
96
|
+
SQLite (~/.zozul/zozul.db)
|
|
97
|
+
|
|
|
98
|
+
+--- /dashboard (browser)
|
|
99
|
+
+--- /api/* (JSON)
|
|
100
|
+
+--- zozul sync --> remote backend (optional)
|
|
101
|
+
```
|
|
136
102
|
|
|
137
|
-
|
|
138
|
-
- **Linux**: writes `~/.config/systemd/user/zozul.service` and enables it with `systemctl --user`.
|
|
103
|
+
Single process on port 7890. macOS uses launchd, Linux uses systemd.
|
|
139
104
|
|
|
140
|
-
|
|
105
|
+
### Data ownership
|
|
141
106
|
|
|
142
|
-
|
|
107
|
+
| What | Source | Notes |
|
|
108
|
+
|---|---|---|
|
|
109
|
+
| Cost | OTEL | JSONL doesn't include cost |
|
|
110
|
+
| Duration | OTEL | Accumulated from active time metrics |
|
|
111
|
+
| Tokens | OTEL (preferred) | JSONL provides initial values, OTEL accumulates |
|
|
112
|
+
| Conversation text | JSONL | Full turns, tool calls, assistant responses |
|
|
113
|
+
| Session events | Hooks | Start, end, stop, tool use |
|
|
143
114
|
|
|
144
115
|
## Configuration
|
|
145
116
|
|
|
146
|
-
|
|
117
|
+
Via `.env` or environment variables:
|
|
147
118
|
|
|
148
119
|
```bash
|
|
149
|
-
ZOZUL_PORT=7890
|
|
150
|
-
ZOZUL_DB_PATH=~/.zozul/zozul.db
|
|
151
|
-
ZOZUL_VERBOSE=1
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
OTEL_LOG_USER_PROMPTS=1 # Include prompt text in OTEL events
|
|
155
|
-
OTEL_LOG_TOOL_DETAILS=1 # Include tool names in OTEL events
|
|
120
|
+
ZOZUL_PORT=7890 # Default: 7890
|
|
121
|
+
ZOZUL_DB_PATH=~/.zozul/zozul.db # Default: ~/.zozul/zozul.db
|
|
122
|
+
ZOZUL_VERBOSE=1 # Log all events
|
|
123
|
+
ZOZUL_API_URL=https://... # Remote backend URL (optional)
|
|
124
|
+
ZOZUL_API_KEY=... # Remote backend API key (optional)
|
|
156
125
|
```
|
|
157
126
|
|
|
158
|
-
CLI flags override `.env` values.
|
|
159
|
-
|
|
160
|
-
## Data captured
|
|
161
|
-
|
|
162
|
-
| Data point | Source | Granularity |
|
|
163
|
-
|---|---|---|
|
|
164
|
-
| Token usage (input/output/cache/creation) | OTEL + JSONL | Per-session and per-turn |
|
|
165
|
-
| Cost (USD) | OTEL | Per-session, per-model |
|
|
166
|
-
| Active time | OTEL | Per-session |
|
|
167
|
-
| Turns / API calls | JSONL | Full content and metadata |
|
|
168
|
-
| User prompts | Hooks (`UserPromptSubmit`) + JSONL | Count (aggregate) + full text (per-turn) |
|
|
169
|
-
| Interruptions | Hooks (`Stop`) | Count (aggregate) |
|
|
170
|
-
| Model responses | JSONL only | Full text |
|
|
171
|
-
| Tool calls and results | Hooks + JSONL | Name, input, output |
|
|
172
|
-
| Session lifecycle | Hooks | Start, end, stop events |
|
|
173
|
-
|
|
174
127
|
## Requirements
|
|
175
128
|
|
|
176
129
|
- Node.js 18+
|
|
177
|
-
-
|
|
178
|
-
- Claude Code installed (`claude --version`)
|
|
130
|
+
- Claude Code (`claude --version`)
|
|
179
131
|
- Claude Pro, Max, Teams, Enterprise, or API key
|
|
180
|
-
|
|
181
|
-
## Updating
|
|
182
|
-
|
|
183
|
-
```bash
|
|
184
|
-
npm install -g zozul-cli
|
|
185
|
-
```
|