{"id":50356721,"url":"https://github.com/varunkumar/claudebox","last_synced_at":"2026-05-29T23:04:04.793Z","repository":{"id":357284311,"uuid":"1235870162","full_name":"varunkumar/claudebox","owner":"varunkumar","description":"Claude in a box","archived":false,"fork":false,"pushed_at":"2026-05-12T04:56:26.000Z","size":52,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-05-12T06:35:03.650Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/varunkumar.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-11T18:27:22.000Z","updated_at":"2026-05-12T04:56:29.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/varunkumar/claudebox","commit_stats":null,"previous_names":["varunkumar/claudebox"],"tags_count":null,"template":false,"template_full_name":null,"purl":"pkg:github/varunkumar/claudebox","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunkumar%2Fclaudebox","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunkumar%2Fclaudebox/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunkumar%2Fclaudebox/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunkumar%2Fclaudebox/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/varunkumar","download_url":"https://codeload.github.com/varunkumar/claudebox/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/varunkumar%2Fclaudebox/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":33673654,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-05-29T02:00:06.066Z","response_time":107,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2026-05-29T23:04:03.731Z","updated_at":"2026-05-29T23:04:04.786Z","avatar_url":"https://github.com/varunkumar.png","language":"Python","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ClaudeBox\n\nClaudeBox is a physical ambient dashboard that displays Claude Code session status on a UNIHIKER K10 sitting on your desk. It shows real-time session activity, token usage, mood via RGB LEDs, environmental sensor data, and lets you approve or deny Bash commands with a physical touch UI.\n\n## How It Works\n\n```\nClaude Code sessions (iTerm2 tabs)\n        |\n        |  fires hooks via ~/.claude/settings.json\n        v\nhook.py  (thin HTTP client, no state)\n        |\n        |  POST localhost:8081/hook   (non-blocking for most hooks)\n        |  POST localhost:8081/hook   (blocking for PermissionRequest)\n        v\nserver.py  (single process, port 8081)\n  |-- HTTP server thread     receives /hook, /focus, /decision\n  |-- Scanner thread         reads JSONL logs every 30s, updates token counts\n  |-- Broadcaster thread     pulls sensors, computes mood, pushes to K10\n  |-- Approval queue         serializes PermissionRequest per session\n  +-- state.json             shared state, thread-safe\n\nfocus_monitor.py  (separate process)\n  +-- iTerm2 FocusMonitor    fires on tab switch\n        |  POST localhost:8081/focus\n        v  server.py records which session is active\n\n                        WiFi\nserver.py broadcaster \u003c-------\u003e K10 (port 8080)\n  GET  k10:8080/sensors           POST /update   refresh display + RGB LEDs\n  POST k10:8080/update            POST /approve  show Y/N touch UI\n  POST k10:8080/approve           GET  /sensors  return sensor readings\n                                  POST mac:8081/decision  (user tapped Y/N)\n```\n\nClaude Code hooks post events to a Mac daemon (`server.py`) over HTTP. The daemon tracks active sessions, scans JSONL logs for token usage, and pushes status updates to the K10 over WiFi. The K10 renders a dashboard on its display, drives RGB mood LEDs, and hosts an approval UI for Bash commands. iTerm2's FocusMonitor determines which session is \"active\": only the focused terminal tab routes approval requests to the device.\n\n## Hardware\n\n**Required:**\n- UNIHIKER K10 (touch display, WiFi, AHT20 temp/humidity, LTR303 light sensor, WS2812 LEDs)\n\n**Coming soon:**\n- Cardputer Adv\n\n## Setup\n\n### 1. Router\n\nGive the K10 a static IP via DHCP reservation in your router settings. You'll need this IP in the next step.\n\n### 2. Mac: Configuration\n\n```bash\ncp config.example.py mac/config.py\n```\n\nEdit `mac/config.py`:\n- Set `K10_IP` to the K10's static IP\n- Adjust `APPROVAL_REQUIRED` / `AUTO_ALLOW` tool lists as needed\n\n`mac/config.py` is gitignored. Never commit credentials or IPs.\n\n### 3. Mac: Hook\n\n```bash\nmkdir -p ~/.claudebox\ncp hook.py ~/.claudebox/hook.py\n```\n\nCopy `.claude/settings.json` to `~/.claude/settings.json` (or merge the `hooks` block if you have an existing settings file). This wires up Claude Code to call the hook on every session event.\n\n### 4. Mac: iTerm2 Focus Monitor\n\nOpen iTerm2 \u003e Scripts menu \u003e Manage \u003e Install Python Runtime (one-time).\n\nThe focus monitor tracks which terminal tab is active so the approval gate routes to the right session.\n\n### 5. K10: Firmware\n\nInstall esptool:\n\n```bash\npip install esptool\n```\n\nBack up the factory firmware (optional but recommended):\n\n```bash\nesptool.py --port /dev/tty.usbmodem83301 \\\n           --baud 921600 \\\n           read_flash 0x0 0x1000000 k10_factory_backup.bin\n```\n\nErase flash, then write the MicroPython image:\n\n```bash\nesptool.py --port /dev/tty.usbmodem83301 \\\n           --baud 921600 \\\n           erase_flash\n\nesptool.py --port /dev/tty.usbmodem83301 \\\n           --baud 921600 \\\n           write_flash -z 0x0 unihiker_k10_micropython.bin\n```\n\nThe port name (`/dev/tty.usbmodem83301`) varies - check `ls /dev/tty.usbmodem*` after plugging in the K10 via USB. Download the MicroPython `.bin` for the K10 from the [UNIHIKER K10 documentation](https://wiki.unihiker.com).\n\n### 6. K10: Configuration\n\n```bash\ncp k10/device/secrets_example.py k10/device/secrets.py\n```\n\nEdit `k10/device/secrets.py` with your WiFi SSID and password.\n\nEdit `k10/device/config.py`:\n- Set `MAC_HOST` to your Mac's local IP address.\n- Set `TZ_OFFSET_S` to your UTC offset in seconds (e.g. IST = `19800` for UTC+5:30, EST = `-18000` for UTC-5). This is applied to the UTC clock synced from NTP on boot.\n\n`secrets.py` is gitignored. Never commit WiFi credentials.\n\n### 7. K10: Deploy\n\nSync the `k10/device/` directory to the K10 using the Pymakr VS Code extension or `mpremote`.\n\n## Running\n\nStart both Mac daemons (separate terminal windows):\n\n```bash\n# Terminal 1: main server\npython3 mac/server.py\n\n# Terminal 2: iTerm2 focus tracker\npython3 mac/focus_monitor.py\n```\n\nThe K10 boots automatically and connects to the Mac. Session status appears on the display within a few seconds of starting a Claude Code session.\n\n## Approval Gate\n\nWhen Claude Code requests permission to run a Bash command, a full-screen prompt appears on the K10 with a countdown timer. Tap **YES** or **NO** on the touch display. If no response within 60 seconds, the command falls back to Claude Code's built-in CLI approval prompt.\n\nOnly the iTerm2 tab that currently has focus routes to the device. Background sessions always fall back to the CLI prompt immediately.\n\n## Mood System\n\nRGB LEDs reflect session intensity based on cumulative token usage:\n\n| Mood     | LED color  | Condition                         |\n|----------|------------|-----------------------------------|\n| sleeping | dim white  | No active session / idle \u003e10 min  |\n| happy    | green      | \u003c20% of session budget used       |\n| neutral  | blue       | 20-50%                            |\n| tired    | amber      | 50-75%                            |\n| stressed | red        | \u003e75%                              |\n\nTune `SESSION_TYPICAL_MAX` in `mac/config.py` to calibrate the thresholds to your typical session size.\n\n## Usage Bars\n\nThe display shows two progress bars for API rate-limit headroom. Both bars shift color as usage climbs:\n\n| Range  | Color  |\n|--------|--------|\n| 0-30%  | Green  |\n| 30-60% | Yellow |\n| 60-90% | Orange |\n| 90%+   | Red    |\n\n- **Session bar** - 5-hour rolling usage window\n- **Week bar** - 7-day rolling usage window\n\n## Project Layout\n\n```\nmac/           Mac daemon: server, scanner, mood, focus monitor\nk10/device/    K10 MicroPython firmware: display, sensors, RGB, approval\nhook.py        Claude Code hook (install to ~/.claudebox/)\nconfig.example.py  Config template (copy to mac/config.py)\n.claude/settings.json  Hook wiring for Claude Code\ntests/         Mac-side test suite (pytest)\ndocs/          Design specs and implementation plans\n```\n\n## Development\n\n```bash\n# Run tests\npython -m pytest tests/ -v\n\n# Tests cover: state persistence, token scanning, mood thresholds,\n# hook ingestion, broadcaster, and full approval round-trips.\n```\n\nK10 firmware is MicroPython with no CPython test suite. Validate sensor reads and display layout on the device directly.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvarunkumar%2Fclaudebox","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fvarunkumar%2Fclaudebox","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fvarunkumar%2Fclaudebox/lists"}