cc-calendar 0.4.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 (38) hide show
  1. cc_calendar-0.4.0/.gitignore +7 -0
  2. cc_calendar-0.4.0/LICENSE +21 -0
  3. cc_calendar-0.4.0/PKG-INFO +261 -0
  4. cc_calendar-0.4.0/README.md +231 -0
  5. cc_calendar-0.4.0/pyproject.toml +65 -0
  6. cc_calendar-0.4.0/src/cc_calendar/__init__.py +9 -0
  7. cc_calendar-0.4.0/src/cc_calendar/__main__.py +3 -0
  8. cc_calendar-0.4.0/src/cc_calendar/cli.py +113 -0
  9. cc_calendar-0.4.0/src/cc_calendar/gitinfo.py +129 -0
  10. cc_calendar-0.4.0/src/cc_calendar/logview.py +204 -0
  11. cc_calendar-0.4.0/src/cc_calendar/notes.py +173 -0
  12. cc_calendar-0.4.0/src/cc_calendar/parser.py +605 -0
  13. cc_calendar-0.4.0/src/cc_calendar/pricing.py +98 -0
  14. cc_calendar-0.4.0/src/cc_calendar/search.py +389 -0
  15. cc_calendar-0.4.0/src/cc_calendar/server.py +396 -0
  16. cc_calendar-0.4.0/src/cc_calendar/static/app.js +897 -0
  17. cc_calendar-0.4.0/src/cc_calendar/static/calendar.js +249 -0
  18. cc_calendar-0.4.0/src/cc_calendar/static/detail.js +202 -0
  19. cc_calendar-0.4.0/src/cc_calendar/static/export.js +91 -0
  20. cc_calendar-0.4.0/src/cc_calendar/static/index.html +132 -0
  21. cc_calendar-0.4.0/src/cc_calendar/static/listfilter.js +93 -0
  22. cc_calendar-0.4.0/src/cc_calendar/static/notes.js +153 -0
  23. cc_calendar-0.4.0/src/cc_calendar/static/notify.js +54 -0
  24. cc_calendar-0.4.0/src/cc_calendar/static/overview.js +148 -0
  25. cc_calendar-0.4.0/src/cc_calendar/static/project.js +132 -0
  26. cc_calendar-0.4.0/src/cc_calendar/static/report.js +61 -0
  27. cc_calendar-0.4.0/src/cc_calendar/static/shortcuts.js +92 -0
  28. cc_calendar-0.4.0/src/cc_calendar/static/style.css +425 -0
  29. cc_calendar-0.4.0/src/cc_calendar/static/summary.js +103 -0
  30. cc_calendar-0.4.0/src/cc_calendar/static/toolspane.js +91 -0
  31. cc_calendar-0.4.0/src/cc_calendar/static/transcript.js +473 -0
  32. cc_calendar-0.4.0/src/cc_calendar/static/urlstate.js +52 -0
  33. cc_calendar-0.4.0/src/cc_calendar/static/util.js +248 -0
  34. cc_calendar-0.4.0/src/cc_calendar/static/vendor/marked.min.js +69 -0
  35. cc_calendar-0.4.0/src/cc_calendar/static/vendor/purify.min.js +3 -0
  36. cc_calendar-0.4.0/src/cc_calendar/stats.py +132 -0
  37. cc_calendar-0.4.0/src/cc_calendar/store.py +264 -0
  38. cc_calendar-0.4.0/src/cc_calendar/tools.py +87 -0
@@ -0,0 +1,7 @@
1
+ .venv/
2
+ __pycache__/
3
+ *.pyc
4
+ dist/
5
+ .pytest_cache/
6
+ .ruff_cache/
7
+ site/
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 atinfinity
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.
@@ -0,0 +1,261 @@
1
+ Metadata-Version: 2.5
2
+ Name: cc-calendar
3
+ Version: 0.4.0
4
+ Summary: Google Calendar-style weekly view of your Claude Code sessions
5
+ Project-URL: Homepage, https://atinfinity.github.io/cc-calendar/
6
+ Project-URL: Documentation, https://atinfinity.github.io/cc-calendar/
7
+ Project-URL: Repository, https://github.com/atinfinity/cc-calendar
8
+ Project-URL: Issues, https://github.com/atinfinity/cc-calendar/issues
9
+ Author-email: atinfinity <dandelion1124@gmail.com>
10
+ License-Expression: MIT
11
+ License-File: LICENSE
12
+ Keywords: calendar,claude,claude-code,dashboard,sessions,transcripts
13
+ Classifier: Development Status :: 4 - Beta
14
+ Classifier: Environment :: Web Environment
15
+ Classifier: Framework :: FastAPI
16
+ Classifier: Intended Audience :: Developers
17
+ Classifier: Operating System :: MacOS
18
+ Classifier: Operating System :: POSIX :: Linux
19
+ Classifier: Programming Language :: Python :: 3
20
+ Classifier: Programming Language :: Python :: 3 :: Only
21
+ Classifier: Programming Language :: Python :: 3.12
22
+ Classifier: Programming Language :: Python :: 3.13
23
+ Classifier: Topic :: Software Development
24
+ Classifier: Topic :: Utilities
25
+ Requires-Python: >=3.12
26
+ Requires-Dist: fastapi>=0.142.2
27
+ Requires-Dist: uvicorn[standard]>=0.54.0
28
+ Requires-Dist: watchfiles>=1.3.0
29
+ Description-Content-Type: text/markdown
30
+
31
+ # cc-calendar
32
+
33
+ [![PyPI](https://img.shields.io/pypi/v/cc-calendar)](https://pypi.org/project/cc-calendar/)
34
+
35
+ A Google Calendar-style weekly view of your [Claude Code](https://claude.com/claude-code) sessions.
36
+
37
+ `cc-calendar` reads the transcripts Claude Code already writes to `~/.claude/projects/` and shows
38
+ when you worked, on what, what it cost, and what came out of it — commits, changed files and pull
39
+ requests — in a local web UI that updates live while sessions run.
40
+
41
+ **Project site:** <https://atinfinity.github.io/cc-calendar/>
42
+
43
+ ![Week calendar colored by project](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/calendar.png)
44
+
45
+ ## Install
46
+
47
+ Requires [uv](https://docs.astral.sh/uv/) (Python 3.12+ is fetched automatically).
48
+
49
+ ```sh
50
+ uv tool install cc-calendar
51
+ cc-calendar
52
+ ```
53
+
54
+ Or try it without installing: `uvx cc-calendar`. Update with `uv tool upgrade cc-calendar`.
55
+
56
+ To run it from a checkout:
57
+
58
+ ```sh
59
+ uv run cc-calendar
60
+ ```
61
+
62
+ The server binds to `127.0.0.1` on a free port and opens your browser.
63
+
64
+ | Option | Description |
65
+ | --- | --- |
66
+ | `--port N` | Listen on a specific port instead of a free one |
67
+ | `--no-browser` | Do not open a browser window |
68
+ | `--claude-dir [NAME=]PATH` | Read logs from another Claude Code config directory (default `~/.claude`). Repeat it to show several directories in one calendar |
69
+ | `--notes PATH` | File that keeps your session notes and tags (default: see [Notes and tags](https://atinfinity.github.io/cc-calendar/getting-started/#notes-and-tags)) |
70
+ | `--search-index PATH` | File that keeps the full-text search index (default: see [Full-text search](https://atinfinity.github.io/cc-calendar/features/#full-text-search)) |
71
+
72
+ ### Several config directories
73
+
74
+ Pass `--claude-dir` more than once to see sessions from several places together, such as
75
+ `~/.claude` directories synced from other machines or separate configs used with
76
+ `CLAUDE_CONFIG_DIR`. Only the directories you list are read, so include `~/.claude` to keep
77
+ your local sessions:
78
+
79
+ ```sh
80
+ cc-calendar --claude-dir ~/.claude --claude-dir ~/sync/laptop/.claude --claude-dir work=~/.claude-work
81
+ ```
82
+
83
+ Each directory gets a name: the one you give with `NAME=`, otherwise `local` for `~/.claude`, the
84
+ parent folder for a path ending in `.claude` (`laptop` above), or the folder itself. Sessions show
85
+ where they came from in the list (**Source** column and filter), the detail pane, the calendar
86
+ tooltip and the CSV/JSON export (`source`), and **Color by → Source** colors them by directory.
87
+ A session found in more than one directory is shown once, from the copy with the latest activity.
88
+
89
+ ### Notes and tags
90
+
91
+ Notes and tags you add to sessions are saved in one JSON file, keyed by session ID:
92
+
93
+ | Platform | Default location |
94
+ | --- | --- |
95
+ | macOS | `~/Library/Application Support/cc-calendar/notes.json` |
96
+ | Linux | `$XDG_DATA_HOME/cc-calendar/notes.json` (`~/.local/share/…` when unset) |
97
+ | Windows | `%APPDATA%\cc-calendar\notes.json` |
98
+
99
+ Point `--notes` at another file to keep it somewhere else, such as a synced folder to share notes
100
+ between machines; changes made to the file elsewhere are picked up. One file serves every
101
+ `--claude-dir`. Notes stay in the file after Claude Code deletes a session's old log.
102
+
103
+ ### Full-text search
104
+
105
+ Tick **Full text** next to the search box to also search what Claude wrote: assistant replies,
106
+ tool inputs (commands, file paths, edits), tool output, and subagent transcripts. Thinking is not
107
+ searched. Queries need at least 3 characters, ignore case and line breaks, and work for Japanese
108
+ and other languages without spaces. Matching sessions show a snippet of the first hit in the list,
109
+ the calendar tooltip and the detail pane; **Open ↗** opens the transcript at that hit, and
110
+ **Matches** in the transcript steps through the others.
111
+
112
+ The text is kept in a SQLite index, built in the background on first start and updated as logs
113
+ grow, so later starts only read new lines. Until it is complete, the status next to the toggle
114
+ says so and results fill in as it goes. The index is a cache and safe to delete:
115
+
116
+ | Platform | Default location |
117
+ | --- | --- |
118
+ | macOS | `~/Library/Caches/cc-calendar/search.db` |
119
+ | Linux | `$XDG_CACHE_HOME/cc-calendar/search.db` (`~/.cache/…` when unset) |
120
+ | Windows | `%LOCALAPPDATA%\cc-calendar\search.db` |
121
+
122
+ Point `--search-index` at another file to keep it elsewhere. It takes a little under half the space of
123
+ the logs it covers.
124
+
125
+ ## Features
126
+
127
+ - **Week and day calendar** — each session is drawn as bars covering its active periods; a session is
128
+ split wherever it sat idle longer than the chosen threshold (15 minutes by default). Overlapping
129
+ sessions sit side by side. Click a date in the week view to open that day on its own. Zoom with
130
+ the − / + buttons or Ctrl + mouse wheel.
131
+ - **Month and year views** — a month calendar and a GitHub-style yearly heatmap, one cell per day
132
+ shaded by active time or cost (switch with "Shade by"). Month cells list the day's busiest
133
+ projects; the year view adds per-month totals. Click a day to open it in the day view, or a
134
+ month total to open that month.
135
+ - **Time and cost totals** — each date shows that day's active time and cost, and the Summary
136
+ table breaks the displayed range down by project. Active time is the drawn bars; a session's cost
137
+ is split across days by when its requests ran. Totals follow the current filters.
138
+ - **Markdown report** — "Copy report" copies the displayed day, week, month or year as Markdown:
139
+ active time and cost per project, each session's title and tags (not notes) and the commits made in the range. Ready
140
+ to paste into a standup note or a daily report; it follows the current filters. Issue and PR
141
+ numbers such as `#12` become links to the repository's `origin` remote.
142
+ - **Tool usage** — the Tools pane aggregates tool calls in the displayed range: most used tools,
143
+ error counts and rates (10% or more is highlighted), calls made inside subagents, MCP servers,
144
+ and subagent runs by type with their tool calls, tokens and cost. It follows the current filters.
145
+ - **Cache efficiency** — each session shows its cache hit rate (cache reads as a share of input
146
+ tokens) and roughly how much caching saved. Sort the list by Cache to find sessions with poor
147
+ reuse; rates below 90% are highlighted (Claude Code usually reuses well over 90%).
148
+ - **Event marks** — marks on each bar show when prompts, commits, compactions and API errors
149
+ happened, and the tooltip counts them for that block. Click a mark (or a request or commit time
150
+ in the detail pane) to open the transcript at that point; the transcript has ‹ › buttons to step
151
+ through each kind of event. Click the key next to the legend to hide the marks.
152
+ - **Activity density** — a heat strip behind each day shows prompts and responses per 10 minutes.
153
+ - **Colors** by project, status, model, effort (the level most requests ran at), source (with
154
+ several config directories), tag (the first tag of each session) or cost
155
+ (< $1 / $1–5 / $5–20 / $20–50 / ≥ $50).
156
+ - **Effort and compactions** — the detail pane and transcript stats show the share of requests
157
+ per effort level, and each compaction shows its trigger and context size before → after
158
+ (e.g. `auto · 168k → 32k tokens`) in the mark tooltip, the transcript and the detail pane.
159
+ - **Status** — Running and Waiting for live sessions, Done or Interrupted for finished ones, with
160
+ the underlying checks (turn ended, no background work left, clean exit, working tree clean).
161
+ - **Notifications** — turn on "Notify" in the top bar to get a desktop notification when a live
162
+ session goes from Running to Waiting for your input, or ends Interrupted, while the tab is in the
163
+ background. Off by default; clicking the notification opens the session.
164
+ - **Detail pane** — tokens, cost, context usage, every request you made with the commits that
165
+ followed it, files changed, pull requests, subagents and background tasks, and links between
166
+ a session and the one it was continued in.
167
+ - **Resume** — "Copy resume command" in the detail pane copies
168
+ `cd <project dir> && claude --resume <session id>`, so you can pick a session up again from a
169
+ terminal.
170
+ - **Transcript viewer** — Markdown rendering, collapsible tool calls, optional thinking and
171
+ metadata, drill-down into subagent transcripts, and a stats panel per transcript (active time,
172
+ requests, tokens and cost by model, tool calls and errors by tool).
173
+ - **Notes and tags** — add a note and tags to a session in the detail pane to find it again
174
+ later. The note saves when you leave the box (or with ⌘/Ctrl+Enter); `Enter` or a comma adds a
175
+ tag, with suggestions from tags already in use. Tags that differ only in case count as one.
176
+ Tags show in the list (**Tags** column and filter) and the calendar tooltip, and a 📝 marks
177
+ sessions with a note. See [where they are saved](https://atinfinity.github.io/cc-calendar/getting-started/#notes-and-tags).
178
+ - **List view** with search over titles, prompts, notes and tags (a match inside a prompt or note is shown under the title), optional
179
+ [full-text search](https://atinfinity.github.io/cc-calendar/features/#full-text-search) over the whole transcripts, project and status filters, and sorting by
180
+ any column (click a header; click again to reverse). List-only filters narrow it down further
181
+ by model, git branch, source (with several config directories), tag, date range (sessions active on
182
+ any day in the range) and cost range.
183
+ - **Project page** — click a project name (in the list, the Summary table, the detail pane or the
184
+ project menu) to see the project over all time: total active time and cost, activity by month,
185
+ every session, and its commit history with links to the repository.
186
+ - **Export** — download the sessions shown in the list view as CSV or JSON, in the current filter
187
+ and sort order: start, end, active time, project, source directory, branch, status, prompts,
188
+ tokens, cost, cache hit rate, model, effort, Claude Code version, commit count, tags and note. Times are
189
+ ISO 8601 with your UTC offset. See the [export format](https://atinfinity.github.io/cc-calendar/export/).
190
+ - **Keyboard shortcuts** — `←` / `→` previous / next range, `t` today, `d` / `w` / `m` / `y` span,
191
+ `c` / `l` calendar / list, `/` search, `j` / `k` next / previous session, `Enter` open its
192
+ transcript, `Esc` close. In a transcript, `n` / `p` step through events, `]` / `[` through
193
+ prompts, and `s` / `e` toggle Stats / Expand tools. Press `?` (or click **?** in the top bar)
194
+ for the full list.
195
+ - **Views in the URL** — the address keeps the view, span, date, selected session and project
196
+ page, so reloading keeps your place, Back and Forward step through range and view changes, and
197
+ views can be bookmarked.
198
+ - **Live updates** — new log lines are picked up within a second.
199
+
200
+ | Session detail | Transcript with stats |
201
+ | --- | --- |
202
+ | ![Detail pane](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/detail.png) | ![Transcript viewer](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/transcript.png) |
203
+ | **List view** | **Month view** |
204
+ | ![List view](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/list.png) | ![Month view](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/month.png) |
205
+
206
+ Screenshots show fictional demo data.
207
+
208
+ Cost comes from Claude Code's own cost record when the session wrote one. Otherwise it is estimated
209
+ from token usage and a built-in price table, and shown with a `~` prefix.
210
+
211
+ Treat all costs as rough figures, not billing data. The price table in
212
+ `src/cc_calendar/pricing.py` uses Anthropic API list prices as of when it was last updated. It does
213
+ not know about subscription plans, discounts or price changes. Models missing from the table count
214
+ as $0, so it needs updating when new models ship.
215
+
216
+ ## Privacy
217
+
218
+ Everything stays on your machine. The server listens only on localhost, reads your logs read-only,
219
+ and makes no network requests. It writes two files: the notes file
220
+ ([Notes and tags](https://atinfinity.github.io/cc-calendar/getting-started/#notes-and-tags)), only when you add or change a note or tag, and the
221
+ [full-text search index](https://atinfinity.github.io/cc-calendar/features/#full-text-search), a cache built from your logs. Requests from other
222
+ websites cannot change either. Commit hashes that do not appear in the
223
+ logs are looked up with `git log` in the session's working directory.
224
+
225
+ ## Development
226
+
227
+ ```sh
228
+ uv sync
229
+ uv run pytest
230
+ uv run ruff check . && uv run ruff format --check .
231
+ ```
232
+
233
+ The frontend is plain HTML, CSS and ES modules in `src/cc_calendar/static/` — no build step.
234
+ Tests use synthetic logs only; never commit real transcripts.
235
+
236
+ Releases are published to PyPI by pushing a version tag; see
237
+ [Releasing](https://atinfinity.github.io/cc-calendar/development/#releasing).
238
+
239
+ The README screenshots are rendered from fictional data generated by `scripts/demo_data.py`, using
240
+ your installed Google Chrome:
241
+
242
+ ```sh
243
+ uv run --with playwright python scripts/screenshots.py
244
+ ```
245
+
246
+ The project site is built with [Zensical](https://zensical.org/) from `docs/` and `zensical.toml`,
247
+ and deployed to GitHub Pages on every push to `main`. Preview it locally:
248
+
249
+ ```sh
250
+ uv run --group docs zensical serve
251
+ ```
252
+
253
+ ## Acknowledgements
254
+
255
+ Inspired by the tool shown in [this post by @tokkyo](https://x.com/tokkyo/status/2106240136778575897).
256
+ This is an independent reimplementation and is not affiliated with the original.
257
+
258
+ ## License
259
+
260
+ MIT. Bundles [marked](https://github.com/markedjs/marked) (MIT) and
261
+ [DOMPurify](https://github.com/cure53/DOMPurify) (Apache-2.0 / MPL-2.0).
@@ -0,0 +1,231 @@
1
+ # cc-calendar
2
+
3
+ [![PyPI](https://img.shields.io/pypi/v/cc-calendar)](https://pypi.org/project/cc-calendar/)
4
+
5
+ A Google Calendar-style weekly view of your [Claude Code](https://claude.com/claude-code) sessions.
6
+
7
+ `cc-calendar` reads the transcripts Claude Code already writes to `~/.claude/projects/` and shows
8
+ when you worked, on what, what it cost, and what came out of it — commits, changed files and pull
9
+ requests — in a local web UI that updates live while sessions run.
10
+
11
+ **Project site:** <https://atinfinity.github.io/cc-calendar/>
12
+
13
+ ![Week calendar colored by project](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/calendar.png)
14
+
15
+ ## Install
16
+
17
+ Requires [uv](https://docs.astral.sh/uv/) (Python 3.12+ is fetched automatically).
18
+
19
+ ```sh
20
+ uv tool install cc-calendar
21
+ cc-calendar
22
+ ```
23
+
24
+ Or try it without installing: `uvx cc-calendar`. Update with `uv tool upgrade cc-calendar`.
25
+
26
+ To run it from a checkout:
27
+
28
+ ```sh
29
+ uv run cc-calendar
30
+ ```
31
+
32
+ The server binds to `127.0.0.1` on a free port and opens your browser.
33
+
34
+ | Option | Description |
35
+ | --- | --- |
36
+ | `--port N` | Listen on a specific port instead of a free one |
37
+ | `--no-browser` | Do not open a browser window |
38
+ | `--claude-dir [NAME=]PATH` | Read logs from another Claude Code config directory (default `~/.claude`). Repeat it to show several directories in one calendar |
39
+ | `--notes PATH` | File that keeps your session notes and tags (default: see [Notes and tags](https://atinfinity.github.io/cc-calendar/getting-started/#notes-and-tags)) |
40
+ | `--search-index PATH` | File that keeps the full-text search index (default: see [Full-text search](https://atinfinity.github.io/cc-calendar/features/#full-text-search)) |
41
+
42
+ ### Several config directories
43
+
44
+ Pass `--claude-dir` more than once to see sessions from several places together, such as
45
+ `~/.claude` directories synced from other machines or separate configs used with
46
+ `CLAUDE_CONFIG_DIR`. Only the directories you list are read, so include `~/.claude` to keep
47
+ your local sessions:
48
+
49
+ ```sh
50
+ cc-calendar --claude-dir ~/.claude --claude-dir ~/sync/laptop/.claude --claude-dir work=~/.claude-work
51
+ ```
52
+
53
+ Each directory gets a name: the one you give with `NAME=`, otherwise `local` for `~/.claude`, the
54
+ parent folder for a path ending in `.claude` (`laptop` above), or the folder itself. Sessions show
55
+ where they came from in the list (**Source** column and filter), the detail pane, the calendar
56
+ tooltip and the CSV/JSON export (`source`), and **Color by → Source** colors them by directory.
57
+ A session found in more than one directory is shown once, from the copy with the latest activity.
58
+
59
+ ### Notes and tags
60
+
61
+ Notes and tags you add to sessions are saved in one JSON file, keyed by session ID:
62
+
63
+ | Platform | Default location |
64
+ | --- | --- |
65
+ | macOS | `~/Library/Application Support/cc-calendar/notes.json` |
66
+ | Linux | `$XDG_DATA_HOME/cc-calendar/notes.json` (`~/.local/share/…` when unset) |
67
+ | Windows | `%APPDATA%\cc-calendar\notes.json` |
68
+
69
+ Point `--notes` at another file to keep it somewhere else, such as a synced folder to share notes
70
+ between machines; changes made to the file elsewhere are picked up. One file serves every
71
+ `--claude-dir`. Notes stay in the file after Claude Code deletes a session's old log.
72
+
73
+ ### Full-text search
74
+
75
+ Tick **Full text** next to the search box to also search what Claude wrote: assistant replies,
76
+ tool inputs (commands, file paths, edits), tool output, and subagent transcripts. Thinking is not
77
+ searched. Queries need at least 3 characters, ignore case and line breaks, and work for Japanese
78
+ and other languages without spaces. Matching sessions show a snippet of the first hit in the list,
79
+ the calendar tooltip and the detail pane; **Open ↗** opens the transcript at that hit, and
80
+ **Matches** in the transcript steps through the others.
81
+
82
+ The text is kept in a SQLite index, built in the background on first start and updated as logs
83
+ grow, so later starts only read new lines. Until it is complete, the status next to the toggle
84
+ says so and results fill in as it goes. The index is a cache and safe to delete:
85
+
86
+ | Platform | Default location |
87
+ | --- | --- |
88
+ | macOS | `~/Library/Caches/cc-calendar/search.db` |
89
+ | Linux | `$XDG_CACHE_HOME/cc-calendar/search.db` (`~/.cache/…` when unset) |
90
+ | Windows | `%LOCALAPPDATA%\cc-calendar\search.db` |
91
+
92
+ Point `--search-index` at another file to keep it elsewhere. It takes a little under half the space of
93
+ the logs it covers.
94
+
95
+ ## Features
96
+
97
+ - **Week and day calendar** — each session is drawn as bars covering its active periods; a session is
98
+ split wherever it sat idle longer than the chosen threshold (15 minutes by default). Overlapping
99
+ sessions sit side by side. Click a date in the week view to open that day on its own. Zoom with
100
+ the − / + buttons or Ctrl + mouse wheel.
101
+ - **Month and year views** — a month calendar and a GitHub-style yearly heatmap, one cell per day
102
+ shaded by active time or cost (switch with "Shade by"). Month cells list the day's busiest
103
+ projects; the year view adds per-month totals. Click a day to open it in the day view, or a
104
+ month total to open that month.
105
+ - **Time and cost totals** — each date shows that day's active time and cost, and the Summary
106
+ table breaks the displayed range down by project. Active time is the drawn bars; a session's cost
107
+ is split across days by when its requests ran. Totals follow the current filters.
108
+ - **Markdown report** — "Copy report" copies the displayed day, week, month or year as Markdown:
109
+ active time and cost per project, each session's title and tags (not notes) and the commits made in the range. Ready
110
+ to paste into a standup note or a daily report; it follows the current filters. Issue and PR
111
+ numbers such as `#12` become links to the repository's `origin` remote.
112
+ - **Tool usage** — the Tools pane aggregates tool calls in the displayed range: most used tools,
113
+ error counts and rates (10% or more is highlighted), calls made inside subagents, MCP servers,
114
+ and subagent runs by type with their tool calls, tokens and cost. It follows the current filters.
115
+ - **Cache efficiency** — each session shows its cache hit rate (cache reads as a share of input
116
+ tokens) and roughly how much caching saved. Sort the list by Cache to find sessions with poor
117
+ reuse; rates below 90% are highlighted (Claude Code usually reuses well over 90%).
118
+ - **Event marks** — marks on each bar show when prompts, commits, compactions and API errors
119
+ happened, and the tooltip counts them for that block. Click a mark (or a request or commit time
120
+ in the detail pane) to open the transcript at that point; the transcript has ‹ › buttons to step
121
+ through each kind of event. Click the key next to the legend to hide the marks.
122
+ - **Activity density** — a heat strip behind each day shows prompts and responses per 10 minutes.
123
+ - **Colors** by project, status, model, effort (the level most requests ran at), source (with
124
+ several config directories), tag (the first tag of each session) or cost
125
+ (< $1 / $1–5 / $5–20 / $20–50 / ≥ $50).
126
+ - **Effort and compactions** — the detail pane and transcript stats show the share of requests
127
+ per effort level, and each compaction shows its trigger and context size before → after
128
+ (e.g. `auto · 168k → 32k tokens`) in the mark tooltip, the transcript and the detail pane.
129
+ - **Status** — Running and Waiting for live sessions, Done or Interrupted for finished ones, with
130
+ the underlying checks (turn ended, no background work left, clean exit, working tree clean).
131
+ - **Notifications** — turn on "Notify" in the top bar to get a desktop notification when a live
132
+ session goes from Running to Waiting for your input, or ends Interrupted, while the tab is in the
133
+ background. Off by default; clicking the notification opens the session.
134
+ - **Detail pane** — tokens, cost, context usage, every request you made with the commits that
135
+ followed it, files changed, pull requests, subagents and background tasks, and links between
136
+ a session and the one it was continued in.
137
+ - **Resume** — "Copy resume command" in the detail pane copies
138
+ `cd <project dir> && claude --resume <session id>`, so you can pick a session up again from a
139
+ terminal.
140
+ - **Transcript viewer** — Markdown rendering, collapsible tool calls, optional thinking and
141
+ metadata, drill-down into subagent transcripts, and a stats panel per transcript (active time,
142
+ requests, tokens and cost by model, tool calls and errors by tool).
143
+ - **Notes and tags** — add a note and tags to a session in the detail pane to find it again
144
+ later. The note saves when you leave the box (or with ⌘/Ctrl+Enter); `Enter` or a comma adds a
145
+ tag, with suggestions from tags already in use. Tags that differ only in case count as one.
146
+ Tags show in the list (**Tags** column and filter) and the calendar tooltip, and a 📝 marks
147
+ sessions with a note. See [where they are saved](https://atinfinity.github.io/cc-calendar/getting-started/#notes-and-tags).
148
+ - **List view** with search over titles, prompts, notes and tags (a match inside a prompt or note is shown under the title), optional
149
+ [full-text search](https://atinfinity.github.io/cc-calendar/features/#full-text-search) over the whole transcripts, project and status filters, and sorting by
150
+ any column (click a header; click again to reverse). List-only filters narrow it down further
151
+ by model, git branch, source (with several config directories), tag, date range (sessions active on
152
+ any day in the range) and cost range.
153
+ - **Project page** — click a project name (in the list, the Summary table, the detail pane or the
154
+ project menu) to see the project over all time: total active time and cost, activity by month,
155
+ every session, and its commit history with links to the repository.
156
+ - **Export** — download the sessions shown in the list view as CSV or JSON, in the current filter
157
+ and sort order: start, end, active time, project, source directory, branch, status, prompts,
158
+ tokens, cost, cache hit rate, model, effort, Claude Code version, commit count, tags and note. Times are
159
+ ISO 8601 with your UTC offset. See the [export format](https://atinfinity.github.io/cc-calendar/export/).
160
+ - **Keyboard shortcuts** — `←` / `→` previous / next range, `t` today, `d` / `w` / `m` / `y` span,
161
+ `c` / `l` calendar / list, `/` search, `j` / `k` next / previous session, `Enter` open its
162
+ transcript, `Esc` close. In a transcript, `n` / `p` step through events, `]` / `[` through
163
+ prompts, and `s` / `e` toggle Stats / Expand tools. Press `?` (or click **?** in the top bar)
164
+ for the full list.
165
+ - **Views in the URL** — the address keeps the view, span, date, selected session and project
166
+ page, so reloading keeps your place, Back and Forward step through range and view changes, and
167
+ views can be bookmarked.
168
+ - **Live updates** — new log lines are picked up within a second.
169
+
170
+ | Session detail | Transcript with stats |
171
+ | --- | --- |
172
+ | ![Detail pane](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/detail.png) | ![Transcript viewer](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/transcript.png) |
173
+ | **List view** | **Month view** |
174
+ | ![List view](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/list.png) | ![Month view](https://raw.githubusercontent.com/atinfinity/cc-calendar/main/docs/images/month.png) |
175
+
176
+ Screenshots show fictional demo data.
177
+
178
+ Cost comes from Claude Code's own cost record when the session wrote one. Otherwise it is estimated
179
+ from token usage and a built-in price table, and shown with a `~` prefix.
180
+
181
+ Treat all costs as rough figures, not billing data. The price table in
182
+ `src/cc_calendar/pricing.py` uses Anthropic API list prices as of when it was last updated. It does
183
+ not know about subscription plans, discounts or price changes. Models missing from the table count
184
+ as $0, so it needs updating when new models ship.
185
+
186
+ ## Privacy
187
+
188
+ Everything stays on your machine. The server listens only on localhost, reads your logs read-only,
189
+ and makes no network requests. It writes two files: the notes file
190
+ ([Notes and tags](https://atinfinity.github.io/cc-calendar/getting-started/#notes-and-tags)), only when you add or change a note or tag, and the
191
+ [full-text search index](https://atinfinity.github.io/cc-calendar/features/#full-text-search), a cache built from your logs. Requests from other
192
+ websites cannot change either. Commit hashes that do not appear in the
193
+ logs are looked up with `git log` in the session's working directory.
194
+
195
+ ## Development
196
+
197
+ ```sh
198
+ uv sync
199
+ uv run pytest
200
+ uv run ruff check . && uv run ruff format --check .
201
+ ```
202
+
203
+ The frontend is plain HTML, CSS and ES modules in `src/cc_calendar/static/` — no build step.
204
+ Tests use synthetic logs only; never commit real transcripts.
205
+
206
+ Releases are published to PyPI by pushing a version tag; see
207
+ [Releasing](https://atinfinity.github.io/cc-calendar/development/#releasing).
208
+
209
+ The README screenshots are rendered from fictional data generated by `scripts/demo_data.py`, using
210
+ your installed Google Chrome:
211
+
212
+ ```sh
213
+ uv run --with playwright python scripts/screenshots.py
214
+ ```
215
+
216
+ The project site is built with [Zensical](https://zensical.org/) from `docs/` and `zensical.toml`,
217
+ and deployed to GitHub Pages on every push to `main`. Preview it locally:
218
+
219
+ ```sh
220
+ uv run --group docs zensical serve
221
+ ```
222
+
223
+ ## Acknowledgements
224
+
225
+ Inspired by the tool shown in [this post by @tokkyo](https://x.com/tokkyo/status/2106240136778575897).
226
+ This is an independent reimplementation and is not affiliated with the original.
227
+
228
+ ## License
229
+
230
+ MIT. Bundles [marked](https://github.com/markedjs/marked) (MIT) and
231
+ [DOMPurify](https://github.com/cure53/DOMPurify) (Apache-2.0 / MPL-2.0).
@@ -0,0 +1,65 @@
1
+ [project]
2
+ name = "cc-calendar"
3
+ version = "0.4.0"
4
+ description = "Google Calendar-style weekly view of your Claude Code sessions"
5
+ readme = "README.md"
6
+ license = "MIT"
7
+ authors = [
8
+ { name = "atinfinity", email = "dandelion1124@gmail.com" }
9
+ ]
10
+ requires-python = ">=3.12"
11
+ keywords = ["claude", "claude-code", "calendar", "sessions", "transcripts", "dashboard"]
12
+ classifiers = [
13
+ "Development Status :: 4 - Beta",
14
+ "Environment :: Web Environment",
15
+ "Framework :: FastAPI",
16
+ "Intended Audience :: Developers",
17
+ "Operating System :: MacOS",
18
+ "Operating System :: POSIX :: Linux",
19
+ "Programming Language :: Python :: 3",
20
+ "Programming Language :: Python :: 3 :: Only",
21
+ "Programming Language :: Python :: 3.12",
22
+ "Programming Language :: Python :: 3.13",
23
+ "Topic :: Software Development",
24
+ "Topic :: Utilities",
25
+ ]
26
+ dependencies = [
27
+ "fastapi>=0.142.2",
28
+ "uvicorn[standard]>=0.54.0",
29
+ "watchfiles>=1.3.0",
30
+ ]
31
+
32
+ [project.urls]
33
+ Homepage = "https://atinfinity.github.io/cc-calendar/"
34
+ Documentation = "https://atinfinity.github.io/cc-calendar/"
35
+ Repository = "https://github.com/atinfinity/cc-calendar"
36
+ Issues = "https://github.com/atinfinity/cc-calendar/issues"
37
+
38
+ [project.scripts]
39
+ cc-calendar = "cc_calendar.cli:main"
40
+
41
+ [build-system]
42
+ requires = ["hatchling"]
43
+ build-backend = "hatchling.build"
44
+
45
+ [tool.hatch.build.targets.sdist]
46
+ only-include = ["src", "README.md", "LICENSE"]
47
+
48
+ [dependency-groups]
49
+ dev = [
50
+ "httpx>=0.28.1",
51
+ "pytest>=9.1.1",
52
+ "ruff>=0.16.10",
53
+ ]
54
+ docs = [
55
+ "zensical>=0.0.67",
56
+ ]
57
+
58
+ [tool.ruff]
59
+ line-length = 100
60
+
61
+ [tool.ruff.lint]
62
+ select = ["E", "F", "I", "UP", "B"]
63
+
64
+ [tool.pytest.ini_options]
65
+ testpaths = ["tests"]
@@ -0,0 +1,9 @@
1
+ """cc-calendar: a Google Calendar-style weekly view of Claude Code sessions."""
2
+
3
+ from importlib.metadata import PackageNotFoundError, version
4
+
5
+ # The version lives in pyproject.toml only.
6
+ try:
7
+ __version__ = version("cc-calendar")
8
+ except PackageNotFoundError: # running from a source tree that was never installed
9
+ __version__ = "0+unknown"
@@ -0,0 +1,3 @@
1
+ from .cli import main
2
+
3
+ main()