Skip to content

feat: inbound webhook receiver + /api/inbound endpoint#49

Open
jakduch wants to merge 5 commits into
josepe98:mainfrom
jakduch:feat/inbound-webhooks
Open

feat: inbound webhook receiver + /api/inbound endpoint#49
jakduch wants to merge 5 commits into
josepe98:mainfrom
jakduch:feat/inbound-webhooks

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?

A Claude Code usage dashboard is great at answering "what did I spend?" but
it can't answer "why?" — the spikes, the regressions, the unexpectedly
cheap days — without context from the systems that actually triggered the
work. This PR adds a tiny inbound webhook receiver at POST /api/inbound/<event_type> plus a viewer card and a cli.py inbound
command, so any external system can drop a small JSON note into your
personal log and have it show up next to the spend timeline.

The intended callers are exactly the things you already run: CI builds
(green/red + duration), GitHub events (PR opened, merged, reverted),
deploy hooks, or hand-rolled annotations like "started refactor X" from a
git pre-commit. The endpoint is intentionally schema-free — it stores
arbitrary payloads in ~/.claude/inbound.jsonl with envelope metadata
(type, timestamp, source IP) — because the dashboard's job is correlation,
not modeling. An optional shared secret in ~/.claude/inbound-config.json
gates writes when the dashboard is exposed beyond localhost. No new
dependencies; ~250 lines of tests cover auth, rotation, malformed input,
and the CLI tail.

Checklist

Code correctness

  • All calcCost() calls pass 6 arguments: (model, inp, out, cache_read, cache_creation, cache_1h)
  • JavaScript template literals use bare backticks (`), not escaped ones (\`)
  • No JS variables referenced before they are defined
  • No new third-party dependencies introduced

Tests

  • python3 -m unittest discover -s tests -v — all passing
  • python3 -m unittest tests.test_browser -v — all passing
  • New behaviour is covered by at least one test

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've explained below why a new file is needed

tests/test_inbound.py is a new file: it exercises a new endpoint family
(/api/inbound, /api/inbound/<type>) and the new CLI subcommand, so it
belongs in its own module rather than bolted onto an existing test file.

jakduch added 2 commits May 23, 2026 20:49
- POST /api/inbound/<event_type> appends JSON to ~/.claude/inbound.jsonl
  with a {type, received_at, source_ip, payload} envelope.
- GET /api/inbound?limit=N returns recent events (newest first).
- Optional shared-secret via X-Inbound-Secret header, configured in
  ~/.claude/inbound-config.json; mismatched/missing secret returns 403.
- 10MB log rotation -> .jsonl.1 (single generation, capped at ~20MB).
- Dashboard 'Recent inbound events' collapsible card (last 10).
- CLI 'python3 cli.py inbound [--tail N]' for terminal viewing.
- 12 tests in tests/test_inbound.py covering auth, GET ordering/limit,
  rotation, unknown event types, and the CLI command.
@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
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