diff --git a/.planning/phases/07-custom-rules-and-print-config/07-CONTEXT.md b/.planning/phases/07-custom-rules-and-print-config/07-CONTEXT.md
new file mode 100644
index 0000000..eb99bdf
--- /dev/null
+++ b/.planning/phases/07-custom-rules-and-print-config/07-CONTEXT.md
@@ -0,0 +1,123 @@
+# Phase 7: Custom Rules and Print-Config - Context
+
+**Gathered:** 2026-03-26
+**Status:** Ready for planning
+
+
+## Phase Boundary
+
+Add user-defined traffic classification rules in TOML (`[[rules]]` array-of-tables) that prepend before built-in rules, with automatic synthesis layer creation for new class names. Add `--print-config` flag that outputs the full effective config as commented TOML to stdout without starting a capture.
+
+Requirements covered: RULE-01, RULE-02, RULE-03, CFG-06.
+
+
+
+
+## Implementation Decisions
+
+### Custom Rule TOML Schema
+- **D-01:** Custom rules use TOML array-of-tables `[[rules]]` with three fields: `port` (uint16, optional — omit to match any port), `protocol` (string, required — "tcp", "udp", or "icmp"), and `class` (string, required — the TrafficClass name). Sound configuration for the class goes in a separate `[sounds.]` block.
+- **D-02:** Port is optional. When omitted (or 0), the rule matches all traffic for the given protocol, mirroring the existing `Rule.DstPort = 0` semantics in `classify.DefaultRules`.
+- **D-03:** Protocol is required. No implicit "match both TCP and UDP" behavior. User must write separate rules for each protocol.
+
+### Rule Ordering and Priority
+- **D-04:** User-defined rules are prepended before built-in `DefaultRules` (RULE-02). First-match-wins semantics are preserved. A user rule for port 443/tcp fires before the built-in HTTPS rule.
+- **D-05:** Rules within the TOML `[[rules]]` array maintain their file order. First rule in the file is first to match.
+
+### Class Name Collision Policy
+- **D-06:** User-defined class names that match built-in names (e.g., `class = "HTTPS"`) are treated as overrides, not errors. The user's rule fires first (prepended), so traffic matching it gets classified under the same built-in class name via the user rule. Sound config in `[sounds.HTTPS]` still applies. This resolves the design question flagged in STATE.md.
+
+### Sound Assignment for Custom Classes
+- **D-07:** New class names that have no `[sounds.]` entry automatically get sensible defaults: a frequency from an unused range and sine waveform. This satisfies RULE-03 (no silent gaps for user-defined classes).
+- **D-08:** (Claude's Discretion) The auto-assignment algorithm — how to pick frequencies for new classes that don't collide with built-in frequencies. Could use a hash of the class name, a sequential pool, or a deterministic spread across an unused frequency band.
+
+### Print-Config
+- **D-09:** `--print-config` outputs the full effective config (defaults merged with user overrides and custom rules) as commented TOML. Comments indicate which values are defaults vs overrides. This satisfies CFG-06.
+- **D-10:** Output goes to stdout (pipeable). User can do `netsynth --print-config > template.toml` to create a config template. The command exits without starting a capture.
+- **D-11:** If a config file is loaded (via auto-discovery or `--config`), show its source path in a header comment.
+
+### Config Package Extension
+- **D-12:** The existing `config.Load()` function must be extended to parse `[[rules]]` blocks in addition to `[sounds.*]`. The `rawConfig` struct gains a `Rules []RawRule` field.
+- **D-13:** `config.Load()` returns both the merged `FreqConfig` map and the user rules (as `[]classify.Rule`). The caller prepends user rules before `classify.DefaultRules`.
+
+### Claude's Discretion
+- How to extend `rawConfig` struct and `Load()` return type (tuple, struct, or new function)
+- Auto-frequency assignment algorithm for custom classes without explicit sound config
+- Whether `--print-config` is a Cobra subcommand or a flag on the root command
+- How to format the commented TOML output (manual string building vs TOML encoder + post-processing)
+
+
+
+
+## Canonical References
+
+**Downstream agents MUST read these before planning or implementing.**
+
+### Classification System
+- `classify/rules.go` — `Rule` struct (Protocol, DstPort, Class), `DefaultRules` ordered slice, first-match-wins
+- `classify/types.go` — `TrafficClass` string type, `AllClasses()`, `ClassifiedPacket`, `WindowSnapshot`
+- `classify/classifier.go` — `NewClassifier(rules []Rule)` — accepts injected rule slice
+
+### Config System (Phase 6 output)
+- `config/config.go` — `Load()`, `rawConfig`, `SoundOverride`, `merge()`, `validate()`, `parseWaveform()`
+- `config/config_test.go` — Existing test patterns for TOML loading
+
+### Synthesis Pipeline
+- `synth/config.go` — `FreqConfig`, `ClassFreqConfigs`, `WaveformType`, `WaveformPresetHarmonics()`
+- `synth/bank.go` — `NewBank(tau, cfgs map[TrafficClass]FreqConfig)` — injection point for merged config
+- `encode/mp3.go` — `RunSynthesis(snapshots, outputPath, freqCfgs)` — pipeline entry
+
+### CLI
+- `cmd/netsynth/main.go` — Cobra command, `--config` flag, `run()` dispatches to live/pcap modes
+
+### Prior Context
+- `.planning/phases/06-config-package-and-sound-overrides/06-CONTEXT.md` — Phase 6 decisions (TOML schema, merge semantics, validation)
+
+No external specs — requirements fully captured in decisions above.
+
+
+
+
+## Existing Code Insights
+
+### Reusable Assets
+- `classify.Rule` struct — Already has Protocol, DstPort, Class fields matching the TOML schema
+- `classify.NewClassifier(rules []Rule)` — Accepts any rule slice, so prepending user rules is straightforward
+- `config.Load()` — Existing TOML loading with BurntSushi/toml, validation, and merge pipeline
+- `config.rawConfig` — Top-level decode struct, needs `Rules` field added
+- `config.parseWaveform()` — Reusable for validating waveform strings in sound overrides
+- `synth.NewBank(tau, cfgs)` — Already accepts arbitrary config maps (Phase 5 injection seam)
+
+### Established Patterns
+- First-match-wins rule ordering in `classify.DefaultRules`
+- TOML strict decoding with `Undecoded()` for unknown key detection
+- Pointer fields (`*float64`, `*string`) for partial override semantics
+- Config loaded once at startup before capture (fail-fast)
+
+### Integration Points
+- `config.Load()` return value must expand to include user rules
+- `cmd/netsynth/main.go:run()` — Prepend user rules before passing to `classify.NewClassifier()`
+- `config.merge()` — Must handle new class names by creating `FreqConfig` entries with auto-assigned frequencies
+- `--print-config` — New flag or subcommand in Cobra root command
+
+
+
+
+## Specific Ideas
+
+- Print-config should show commented TOML with `# default` / `# override` annotations and source path header
+- Output to stdout so users can pipe to a file as a template
+
+
+
+
+## Deferred Ideas
+
+None — discussion stayed within phase scope.
+
+
+
+---
+
+*Phase: 07-custom-rules-and-print-config*
+*Context gathered: 2026-03-26*
diff --git a/.planning/phases/07-custom-rules-and-print-config/07-DISCUSSION-LOG.md b/.planning/phases/07-custom-rules-and-print-config/07-DISCUSSION-LOG.md
new file mode 100644
index 0000000..1141842
--- /dev/null
+++ b/.planning/phases/07-custom-rules-and-print-config/07-DISCUSSION-LOG.md
@@ -0,0 +1,73 @@
+# Phase 7: Custom Rules and Print-Config - 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:** 07-custom-rules-and-print-config
+**Areas discussed:** Custom rule TOML schema, Class name collision policy, Print-config output format, Sound assignment for custom classes
+
+---
+
+## Custom Rule TOML Schema
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Minimal: port + protocol + class | Matches existing Rule struct. Sound config in separate [sounds.X]. | ✓ |
+| Inline sound: port + protocol + class + frequency/waveform | All-in-one rule block, mixes classification and sound concerns. | |
+| Rich matching: port ranges, src/dst, regex | More expressive but significantly more complex. | |
+
+**User's choice:** Minimal — port + protocol + class
+**Notes:** Protocol is required. Port is optional (omit to match any port for the protocol).
+
+---
+
+## Class Name Collision Policy
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Treat as override | User's rule fires first (prepended), same class name. Simplest model. | ✓ |
+| Reject with error | Startup error if user rule uses built-in class name. | |
+| Namespace: prefix user classes | User classes get "user-" prefix. Adds naming complexity. | |
+
+**User's choice:** Treat as override
+**Notes:** Resolves the design question flagged in STATE.md since Phase 5 research.
+
+---
+
+## Print-Config Output Format
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Commented TOML | Valid TOML with comments showing default vs override. Pipeable to file. | ✓ |
+| Plain TOML | Clean but doesn't show what's default vs overridden. | |
+| Human-readable table | Formatted table, not valid TOML. | |
+
+**User's choice:** Commented TOML to stdout
+**Notes:** Output to stdout so `netsynth --print-config > template.toml` works. Shows source path in header comment.
+
+---
+
+## Sound Assignment for Custom Classes
+
+| Option | Description | Selected |
+|--------|-------------|----------|
+| Auto-assign sensible defaults | Pick unused frequency + sine waveform. No silence. | ✓ |
+| Require explicit [sounds.X] | Error if no matching sound config. More friction. | |
+| Single fallback tone | All custom classes share one tone. Defeats distinct sounds purpose. | |
+
+**User's choice:** Auto-assign sensible defaults
+**Notes:** Satisfies RULE-03 (no silent gaps). Algorithm left to Claude's discretion.
+
+---
+
+## Claude's Discretion
+
+- Auto-frequency assignment algorithm
+- --print-config as flag vs subcommand
+- Commented TOML formatting approach
+- config.Load() return type extension
+
+## Deferred Ideas
+
+None — discussion stayed within phase scope.