From 361e49ca93eb51c5f7da1739e95d37fdf3d5a64f Mon Sep 17 00:00:00 2001 From: Kelvis Artigas <9992885+sivlek14@users.noreply.github.com> Date: Fri, 8 May 2026 00:12:34 -0400 Subject: [PATCH 1/2] feat: add Docker support with compose Adds Dockerfile, compose.yaml, and .dockerignore so the dashboard can be served with `docker compose up -d`. The container bind-mounts ~/.claude so the SQLite DB at ~/.claude/usage.db persists on the host and CLI commands keep working alongside the running server. README updated with Docker quick-start and docker compose run examples. tests/test_docker_setup.py adds static stdlib-only checks for the Dockerfile base image, exposed port, and ~/.claude mount. Co-Authored-By: Claude Sonnet 4.6 --- .dockerignore | 11 +++++++++++ Dockerfile | 14 ++++++++++++++ README.md | 18 ++++++++++++++++++ compose.yaml | 12 ++++++++++++ tests/test_docker_setup.py | 29 +++++++++++++++++++++++++++++ 5 files changed, 84 insertions(+) create mode 100644 .dockerignore create mode 100644 Dockerfile create mode 100644 compose.yaml create mode 100644 tests/test_docker_setup.py diff --git a/.dockerignore b/.dockerignore new file mode 100644 index 0000000..bc2b812 --- /dev/null +++ b/.dockerignore @@ -0,0 +1,11 @@ +.git/ +.github/ +.claude/ +tests/ +docs/ +*.md +LICENSE +__pycache__/ +*.pyc +.DS_Store +server.log diff --git a/Dockerfile b/Dockerfile new file mode 100644 index 0000000..562cba1 --- /dev/null +++ b/Dockerfile @@ -0,0 +1,14 @@ +FROM python:3.12-slim + +WORKDIR /app +COPY cli.py dashboard.py scanner.py ./ + +ENV HOST=0.0.0.0 \ + PORT=8080 \ + PYTHONUNBUFFERED=1 + +EXPOSE 8080 + +# Run scan once at startup, then serve. Bypasses cli.py:cmd_dashboard +# to avoid the webbrowser.open call (irrelevant inside a container). +CMD ["python3", "-c", "from scanner import scan; scan(); from dashboard import serve; serve()"] diff --git a/README.md b/README.md index cc3d0a8..5c2c2f6 100644 --- a/README.md +++ b/README.md @@ -52,6 +52,24 @@ cd claude-usage python3 cli.py dashboard ``` +### Docker + +```bash +docker compose up -d +# Open http://localhost:8080 +``` + +Mounts `~/.claude` into the container, so the SQLite DB at `~/.claude/usage.db` +persists on the host and CLI commands (`python3 cli.py today`) keep working +alongside the container. + +To run single-shot CLI commands without starting the server: + +```bash +docker compose run --rm claude-usage python3 cli.py today +docker compose run --rm claude-usage python3 cli.py stats +``` + --- ## Usage diff --git a/compose.yaml b/compose.yaml new file mode 100644 index 0000000..7ffba00 --- /dev/null +++ b/compose.yaml @@ -0,0 +1,12 @@ +services: + claude-usage: + build: . + container_name: claude-usage + ports: + - "8080:8080" + volumes: + # JSONL logs (read) + usage.db (read/write) + - ${HOME}/.claude:/root/.claude + # Optional: Xcode Claude integration logs (macOS only) + # - ${HOME}/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/projects:/root/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/projects:ro + restart: unless-stopped diff --git a/tests/test_docker_setup.py b/tests/test_docker_setup.py new file mode 100644 index 0000000..83104f7 --- /dev/null +++ b/tests/test_docker_setup.py @@ -0,0 +1,29 @@ +"""Static checks for Docker setup (no docker build required — stdlib only).""" + +import re +import unittest +from pathlib import Path + +ROOT = Path(__file__).resolve().parent.parent + + +class TestDockerSetup(unittest.TestCase): + def test_dockerfile_exists_and_uses_python(self): + df = (ROOT / "Dockerfile").read_text() + self.assertRegex(df, r"(?m)^FROM\s+python:", + "Dockerfile must use a Python base image") + + def test_compose_exposes_dashboard_port(self): + compose = (ROOT / "compose.yaml").read_text() + self.assertIn("8080", compose) + + def test_compose_mounts_claude_home(self): + compose = (ROOT / "compose.yaml").read_text() + self.assertTrue( + re.search(r"(~|\$HOME|\$\{HOME\})/\.claude", compose), + f"compose.yaml must bind-mount ~/.claude; got:\n{compose}", + ) + + +if __name__ == "__main__": + unittest.main() From 6aed15cff6fb1831eb244c325506215d806fa2be Mon Sep 17 00:00:00 2001 From: Kelvis Artigas <9992885+sivlek14@users.noreply.github.com> Date: Fri, 8 May 2026 01:30:08 -0400 Subject: [PATCH 2/2] Potential fix for pull request finding Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com> --- compose.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compose.yaml b/compose.yaml index 7ffba00..69dae1c 100644 --- a/compose.yaml +++ b/compose.yaml @@ -6,7 +6,7 @@ services: - "8080:8080" volumes: # JSONL logs (read) + usage.db (read/write) - - ${HOME}/.claude:/root/.claude + - ${HOME:?HOME must be set}/.claude:/root/.claude # Optional: Xcode Claude integration logs (macOS only) # - ${HOME}/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/projects:/root/Library/Developer/Xcode/CodingAssistant/ClaudeAgentConfig/projects:ro restart: unless-stopped