Firewatch
Query, filter, and act on GitHub PR activity using the Firewatch CLI (fw).
Quick Start
fw --refresh --summary --open # Sync and see what needs attention
fw --type comment --pr 42 # Comments on PR #42
fw --type comment | jq 'select(.author != .pr_author)' # External feedback only
Core Concepts
JSONL Output
Firewatch outputs one JSON object per line. Each entry is denormalized — it contains full PR context (title, state, author, labels) so you never need joins.
fw --type comment --limit 1
{
"id": "IC_kwDOK...",
"type": "comment",
"subtype": "review_comment",
"author": "alice",
"body": "Consider adding error handling here",
"file": "src/auth.ts",
"line": 42,
"pr": 123,
"pr_title": "Add user authentication",
"pr_state": "open",
"pr_author": "bob",
"created_at": "2025-01-14T10:00:00Z"
}
Entry Types
| Type | Subtype | Meaning |
|---|---|---|
comment |
review_comment |
Inline code comment (actionable) |
comment |
issue_comment |
General PR comment |
review |
— | Review submission (approve/request changes) |
commit |
— | Commit pushed to PR branch |
ci |
— | CI/CD status check |
event |
— | Lifecycle event (opened, closed, merged) |
Querying
Filter Flags
fw --type comment # By type
fw --since 24h # By time (30s, 5m, 24h, 7d, 2w, 1mo)
fw --pr 42 # By PR number
fw --author alice # By author
fw --open # Open PRs only
fw --active # Open or draft PRs
fw --mine # PRs assigned to me
fw --reviews # PRs I need to review
Combine filters (AND logic):
fw --type review --author alice --since 7d --open
Aggregation
Per-PR summary instead of individual entries:
fw --summary --open
Composing with jq
CLI filters handle common cases; jq handles everything else:
# Only approved reviews
fw --type review | jq 'select(.state == "approved")'
# Comments mentioning "TODO"
fw --type comment | jq 'select(.body | test("TODO"; "i"))'
# External feedback (not self-comments)
fw --type comment | jq 'select(.author != .pr_author)'
# Count by type
fw | jq -s 'group_by(.type) | map({type: .[0].type, count: length})'
Tip: Use CLI filters first, then jq. CLI filters are faster because they skip JSON parsing for non-matching entries.
See references/jq-cookbook.md for more patterns.
Taking Action
Post a Comment
fw add 42 "LGTM, merging!"
Reply to a Review Comment
Every comment entry has an id field:
fw add 42 "Fixed in latest commit" --reply IC_kwDOK...
Reply and Resolve
fw add 42 "Done" --reply IC_kwDOK... --resolve
Resolve Without Replying
fw close IC_kwDOK...
Resolve multiple threads:
fw close IC_abc IC_def IC_ghi
Staleness Tracking
Review comments can become stale when the file is modified. Run fw check to populate staleness data:
fw check
Then query for unaddressed comments:
fw --type comment | jq 'select(.file_activity_after.modified == false)'
The file_activity_after field shows:
modified— Whether file was changed after the commentcommits_touching_file— How many commits touched the filelatest_commit— SHA of the most recent commit to the file
Graphite Stack Support
Firewatch integrates with Graphite for stack-aware queries. When syncing in a repo with Graphite stacks, entries include stack metadata:
fw --refresh # Auto-detects Graphite stacks
Stack Fields
Entries gain a graphite object:
{
"graphite": {
"stack_id": "abc123",
"stack_position": 2,
"stack_size": 4,
"parent_pr": 101
}
}
stack_position— 1 is the base (closest to main), higher = further upfile_provenance— Which PR in the stack introduced each file
Quick Stack Queries
# All entries with stack metadata
fw | jq 'select(.graphite != null)'
# Base PRs only (bottom of stack)
fw --summary | jq 'select(.graphite.stack_position == 1)'
# Comments where file originated in a different PR
fw --type comment | jq 'select(.file_provenance.origin_pr != .pr)'
Stack Workflows
For detailed Graphite workflows (querying stacks, cross-PR fixes, commit patterns):
- graphite/stack-queries.md — Querying stack data
- graphite/cross-pr-fixes.md — File provenance and fixing in the right PR
- graphite/commit-workflow.md —
gt modifyvsgt amend -a
Command Reference
| Command | Purpose |
|---|---|
fw [options] |
Query cached entries (auto-syncs if stale) |
fw --refresh |
Force sync before query |
fw --summary |
Aggregate into per-PR summaries |
fw add <pr> [body] |
Post a comment or add metadata |
fw close <id>... |
Resolve review threads |
fw check |
Refresh staleness hints |
fw status |
Firewatch state info |
fw doctor |
Diagnose auth/cache/repo issues |
fw schema <type> |
Print JSON schema |
Query Options
| Option | Description |
|---|---|
--type <type> |
Filter by entry type |
--since <duration> |
Time filter (24h, 7d, etc.) |
--pr <numbers> |
Filter by PR number(s) |
--author <name> |
Filter by author |
--open |
Open PRs only |
--active |
Open or draft PRs |
--mine |
PRs assigned to me |
--reviews |
PRs I need to review |
--summary |
Aggregate to per-PR summary |
Add Options
| Option | Description |
|---|---|
--reply <id> |
Reply to a specific comment |
--resolve |
Resolve the thread after posting |
--review <type> |
Add review (approve, request-changes, comment) |
--label <name> |
Add label (repeatable) |
Patterns
- patterns/daily-standup.md — Morning PR review workflow
- patterns/implementing-feedback.md — Systematic feedback resolution
- patterns/resolving-threads.md — Reply and resolve patterns
References
- references/entry-schema.md — FirewatchEntry field reference
- references/jq-cookbook.md — Common jq filters
- references/query-patterns.md — Query combinations
- references/troubleshooting.md — Common issues and fixes
Agent Tips
- CLI filters first, then jq — More efficient than jq-only filtering
- Denormalized = no joins — Each entry has full PR context
- Entry IDs for actions — Use
idfield with--replyandfw close - Run
fw checkfor staleness — Populatesfile_activity_afterfield - Check
.graphitefor stacks — Null if not in a Graphite stack - File provenance for cross-PR fixes — See graphite/cross-pr-fixes.md