Skip to content

feat(cowork): index Claude Desktop cowork (local agent mode) sessions#681

Open
Cauchon wants to merge 3 commits into
kenn-io:mainfrom
Cauchon:feat/cowork-indexing
Open

feat(cowork): index Claude Desktop cowork (local agent mode) sessions#681
Cauchon wants to merge 3 commits into
kenn-io:mainfrom
Cauchon:feat/cowork-indexing

Conversation

@Cauchon

@Cauchon Cauchon commented Jun 13, 2026

Copy link
Copy Markdown

Adds support for indexing Claude Desktop "cowork" (local agent mode) sessions, which were previously not discovered, so their conversations and statistics never showed up in Sessions/Usage.

Fixes #639.

Claude Desktop stores cowork sessions under its local-agent-mode-sessions directories — on macOS ~/Library/Application Support/Claude/local-agent-mode-sessions/<uuid>/<uuid>, with Linux and Windows equivalents. This adds a new cowork agent to the registry with its own discovery, parser, and source-file resolution, so these sessions sync into SQLite and are counted like any other agent.

What's included:

  • New cowork agent definition in the parser registry (internal/parser/types.go) with the cowork: ID prefix and per-OS default directories (internal/parser/cowork_paths.go).
  • Cowork session parser and discovery (internal/parser/cowork.go) plus tests.
  • Sync engine wiring (internal/sync/engine.go) so cowork directories are discovered and watched.
  • Frontend label so the agent renders as "Claude Cowork".

Where to look: internal/parser/cowork.go for the parsing and discovery logic, and the registry entry in internal/parser/types.go.

Limitation: the on-disk cowork format is derived from observing Claude Desktop's local-agent-mode-sessions output, so it may need updates if that format changes.

Cowork conversations were never recorded in Sessions/Usage because their
transcripts live outside ~/.claude/projects, under the Claude Desktop app
data dir at local-agent-mode-sessions/<org>/<workspace>/local_<uuid>/.claude/
projects/<enc>/<cliSessionId>.jsonl, which the Claude discovery never reaches.

Add a "cowork" agent (display name "Claude Cowork", IDPrefix "cowork:",
COWORK_DIR / cowork_dirs config) that discovers those transcripts and parses
them through the existing Claude JSONL parser, then rewrites the results into
the cowork namespace: prefixed session IDs, title from the local_<uuid>.json
metadata (falling back to the ai-title event), project from userSelectedFolders
(else "cowork"), and metadata-derived timestamps for empty transcripts. Token
usage is now counted because the transcripts are standard Claude Code JSONL with
message.usage.

Discovery walks only the org/workspace structure, skipping the heavy
local_<uuid>/ working dirs and the skills-plugin mirror. Subagent transcripts
under subagents/ are ingested too, matching Claude, so subagent drill-down works
and SubagentSessionID links resolve. The skip check folds the metadata file's
mtime into a composite mtime so title renames are re-parsed instead of skipped.
Symlinked project directories are followed only when contained within the
session dir, matching the Cursor discovery guard. Live file-watch events are
classified via ClassifyCoworkPath; full and periodic sync are Registry-driven.

Default dirs cover macOS, Linux, and Windows; Docker uses COWORK_DIR pointing at
the mounted host directory. The agent surfaces as "Claude Cowork" in the agent
directories settings, session filters, and exports.
@roborev-ci

roborev-ci Bot commented Jun 13, 2026

Copy link
Copy Markdown

roborev: Combined Review (eb14a81)

No Medium, High, or Critical findings to report.

The only reported issue was Low severity and is omitted per instructions.


Panel: ci_default_security | Synthesis: codex, 5s | Members: codex_default (codex/default, done, 7m11s), codex_security (codex/security, done, 1m0s) | Total: 8m16s

The CI lint job enforces golangci-lint's modernize checks on pull requests. The cowork metadata path helper used strings.Index plus slicing for marker detection, which is equivalent to strings.Cut and was rejected by the linter.

Use the standard helper so the parser keeps the same behavior while satisfying the pinned lint configuration.

Validation: go fmt ./...; make lint-ci; go vet ./...; go test -tags "fts5,kit_posthog_disabled" ./internal/parser
@roborev-ci

roborev-ci Bot commented Jun 14, 2026

Copy link
Copy Markdown

roborev: Combined Review (3fe6495)

Clean overall for Medium+ severity: no findings to report.

The only reported issue was Low severity, so it is omitted per instructions.


Panel: ci_default_security | Synthesis: codex, 6s | Members: codex_default (codex/default, done, 6m54s), codex_security (codex/security, done, 2m39s) | Total: 9m39s

@mariusvniekerk

Copy link
Copy Markdown
Collaborator

@wesm So one open question here is do we want to categorize cowork as different from regular claude?

Claude Desktop on Windows can run as an MSIX package, which stores app data under AppData/Local/Packages/Claude_pzs8sxrjxfjjc/LocalCache/Roaming instead of the older AppData/Roaming location. Without that default, cowork discovery misses sessions for the current packaged desktop app unless users configure the path manually.

Keep the older Roaming path as a fallback for non-MSIX or legacy installs while trying the package-local path by default too.

Validation: go fmt ./...; go test -tags "fts5,kit_posthog_disabled" ./internal/parser -run TestCoworkDefaultDirs -count=1; go test -tags "fts5,kit_posthog_disabled" ./internal/parser; go vet ./...; make lint-ci
@roborev-ci

roborev-ci Bot commented Jun 14, 2026

Copy link
Copy Markdown

roborev: Combined Review (e1ef89f)

Summary verdict: Changes need follow-up before merge due to Cowork watcher and metadata mtime correctness issues.

Medium

  • Location: internal/parser/types.go:91

  • Problem: Cowork is registered for recursive watching, but its session dirs contain large local_* working trees that discovery deliberately skips. Startup can recurse into .claude/outputs trees, exhaust the watch budget, and leave later agent roots unwatched.

  • Fix: Add a Cowork-specific watch strategy that skips local_* payload dirs while still catching metadata changes, or make Cowork shallow/poll-based with tests for watcher behavior.

  • Location: internal/sync/engine.go:2432

  • Problem: Cowork metadata mtime is not used by SyncAllSince filtering or SourceMtime, so metadata-only changes or late metadata arrival can be skipped outside the direct SyncPaths path.

  • Fix: Use parser.CoworkSessionMtime in discoveredFileMtime and SourceMtime, with tests mirroring the Command Code metadata mtime coverage.


Panel: ci_default_security | Synthesis: codex, 9s | Members: codex_default (codex/default, done, 9m26s), codex_security (codex/security, done, 1m58s) | Total: 11m33s

@mariusvniekerk mariusvniekerk requested a review from wesm June 15, 2026 00:38
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Development

Successfully merging this pull request may close these issues.

cowork conversation statistics are missing / not counted

2 participants