Skip to content

cloudprobe/debrief

debrief

What I decided, shipped, and investigated today — synthesized from git + Claude Code sessions, locally.

CI Coverage Go Report Card Latest Release License: MIT


Important

100% local. Zero network calls. debrief reads your git history and Claude Code session files directly from disk. Nothing leaves your machine — no API calls, no logins, no cloud.


💡 Why debrief?

Most tools list your commits. debrief tells you what you decided, shipped, investigated, and what to watch — classified from git history and the context buried in your Claude Code session logs.

  • Your decisions and discoveries live in .jsonl session files you never reread. debrief mines them.
  • git log is a timeline, not a standup. debrief groups work by intent, not by timestamp.
  • Everything runs locally: no API calls, no logins, no cloud.

Also tracks Claude API cost across direct API, Max/Pro, Vertex, and Bedrock.


🚀 Install

brew install cloudprobe/tap/debrief

Or with Go:

go install github.com/cloudprobe/debrief/cmd/debrief@latest

Setup

debrief init

Choose your Claude Code access type. Config is written to ~/.config/debrief/config.yaml.


📋 Output samples

debrief standup — grouped by intent, not timestamp:

Fri, Apr 18 2026

Decided
  - Dropped the Slack webhook path — too much scope for v1
  - Went with go-yaml over mapstructure for config parsing

Shipped
  - Redesigned the cost table with per-model breakdown (#12)
  - Added --project filter to standup and cost commands

Investigated
  - goreleaser's default matrix skips arm64 Linux — had to add it explicitly

Watch
  - The classifier regex is too aggressive on test: prefixes and drops real work

Empty sections are skipped. A day of only chore commits prints Quiet day — just chores and lints. Nothing shipped worth writing up. so you can tell the tool worked, the day was just quiet.

Below the output (on stderr, so it's not copied or piped), debrief prints a one-line status so you always know what mode you're in:

  • -- humanized via claude-code (disable: --no-humanize) — bullets were rewritten via the local claude CLI.
  • -- raw output — install the claude CLI for humanized bulletsclaude isn't on PATH.
  • -- raw output (--no-humanize set) — you opted out explicitly.

debrief standup --format slack — flat bullets for pasting:

`Fri, Apr 18 2026`

- Dropped the Slack webhook path — too much scope for v1
- Went with go-yaml over mapstructure for config parsing
- Redesigned the cost table with per-model breakdown (#12)
- goreleaser's default matrix skips arm64 Linux — had to add it explicitly

debrief cost week — per-model cost breakdown:

┌────────────┬──────────────────────────┬────────────┐
│ Date       │ Model                    │ Cost (USD) │
├────────────┼──────────────────────────┼────────────┤
│ 2026-04-06 │ opus 4.6                 │     $3.21  │
│            │ sonnet 4.6               │     $0.84  │
│            │ subtotal                 │     $4.05  │
├────────────┼──────────────────────────┼────────────┤
│ 2026-04-07 │ sonnet 4.6               │     $1.12  │
├────────────┼──────────────────────────┼────────────┤
│ grand total│                          │     $5.17  │
└────────────┴──────────────────────────┴────────────┘

🛠 Commands

Command Args Description
debrief init Interactive setup wizard
debrief standup today yesterday week month -d YYYY-MM-DD Standup summary from commits + AI sessions
debrief cost today yesterday week month -d YYYY-MM-DD Estimated API cost with per-model breakdown
debrief log "message" / --list Record or list journal entries
debrief version Print version
All flags
Flag Commands Description
--format standup Output format: text (default) or slack
--copy standup, cost Copy output to clipboard
--project, -p standup, cost Filter to repos matching substring
--date, -d all Override date (YYYY-MM-DD)

⚙️ Configuration

~/.config/debrief/config.yaml (respects $XDG_CONFIG_HOME):

git_repo_paths:
  - ~/work
  - ~/projects
  - ~/code
git_discovery_depth: 2        # how deep to scan for git repos
# If every configured path is missing or empty, debrief falls back to
# scanning the current directory (including CWD itself if it's a repo)
# and prints a one-line note telling you what it scanned.

pricing:
  preset: direct              # direct | max | vertex | bedrock
  overrides:
    claude-opus-4-5:
      input_per_million: 15.0
      output_per_million: 75.0

# optional overrides for AI session paths
claude_dir: ~/.claude/projects
codex_dir: ~/.codex/sessions
gemini_dir: ~/.gemini/tmp

🔒 How it works

flowchart LR
    A[git log] --> C[classifier]
    B["~/.claude/*.jsonl"] --> C
    D["debrief log entries"] --> C
    C --> E[Decided]
    C --> F[Shipped]
    C --> G[Investigated]
    C --> H[Watch]
    E & F & G & H --> I[output]
Loading

The local classifier runs entirely in-process — no model calls, no network.

Commit signal rules:

Commit shape Bucket
feat, fix, perf, refactor, build, ci Shipped
docs with substantive body Shipped
chore, test with a (#N) PR-squash suffix + substantive body Shipped (merged via review)
other chore, test, short docs Skipped as noise
any non-conventional prefix Shipped (fallback)
Merge pull request / Merge branch Shipped

Session note signal rules:

Keyword pattern Bucket
"decided", "went with", "chose", "switched to", "picked" Decided
"found", "discovered", "ruled out", "investigated", "turns out" Investigated
"risk", "concern", "watch out" Watch
everything else that survives quality filters Shipped

Output order is always: Decided → Shipped → Investigated → Watch. Empty sections are omitted.


📖 debrief log

debrief log lets you record short journal entries during the day that feed directly into the classifier.

# record an entry
debrief log "decided to use gRPC instead of REST"
debrief log "found that squash commits bypass prefix filter"
debrief log "concern: migration could break existing configs"

# review today's entries
debrief log --list

Entries are stored locally and appear in your next standup summary alongside commits and session notes. Writing entries in natural language ("decided to...", "found that...", "concern: ...") ensures they land in the right classifier bucket.


FAQ

Does debrief send any data to the internet?

No. It reads only from your local filesystem: git log output, ~/.claude/projects/*.jsonl session files, and debrief log entries. No network calls are made at any point.

What Claude access types are supported for cost tracking?

Direct API, Max/Pro subscription, Vertex AI, and Amazon Bedrock. Set your type with debrief init or manually in config.yaml under pricing.preset.

Why are some commits not showing up in standup?

chore and test commits are filtered as noise by default. Short docs commits are too. But if a chore(lint): ... (#42) went through a PR and has a meaningful message, it's treated as shipped — the PR-squash suffix + substantive body combo is evidence the work was reviewed and merged. If a day ends up with only filtered commits, you'll see Quiet day — just chores and lints rather than the tool looking broken. Use debrief log to surface anything the filter drops.

The cost table shows $0.00 for some models — is that correct?

Zero-cost entries are filtered from the table automatically. If a model shows up with no cost (e.g. Max/Pro subscription models), it will not appear in the cost output.

debrief standup dsad returned an error — is that expected?

Yes. Unknown time-range arguments are rejected with an error listing the allowed values (today, yesterday, week, month, -d YYYY-MM-DD).


License

MIT — see LICENSE.

About

Know what you actually did today — git commits, AI sessions, one command

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors