Skip to content

feat: workspace / team mode -- multi-machine usage tracking (shared SQLite or Postgres)#41

Open
jakduch wants to merge 2 commits into
josepe98:mainfrom
jakduch:feat/workspace-mode
Open

feat: workspace / team mode -- multi-machine usage tracking (shared SQLite or Postgres)#41
jakduch wants to merge 2 commits into
josepe98:mainfrom
jakduch:feat/workspace-mode

Conversation

@jakduch
Copy link
Copy Markdown
Collaborator

@jakduch jakduch commented May 23, 2026

What does this add and why do you believe it belongs in this dashboard?

This adds an opt-in workspace / team mode so the same dashboard can roll up usage from more than one machine -- either via a shared SQLite file on a network drive (Dropbox, NFS, SMB) or via a shared Postgres instance. Configuration lives in ~/.claude/workspace.json (or env vars CLAUDE_USAGE_BACKEND, CLAUDE_USAGE_PG, CLAUDE_USAGE_MACHINE_ID, CLAUDE_USAGE_TEAM); when no config exists, behavior is byte-identical to the single-machine SQLite default, so existing users see zero change.

The case for a personal dashboard: a growing number of solo developers run Claude Code from a laptop and a desktop and a remote dev box, and the per-machine ~/.claude/usage.db fragments the picture. Small teams sharing a single Anthropic plan have the same shape of problem at the next zoom level -- they need aggregate visibility into how the shared quota is being consumed before someone hits the cap mid-week. The same machine_id-stamped schema and the same dashboard solve both cases. The UI gains a single optional "filter by machine" dropdown that stays hidden when only one machine is present, so single-machine users are never asked to think about it.

Checklist

Code correctness

  • All calcCost() calls pass 6 arguments: (model, inp, out, cache_read, cache_creation, cache_1h) -- no calcCost() calls added or modified in this PR
  • JavaScript template literals use bare backticks, not escaped ones -- verified in PR-added JS
  • No JS variables referenced before they are defined
  • No new third-party dependencies introduced (psycopg2 is imported lazily inside the Postgres code path with a friendly error; stdlib-only otherwise)

Tests

  • python3 -m unittest discover -s tests -v -- all passing (212 tests, 1 skipped: psycopg2 not installed locally)
  • python3 -m unittest tests.test_browser -v -- all passing (6 tests)
  • New behaviour is covered by at least one test (tests/test_workspace.py, 28 new tests covering config defaults, env overrides, schema migration, machine_id stamping, dashboard rollups, filter UI, and lazy psycopg2 import)

Scope

  • This is a single concern -- one feature or fix per PR
  • Only touches existing files (dashboard.py, scanner.py, cli.py, pricing.py, cowork.py, tests/) -- or I have explained below why a new file is needed

workspace.py is added as a new module because the configuration loader, env-var precedence rules, machine-id resolution, and lazy Postgres connection helper are a self-contained concern with their own test surface; folding them into scanner.py or dashboard.py would have mixed transport/config concerns with scanning and rendering, and the team-mode code path needs to be importable from both. tests/test_workspace.py follows the existing one-test-file-per-module convention.

@jakduch jakduch force-pushed the feat/workspace-mode branch from 19e9f91 to ae05812 Compare May 24, 2026 19:26
@josepe98 josepe98 closed this May 25, 2026
@josepe98 josepe98 reopened this May 25, 2026
@josepe98 josepe98 closed this May 25, 2026
@josepe98 josepe98 reopened this May 25, 2026
@josepe98 josepe98 closed this May 25, 2026
@josepe98 josepe98 reopened this May 25, 2026
@josepe98 josepe98 closed this May 25, 2026
@josepe98 josepe98 reopened this May 25, 2026
@jakduch jakduch force-pushed the feat/workspace-mode branch 2 times, most recently from a28341f to 3003d2f Compare May 26, 2026 20:39
jakduch added 2 commits May 26, 2026 22:48
Adds an opt-in shared-database mode so multiple developers can roll up
Claude Code usage across a team. Two backends:

- Shared SQLite (db_path on Dropbox / NFS / SMB)
- Postgres (psycopg2-binary is an optional, lazy-imported dep)

Schema: machine_id column added to turns + sessions tables via an
idempotent migration -- existing single-machine databases upgrade in
place on first scan.

Dashboard: /api/data payload gains by_machine aggregation and
all_machines list; a Machine filter dropdown is rendered but kept
display:none until JS detects more than one machine has reported in,
so single-laptop installs see no UI change.

Config: ~/.claude/workspace.json (backend, machine_id, team, optional
db_path, optional pg_dsn). Env vars (CLAUDE_USAGE_BACKEND,
CLAUDE_USAGE_PG, CLAUDE_USAGE_MACHINE_ID, CLAUDE_USAGE_TEAM) override
the file for CI / Docker workflows.

Backward compat: if no workspace.json exists, behavior is identical to
today's single-machine SQLite default.

Tests: 22 new in tests/test_workspace.py covering config defaults, env
overrides, lazy psycopg2 import, migration idempotency, pre-feature DB
upgrade, machine_id stamping, by_machine payload aggregation, and UI
HTML hooks. Full suite: 212 pass, 7 skipped.
@jakduch jakduch force-pushed the feat/workspace-mode branch from 3003d2f to 71e6fd8 Compare May 26, 2026 20:49
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants