diff --git a/.planning/phases/04-power-user-features/04-CONTEXT.md b/.planning/phases/04-power-user-features/04-CONTEXT.md
new file mode 100644
index 0000000..6523187
--- /dev/null
+++ b/.planning/phases/04-power-user-features/04-CONTEXT.md
@@ -0,0 +1,108 @@
+# Phase 4: Power User Features - Context
+
+**Gathered:** 2026-03-26
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Two additive CLI features: BPF capture filter (`--filter` flag) and offline pcap file input (`--read` flag). Both feed into the existing classify → aggregate → synthesis pipeline. No changes to audio synthesis, classification rules, or MP3 encoding.
+
+
+
+
+## Implementation Decisions
+
+### Pcap file timing
+- **D-01:** Use packet timestamps from the pcap file to assign packets to 500ms time windows. Processing is fast — a 10-minute pcap produces a 10-minute MP3 in seconds.
+- **D-02:** Preserve time gaps as silence. Windows with zero packets during gaps produce silent audio sections. MP3 duration faithfully matches the pcap file's time span.
+
+### Flag interaction rules
+- **D-03:** `--read` and `-i` are mutually exclusive. Error if both provided. `--read` replaces `-i` as the packet source.
+- **D-04:** `--filter` works with both `-i` (live capture) and `--read` (pcap file). BPF filter applies to whichever packet source is active.
+- **D-05:** `--read` without `-o` derives output filename from input: `capture.pcap` → `capture.mp3`.
+
+### Offline processing feedback
+- **D-06:** Bookend messages: `"Reading ..."` at start, then protocol summary + `"Saved"` line at end. No progress bar — processing is fast enough that it would flash by.
+- **D-07:** `--verbose` works with `--read` — per-window protocol activity lines scroll by quickly. Consistent behavior regardless of packet source.
+
+### Claude's Discretion
+- BPF filter validation approach (pre-validate before opening capture vs let go-pcap/gopacket reject it)
+- Pcap file format detection and error messages for corrupt/unreadable files
+- Implementation of timestamp-based windowing (new aggregation path vs adapter that feeds existing Aggregate())
+- How to handle pcap files with no packets (reuse existing zero-packet guard from OUT-03)
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Project context
+- `.planning/PROJECT.md` — Core value, constraints (Go, MP3 output, non-interactive)
+- `.planning/REQUIREMENTS.md` — CAPT-05 (BPF filter), CAPT-06 (pcap file input)
+
+### Prior phase context
+- `.planning/phases/01-capture-and-classification/01-CONTEXT.md` — Phase 1 decisions; pure-Go pcap backend, classifier design, privilege model
+- `.planning/phases/02-audio-synthesis-engine/02-CONTEXT.md` — Phase 2 decisions; tone mapping, mixing, encoding
+- `.planning/phases/03-pipeline-integration-and-mvp/03-CONTEXT.md` — Phase 3 decisions; hash-bucketing, encoding feedback format
+
+### Key source files (integration points)
+- `cmd/netsynth/main.go` — CLI wiring; Cobra flags, pipeline assembly, encoding feedback output
+- `capture/capture.go` — `OpenCapture()` and `StartCapture()` — will need filter parameter and pcap file reading path
+- `aggregate/window.go` — `Aggregate()` function using real-time ticks; pcap mode needs timestamp-based windowing
+- `encode/mp3.go` — `RunSynthesis()` entry point; no changes expected
+- `classify/types.go` — `WindowSnapshot` struct (input contract for synthesis)
+
+### Stack decisions
+- `CLAUDE.md` — Technology stack section; `packetcap/go-pcap` for capture, `gopacket/gopacket` for decoding
+- `.planning/research/STACK.md` — Library recommendations and alternatives
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `capture.StartCapture(ctx, iface)` — live capture pipeline; pcap file reading needs a parallel entry point returning the same `<-chan gopacket.Packet`
+- `classify.NewClassifier(rules)` / `classifier.Classify(pkt)` — reused unchanged for both live and pcap sources
+- `aggregate.Aggregate(done, classified, windowMs, onSnapshot)` — reused for live; pcap needs timestamp-based variant
+- `encode.RunSynthesis([]WindowSnapshot, path)` — reused unchanged
+- `aggregate.PrintSummary()` / `aggregate.PrintWindowLine()` — reused for both modes
+
+### Established Patterns
+- Channel-based pipeline: capture → classify → aggregate → synthesis
+- `done <-chan struct{}` for shutdown signaling via `signal.NotifyContext`
+- Buffered channels for stage decoupling (512 capture, 1024 classified, 8 aggregate)
+- `io.Writer` injection for testable output
+- Cobra flag-based CLI with `RunE` function
+
+### Integration Points
+- `main.go` — Add `--filter` and `--read` Cobra flags; branch `run()` into live vs pcap paths
+- `capture/capture.go` — Add filter parameter to `OpenCapture()`; add new `ReadPcapFile()` function
+- `aggregate/window.go` — Add timestamp-based windowing function for offline mode (or adapter)
+
+
+
+
+## Specific Ideas
+
+- `--read` + `--filter` is a key workflow: capture broad with tcpdump, then sonify a subset
+- Output filename derivation (`capture.pcap` → `capture.mp3`) follows ffmpeg conventions
+- Pcap file processing should feel instant — no unnecessary waiting or progress indicators
+- BPF filter errors should fail fast before any capture begins, with a clear message
+
+
+
+
+## Deferred Ideas
+
+None — discussion stayed within phase scope
+
+
+
+---
+
+*Phase: 04-power-user-features*
+*Context gathered: 2026-03-26*
diff --git a/.planning/phases/04-power-user-features/04-DISCUSSION-LOG.md b/.planning/phases/04-power-user-features/04-DISCUSSION-LOG.md
new file mode 100644
index 0000000..08e8ddf
--- /dev/null
+++ b/.planning/phases/04-power-user-features/04-DISCUSSION-LOG.md
@@ -0,0 +1,108 @@
+# Phase 4: Power User Features - Discussion Log
+
+> **Audit trail only.** Do not use as input to planning, research, or execution agents.
+> Decisions are captured in CONTEXT.md — this log preserves the alternatives considered.
+
+**Date:** 2026-03-26
+**Phase:** 04-power-user-features
+**Areas discussed:** Pcap file timing, Flag interaction rules, Offline processing feedback
+
+---
+
+## Pcap File Timing
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Packet timestamps | Use each packet's captured timestamp to assign it to a 500ms window. Fast processing. Faithful to original timing. | ✓ |
+| Fixed-rate chunking | Ignore timestamps, just group every N packets into a window. Simpler but loses temporal fidelity. | |
+| You decide | Claude picks the best approach based on codebase constraints | |
+
+**User's choice:** Packet timestamps
+**Notes:** None
+
+### Follow-up: Time gaps
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Preserve gaps as silence | Gaps become silent sections in the MP3. Faithful but potentially long files. | ✓ |
+| Collapse gaps | Skip windows with zero packets. Dense, shorter output. | |
+| You decide | Claude picks based on what fits the pipeline best | |
+
+**User's choice:** Preserve gaps as silence
+**Notes:** MP3 duration matches the pcap's time span faithfully, including periods of no traffic.
+
+---
+
+## Flag Interaction Rules
+
+### --read and -i interaction
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Mutually exclusive | Error if both provided. Matches tcpdump behavior. | ✓ |
+| Ignore -i when --read set | Silently ignore -i if --read is present. | |
+| You decide | Claude picks based on CLI conventions | |
+
+**User's choice:** Mutually exclusive
+**Notes:** None
+
+### --filter with --read
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Yes, allow both | --filter applies BPF to the pcap file contents. Common workflow: capture broad, then sonify a subset. | ✓ |
+| Only with live capture | --filter only works with -i. Simpler scope. | |
+| You decide | Claude picks based on go-pcap/gopacket capabilities | |
+
+**User's choice:** Yes, allow both
+**Notes:** None
+
+### --read without -o default
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Derive from input filename | capture.pcap → capture.mp3. Parallel to ffmpeg conventions. | ✓ |
+| Same timestamp default as live | netsynth-.mp3 regardless of input. | |
+| You decide | Claude picks the most intuitive default | |
+
+**User's choice:** Derive from input filename
+**Notes:** None
+
+---
+
+## Offline Processing Feedback
+
+### User feedback during pcap processing
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Bookend messages | "Reading capture.pcap..." at start, then summary + Saved line at end. | ✓ |
+| Packet count progress | Running packet count as file is read. More feedback but adds complexity for fast operation. | |
+| You decide | Claude picks based on existing output style | |
+
+**User's choice:** Bookend messages
+**Notes:** None
+
+### --verbose with --read
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Yes, same output | Per-window activity lines scroll by. Consistent behavior regardless of source. | ✓ |
+| No, only live capture | --verbose ignored with --read. Keeps offline mode minimal. | |
+| You decide | Claude picks based on consistency | |
+
+**User's choice:** Yes, same output
+**Notes:** None
+
+---
+
+## Claude's Discretion
+
+- BPF filter validation approach
+- Pcap file format detection and error messages
+- Timestamp-based windowing implementation strategy
+- Handling of pcap files with no packets
+
+## Deferred Ideas
+
+None — discussion stayed within phase scope