Skip to content

Commit 5ffb3f7

Browse files
raaymaxclaude
andauthored
feat: add config system with discovery, loading, and CLI commands (#11)
* docs: map existing codebase - STACK.md - Technologies and dependencies - ARCHITECTURE.md - System design and patterns - STRUCTURE.md - Directory layout - CONVENTIONS.md - Code style and patterns - TESTING.md - Test structure - INTEGRATIONS.md - External services - CONCERNS.md - Technical debt and issues * docs: initialize project Terminal-based log viewer adding project-scoped configuration and stream cleanup * chore: add project config Mode: yolo Depth: standard Parallelization: enabled Workflow agents: research=on, plan_check=on, verifier=on * docs: complete project research Files: - STACK.md: serde-saphyr for YAML, signal-hook 0.4 upgrade - FEATURES.md: table stakes (auto-discovery, precedence), differentiators (named sources) - ARCHITECTURE.md: layered config with precedence merging, signal flag pattern - PITFALLS.md: async-signal-safety, race conditions, discovery loops - SUMMARY.md: synthesized findings with 5-phase roadmap structure Key findings: - Stack: serde-saphyr 0.0 (panic-free YAML), signal-hook 0.4.3 upgrade - Architecture: config loads before event loop, flag pattern for cleanup - Critical pitfall: async-signal-unsafe operations (existing pattern correct, needs refinement) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs: define v1 requirements 20 requirements across 6 categories: - Signal handling (4) - Config discovery (3) - Config loading (3) - Config options (5) - Project-local streams (2) - Config commands (3) * docs: create roadmap (5 phases) Phases: 1. Signal Infrastructure: SIG-01..04 2. Config Discovery: DISC-01..03 3. Config Loading: LOAD-01..03, OPT-01..05 4. Project-Local Streams: PROJ-01..02 5. Config Commands: CMD-01..03 All 20 v1 requirements mapped to phases. * docs(01): capture phase context Phase 01: Signal Infrastructure - Implementation decisions documented - Phase boundary established * docs(01): research signal infrastructure Phase 1: Signal Infrastructure - Standard stack: signal-hook flag module (already in deps) - Architecture patterns: double Ctrl+C, flag-based shutdown, stale marker cleanup - Pitfalls: process::exit() in handlers, blocking iterators, registration order * docs(01): create phase plan Phase 01: Signal Infrastructure - 1 plan in 1 wave - 3 tasks: signal module, capture refactor, stale cleanup - Ready for execution * feat(01-01): create signal module with shutdown infrastructure - Add src/signal.rs with setup_shutdown_handlers() function - Uses signal-hook::flag for flag-based signal handling - Supports double Ctrl+C for force quit (exit code 1) - Register conditional shutdown before flag setter (order matters) - Add mod signal; declaration to main.rs * refactor(01-01): use flag-based shutdown in capture mode - Remove thread::spawn signal handler with process::exit() - Use signal module's setup_shutdown_handlers() instead - Check shutdown_flag.load(Ordering::SeqCst) in tee loop - Cleanup now always runs (no premature exit from signal handler) - Supports double Ctrl+C force quit via conditional_shutdown * feat(01-01): add stale marker cleanup at startup - Add cleanup_stale_markers() to source.rs - Scans sources directory for marker files - Removes markers where PID is no longer running - Called in main() before any mode dispatch - Errors logged to stderr but don't prevent startup - Fixes SIGKILL recovery scenario * docs(01-01): complete signal infrastructure plan Tasks completed: 3/3 - Create signal.rs module with shutdown infrastructure - Refactor capture.rs to use flag-based shutdown - Add stale marker cleanup at startup SUMMARY: .planning/phases/01-signal-infrastructure/01-01-SUMMARY.md * docs(01): complete signal infrastructure phase Phase 1 verified: - Signal module with flag-based shutdown handlers - Capture mode refactored to use flags (no process::exit) - Stale marker cleanup at startup - Double Ctrl+C force-exit support Requirements: SIG-01, SIG-02, SIG-03, SIG-04 complete * feat(install): add MCP configuration for AI assistants - Detect installed AI assistants (Claude Code, Claude Desktop, Codex, Gemini CLI, Cursor, Windsurf, Zed) - Prompt to configure MCP integration for each detected assistant - Support JSON config (Desktop, Cursor, Windsurf, Gemini) and TOML (Codex) - Use /dev/tty for reads to work with piped installation * docs(02): capture phase context Phase 02: Config Discovery - Implementation decisions documented - Phase boundary established * docs(02): research config discovery domain Phase 02: Config Discovery - Standard stack identified (std::path, dirs crate) - Architecture patterns documented (ancestors traversal) - Pitfalls catalogued (permission errors, symlinks) * docs(02): create phase plan Phase 02: Config Discovery - 1 plan in 1 wave - 1 parallel, 0 sequential - Ready for execution * fix(02): revise plan based on checker feedback Addresses checker issues: - DISC-03: Added explicit root boundary handling mention - Added dirs crate dependency verification step - Changed to discover_verbose() for -v flag search PATH output - Added key_link for data_dir() -> Phase 4 connection - Added test cases for root boundary and global config detection - Clarified subdirectory walking verification in Task 2 * feat(02-01): add config discovery module - Add src/config/discovery.rs with discover() and discover_verbose() functions - DiscoveryResult struct holds project_root, project_config, global_config paths - data_dir() method returns project_root/.lazytail for Phase 4 storage - Walks parent directories to find lazytail.yaml (terminates at filesystem root) - Checks ~/.config/lazytail/config.yaml for global config - discover_verbose() returns all searched directories for -v output - Unit tests verify discovery behavior including root boundary * feat(02-01): integrate config discovery into main.rs - Add mod config; declaration to main.rs - Add -v/--verbose flag to Args struct - Call discover_verbose() after cleanup_stale_markers() - Verbose mode shows search path (all directories checked) to stderr - Verbose mode shows discovery results (project root, project config, global config) - Non-verbose mode has no discovery output - Store discovery result for Phase 3 config loading * docs(02-01): complete config discovery plan Tasks completed: 2/2 - Task 1: Create config discovery module with tests - Task 2: Integrate discovery into main.rs with verbose output SUMMARY: .planning/phases/02-config-discovery/02-01-SUMMARY.md * docs(02): complete config-discovery phase Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs(03): capture phase context Phase 03: Config Loading - Implementation decisions documented - Phase boundary established * docs(03): research config loading phase Phase 3: Config Loading - Standard stack identified (serde-saphyr, strsim) - Architecture patterns documented (strict parsing, typo suggestions) - Pitfalls catalogued (deny_unknown_fields, tilde expansion) * docs(03): create phase plan Phase 03: Config Loading - 2 plans in 2 waves - Wave 1: Config infrastructure (types, parser, errors) - Wave 2: Integration with main.rs and UI - Ready for execution * feat(03-01): add config types with deny_unknown_fields - Add serde-saphyr, strsim, thiserror dependencies to Cargo.toml - Create src/config/types.rs with RawConfig, RawSource, Source, Config - Create stub src/config/error.rs with ConfigError variants - Create stub src/config/loader.rs for later implementation - Update src/config/mod.rs to export new modules * feat(03-01): add ConfigError with suggestions and locations - Add jaro_winkler similarity search for typo suggestions - Known fields: root (name, sources), source (name, path) - 0.8 threshold for Jaro-Winkler similarity matching - Extract line/column from serde-saphyr error messages - Cargo-style error formatting with suggestion hints - Comprehensive unit tests for all error formatting * feat(03-01): add config loader with path expansion - Add expand_path() for tilde to home directory expansion - Add load_file() for YAML parsing with serde-saphyr - Add validate_sources() for path expansion and existence check - Add load() to merge project and global configs - Project name takes precedence, sources kept in separate groups - Graceful degradation: empty Config when no configs exist - Comprehensive unit tests for all loader functions * docs(03-01): complete config loading infrastructure plan Tasks completed: 3/3 - Add dependencies and create config types - Create error module with suggestions - Create config loader with path expansion SUMMARY: .planning/phases/03-config-loading/03-01-SUMMARY.md * feat(03-02): add config source types and tab creation - Add ProjectSource and GlobalSource variants to SourceType enum - Update SourcePanelState.expanded array to 5 elements - Update tabs_by_category to return 5 categories - Add from_config_source() method to TabState for creating tabs from config - Add disabled_source() helper for missing config sources - Add config_source_type and disabled fields to TabState - Update source_type() to check config_source_type first * feat(03-02): update UI for config source categories - Add ProjectSource and GlobalSource category names to side panel - Rename Global category to Captured for clarity - Show disabled sources (missing files) in grayed-out style * feat(03-02): integrate config loading in main.rs - Load config from discovered files at startup - Create tabs from project and global config sources - Prepend config tabs before CLI args and discovery tabs - Update discovery mode to accept config and errors - Log config errors to stderr (debug source is future enhancement) - Update exit message with config option when no sources found * docs(03-02): complete config integration plan Tasks completed: 3/3 - Task 1: Add config source types and tab creation - Task 2: Update UI for config source categories - Task 3: Integrate config loading in main.rs SUMMARY: .planning/phases/03-config-loading/03-02-SUMMARY.md * fix(03): commit Cargo.lock and formatting Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs(03): add phase verification report Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * feat(filter): add query filter module (WIP) Accidentally mixed with phase 3 commits - included to fix build. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * fix(filter): export query module Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs(03): complete config loading phase - Mark phase 3 plans complete in ROADMAP.md - Update STATE.md with phase completion - Mark LOAD-01, LOAD-02, LOAD-03, OPT-01, OPT-02 complete in REQUIREMENTS.md - OPT-03, OPT-04, OPT-05 deferred Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * docs(04): research project-local streams phase Phase 4: Project-Local Streams - Document context-aware directory resolution pattern - Research DirBuilder with mode 0o700 for secure permissions - Identify integration points with existing discovery/source modules - Catalogue pitfalls (mode permissions, context mismatch) * docs(04): create phase plan Phase 04: Project-Local Streams - 2 plans in 2 waves - Wave 1: Context-aware directory functions + capture mode - Wave 2: Discovery mode with dual-location scanning - Ready for execution * feat(04-01): add context-aware directory resolution to source.rs - Add create_secure_dir() for 0700 permissions on Unix - Add resolve_data_dir(discovery) for context-aware data directory - Add resolve_sources_dir(discovery) for context-aware sources directory - Add ensure_directories_for_context(discovery) wrapper - Add check_source_status_for_context, create_marker_for_context, remove_marker_for_context for discovery-aware marker operations - Add comprehensive tests for all new functions * feat(04-01): integrate context-aware capture mode - Update run_capture_mode to accept DiscoveryResult parameter - Use context-aware functions: ensure_directories_for_context, check_source_status_for_context, create_marker_for_context, resolve_data_dir, remove_marker_for_context - Add location indicator (project/global) to capture header output - Update main.rs to pass discovery result to capture mode * docs(04-01): complete context-aware directory resolution plan Tasks completed: 2/2 - Add context-aware directory functions to source.rs - Integrate context-aware capture mode SUMMARY: .planning/phases/04-project-local-streams/04-01-SUMMARY.md * feat(04-02): add SourceLocation enum and context-aware discovery - Add SourceLocation enum (Project, Global) to track source origin - Add location field to DiscoveredSource struct - Create scan_data_directory helper for code reuse - Add check_source_status_in_dir for location-specific status checks - Add discover_sources_for_context to scan both project and global dirs - Project sources appear first and shadow global sources with same name - Update existing discover_sources to set location: Global - Update main.rs DiscoveredSource construction with location field - Add tests for dual-location discovery and shadowing * feat(04-02): integrate context-aware discovery in discovery mode - Update run_discovery_mode to accept DiscoveryResult parameter - Use discover_sources_for_context for dual-location scanning - Use ensure_directories_for_context for secure directory creation - Directory watcher now watches project data dir if in project context - Pass watched_location to run_app_with_discovery for correct source location - New sources discovered via watcher use the context-appropriate location * docs(04-02): complete dual-location discovery plan Tasks completed: 2/2 - Add SourceLocation enum and context-aware discovery - Integrate context-aware discovery in main.rs SUMMARY: .planning/phases/04-project-local-streams/04-02-SUMMARY.md * docs(04): complete project-local streams phase - Phase 4 verified and complete - PROJ-01, PROJ-02 requirements marked complete - All success criteria met * docs(05): capture phase context Phase 05: Config Commands - Implementation decisions documented - Phase boundary established * docs(05): research phase domain Phase 5: Config Commands - Standard stack identified (clap subcommands, colored crate) - Architecture patterns documented (nested subcommands, closest-config-wins) - Pitfalls catalogued (backward compat, quiet success, NO_COLOR) * docs(05): create phase plan Phase 05: Config Commands - 2 plan(s) in 1 wave(s) - Both parallel (wave 1), 05-02 depends on 05-01 - Ready for execution * feat(05-01): add cmd module structure with subcommand definitions - Add colored dependency (v3.1) to Cargo.toml - Create src/cmd/mod.rs with Commands enum (Init, Config) - Create InitArgs struct with --force flag - Create ConfigAction enum (Validate, Show) - Add placeholder init.rs for task 3 * feat(05-01): add subcommand dispatch to main.rs - Rename Args to Cli struct for clarity - Add optional command field with Option<cmd::Commands> - Handle subcommands before mode detection logic - Route init command to cmd::init::run() - Add TODO stubs for config validate/show (Plan 05-02) - Rename all args references to cli - Preserve backward compatibility for file/stdin/discovery modes * feat(05-01): implement lazytail init command - Create lazytail.yaml with commented template - Auto-detect project name from directory - Create .lazytail/ directory with secure permissions (0700) - Check for existing config, fail without --force - Add unit tests for template generation * docs(05-01): complete CLI subcommand infrastructure plan Tasks completed: 3/3 - Add colored dependency and create cmd module structure - Refactor main.rs for subcommand handling - Implement init command SUMMARY: .planning/phases/05-config-commands/05-01-SUMMARY.md * feat(05-02): add load_single_file for config commands - Add SingleFileConfig struct for single-file loading (closest-wins semantics) - Add load_single_file() function that loads only one config file - Export new types from config module - Supports config validate and config show commands * feat(05-02): implement config validate and show commands - Add config::validate() with Unix-style quiet success - Add config::show() with colored output display - Implement closest-wins semantics via effective_config_path() - Validate YAML syntax, known fields, and source file existence - Show respects NO_COLOR environment variable * feat(05-02): wire up config validate and show in main.rs - Replace TODO placeholders with actual command implementations - Use map_err pattern for correct exit code propagation - Config commands now fully functional end-to-end * docs(05-02): complete config validate and show plan Tasks completed: 3/3 - Add load_single_file to config loader - Implement config validate and show commands - Wire up config subcommands in main.rs SUMMARY: .planning/phases/05-config-commands/05-02-SUMMARY.md * docs(05): complete config-commands phase All phase requirements verified: - CMD-01: lazytail init creates starter config - CMD-02: lazytail config validate checks config errors - CMD-03: lazytail config show displays effective config Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com> * chore: update Cargo.lock for colored dependency * fix(tab): set config_source_type from discovered source location * fix: address review issues from PR review - Replace process::exit() in map_err with anyhow error propagation - Remove unused re-exports (discover_verbose, ConfigError) from config/mod.rs - Gate test-only functions with #[cfg(test)] (ensure_directories, create_marker, has_sources) * fix: resolve clippy warnings treated as errors in CI - Gate test-only methods data_dir() and has_config() with #[cfg(test)] - Allow dead_code on ConfigError::Validation variant (reserved for future use) --------- Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>
1 parent aebf10d commit 5ffb3f7

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

67 files changed

+14442
-120
lines changed

.planning/PROJECT.md

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
# LazyTail
2+
3+
## What This Is
4+
5+
LazyTail is a terminal-based log viewer for developers who work with multiple log streams. It provides multi-tab viewing, vim-style navigation, real-time filtering, and an MCP server for AI-assisted log analysis.
6+
7+
## Core Value
8+
9+
Fast, keyboard-driven log exploration across multiple sources with live updates.
10+
11+
## Requirements
12+
13+
### Validated
14+
15+
- ✓ Multi-tab log viewing with independent state per tab — existing
16+
- ✓ Vim-style navigation (hjkl, gg/G, Ctrl+d/u, search) — existing
17+
- ✓ Real-time filtering with string, regex, and query syntax — existing
18+
- ✓ Background filtering with progress indication — existing
19+
- ✓ File watching for live log updates — existing
20+
- ✓ Stdin/pipe streaming support — existing
21+
- ✓ Line expansion for long lines — existing
22+
- ✓ Global stream capture (`cmd | lazytail -n "name"`) stored in ~/.config/lazytail/data/ — existing
23+
- ✓ MCP server for AI tool integration — existing
24+
- ✓ Source discovery mode to browse captured streams — existing
25+
26+
### Active
27+
28+
- [ ] Stream cleanup on exit/SIGTERM — stream files should be cleaned up so names can be reused
29+
- [ ] Project-scoped log configuration — `lazytail.yaml` config file defines project sources
30+
- [ ] Project-local stream storage — `.lazytail/` folder for project-specific streams
31+
- [ ] Dual storage support — both global (~/.config/lazytail/) and project-local (.lazytail/) coexist
32+
33+
### Out of Scope
34+
35+
- GUI interface — terminal-first tool
36+
- Log aggregation/shipping — this is a viewer, not a collector
37+
- Remote log access — local files and streams only
38+
39+
## Context
40+
41+
LazyTail is a brownfield project with an established architecture:
42+
- Event-driven main loop (render-collect-process)
43+
- Trait-based reader abstraction (`LogReader`) for files and streams
44+
- Channel-based communication for background filtering
45+
- Existing stream capture stores data in `~/.config/lazytail/data/`
46+
47+
Current stream handling in `src/main.rs` creates files but doesn't clean them up on exit. Signal handling exists via `signal-hook` crate but isn't connected to stream cleanup.
48+
49+
## Constraints
50+
51+
- **Tech stack**: Rust with ratatui/crossterm — established, no changes
52+
- **Config format**: YAML for lazytail.yaml — human-readable, familiar to developers
53+
- **Backwards compatibility**: Global streams in ~/.config/lazytail/ must continue working
54+
55+
## Key Decisions
56+
57+
| Decision | Rationale | Outcome |
58+
|----------|-----------|---------|
59+
| YAML for project config | Human-readable, familiar format | — Pending |
60+
| .lazytail/ for project streams | Mirrors .git/ pattern, keeps project state local | — Pending |
61+
| Both global and project storage | Flexibility for different use cases | — Pending |
62+
63+
---
64+
*Last updated: 2026-02-03 after initialization*

.planning/REQUIREMENTS.md

Lines changed: 88 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,88 @@
1+
# Requirements
2+
3+
**Project:** LazyTail — Project Configuration & Stream Cleanup
4+
**Version:** v1
5+
**Created:** 2026-02-03
6+
7+
## v1 Requirements
8+
9+
### Signal Handling
10+
11+
- [x] **SIG-01**: Graceful shutdown on SIGINT/SIGTERM cleans up stream markers before exit
12+
- [x] **SIG-02**: Fix capture.rs signal handler — remove process::exit(), let main thread handle cleanup
13+
- [x] **SIG-03**: Stale marker detection on startup — recover from SIGKILL by checking if PID still running
14+
- [x] **SIG-04**: Double Ctrl+C support — first triggers graceful shutdown, second forces immediate exit
15+
16+
### Config Discovery
17+
18+
- [x] **DISC-01**: Project root discovery — walk up directories looking for lazytail.yaml or .lazytail/
19+
- [x] **DISC-02**: Graceful missing config — tool works without config file using defaults
20+
- [x] **DISC-03**: Filesystem boundary checks — stop at root and $HOME to prevent slow traversal
21+
22+
### Config Loading
23+
24+
- [x] **LOAD-01**: YAML format support — parse lazytail.yaml using serde-saphyr
25+
- [x] **LOAD-02**: Hierarchical precedence — CLI args override project config override global config
26+
- [x] **LOAD-03**: Clear error messages — show file path and line number on parse errors
27+
28+
### Config Options
29+
30+
- [x] **OPT-01**: `name` option — project display name shown in UI
31+
- [x] **OPT-02**: `sources` option — file-based source definitions with paths/globs
32+
- [ ] **OPT-03**: `follow` option — default auto-follow mode for new tabs (deferred)
33+
- [ ] **OPT-04**: `filter` option — default filter pattern applied on startup (deferred)
34+
- [ ] **OPT-05**: `streams_dir` option — custom location for project streams (deferred)
35+
36+
### Project-Local Streams
37+
38+
- [x] **PROJ-01**: .lazytail/ directory — create project-local directory for stream storage
39+
- [x] **PROJ-02**: Context-aware capture — `lazytail -n` writes to project .lazytail/ when in project, global otherwise
40+
41+
### Config Commands
42+
43+
- [x] **CMD-01**: `lazytail init` — generate starter lazytail.yaml with comments
44+
- [x] **CMD-02**: `lazytail config validate` — parse config and report errors without running
45+
- [x] **CMD-03**: `lazytail config show` — display effective merged config
46+
47+
## v2 Requirements (Deferred)
48+
49+
- Local override file (lazytail.local.yaml) for personal settings not committed to git
50+
- Environment variable overrides (LAZYTAIL_* prefix)
51+
- Command-based sources in config (capture output of commands)
52+
- Source groups (open multiple related sources with one command)
53+
- JSON Schema for editor autocomplete support
54+
55+
## Out of Scope
56+
57+
- GUI interface — terminal-first tool
58+
- Remote log access — local files and streams only
59+
- TOML config format — YAML chosen for nested structures and multi-line strings
60+
- Wrap option in config — line expansion handles long lines
61+
62+
## Traceability
63+
64+
| Requirement | Phase | Status |
65+
|-------------|-------|--------|
66+
| SIG-01 | Phase 1 | complete |
67+
| SIG-02 | Phase 1 | complete |
68+
| SIG-03 | Phase 1 | complete |
69+
| SIG-04 | Phase 1 | complete |
70+
| DISC-01 | Phase 2 | complete |
71+
| DISC-02 | Phase 2 | complete |
72+
| DISC-03 | Phase 2 | complete |
73+
| LOAD-01 | Phase 3 | complete |
74+
| LOAD-02 | Phase 3 | complete |
75+
| LOAD-03 | Phase 3 | complete |
76+
| OPT-01 | Phase 3 | complete |
77+
| OPT-02 | Phase 3 | complete |
78+
| OPT-03 | - | deferred |
79+
| OPT-04 | - | deferred |
80+
| OPT-05 | - | deferred |
81+
| PROJ-01 | Phase 4 | complete |
82+
| PROJ-02 | Phase 4 | complete |
83+
| CMD-01 | Phase 5 | complete |
84+
| CMD-02 | Phase 5 | complete |
85+
| CMD-03 | Phase 5 | complete |
86+
87+
---
88+
*Last updated: 2026-02-05*

.planning/ROADMAP.md

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
# Roadmap: LazyTail Project Configuration & Stream Cleanup
2+
3+
## Overview
4+
5+
This roadmap delivers project-scoped configuration and robust signal handling to LazyTail. The journey starts with signal infrastructure (foundational for all cleanup), builds configuration discovery and loading, integrates config into the application, extends to project-local streams, and finishes with developer experience commands. Each phase builds on the previous, following the dependency chain identified in research.
6+
7+
## Phases
8+
9+
**Phase Numbering:**
10+
- Integer phases (1, 2, 3): Planned milestone work
11+
- Decimal phases (2.1, 2.2): Urgent insertions (marked with INSERTED)
12+
13+
Decimal phases appear between their surrounding integers in numeric order.
14+
15+
- [x] **Phase 1: Signal Infrastructure** - Robust signal handling with cleanup coordination
16+
- [x] **Phase 2: Config Discovery** - Find project root and config files
17+
- [x] **Phase 3: Config Loading** - Parse YAML and merge configuration layers
18+
- [x] **Phase 4: Project-Local Streams** - .lazytail/ directory with context-aware capture
19+
- [x] **Phase 5: Config Commands** - Init, validate, and show commands for developer experience
20+
21+
## Phase Details
22+
23+
### Phase 1: Signal Infrastructure
24+
**Goal**: Application handles termination signals gracefully with proper cleanup
25+
**Depends on**: Nothing (first phase)
26+
**Requirements**: SIG-01, SIG-02, SIG-03, SIG-04
27+
**Success Criteria** (what must be TRUE):
28+
1. Running `lazytail -n test` then pressing Ctrl+C cleans up stream markers before exit
29+
2. Running `lazytail -n test` then sending SIGTERM cleans up stream markers before exit
30+
3. After SIGKILL (kill -9), restarting lazytail detects and cleans stale markers
31+
4. Double Ctrl+C forces immediate exit without hanging
32+
5. capture.rs signal handler does not call process::exit() directly
33+
**Plans:** 1 plan
34+
35+
Plans:
36+
- [x] 01-01-PLAN.md — Signal module, capture.rs refactor, stale marker cleanup
37+
38+
### Phase 2: Config Discovery
39+
**Goal**: Application finds project root and config files by walking directory tree
40+
**Depends on**: Phase 1
41+
**Requirements**: DISC-01, DISC-02, DISC-03
42+
**Success Criteria** (what must be TRUE):
43+
1. Running lazytail in a subdirectory finds lazytail.yaml in parent directories
44+
2. Running lazytail in a directory with lazytail.yaml recognizes it as project root
45+
3. Running lazytail without any config file works normally using defaults
46+
4. Discovery stops at filesystem root (/)
47+
**Plans:** 1 plan
48+
49+
Plans:
50+
- [x] 02-01-PLAN.md — Config discovery module with verbose output integration
51+
52+
### Phase 3: Config Loading
53+
**Goal**: Application parses YAML config and merges multiple configuration sources with clear precedence
54+
**Depends on**: Phase 2
55+
**Requirements**: LOAD-01, LOAD-02, LOAD-03, OPT-01, OPT-02
56+
**Note**: OPT-03, OPT-04, OPT-05 (follow, filter, streams_dir) deferred per CONTEXT.md - only `name` and `sources` for now
57+
**Success Criteria** (what must be TRUE):
58+
1. lazytail.yaml with `name` and `sources` options parses correctly
59+
2. Project config overrides global config for name; sources kept in separate groups
60+
3. Parse errors show file path, line number, and "did you mean" suggestions
61+
4. Named sources from config appear in side panel
62+
5. Sources with missing files shown grayed out/disabled
63+
**Plans:** 2 plans
64+
65+
Plans:
66+
- [x] 03-01-PLAN.md — Config loading infrastructure (types, parser, errors)
67+
- [x] 03-02-PLAN.md — Integration with main.rs and UI (source categories)
68+
69+
### Phase 4: Project-Local Streams
70+
**Goal**: Streams captured within a project are stored locally in .lazytail/ directory
71+
**Depends on**: Phase 3
72+
**Requirements**: PROJ-01, PROJ-02
73+
**Success Criteria** (what must be TRUE):
74+
1. Running `lazytail -n test` inside a project creates stream in .lazytail/data/
75+
2. Running `lazytail -n test` outside any project creates stream in ~/.config/lazytail/data/
76+
3. Discovery mode shows both project-local and global streams appropriately
77+
4. .lazytail/ directory created with secure permissions (mode 0700)
78+
**Plans:** 2 plans
79+
80+
Plans:
81+
- [x] 04-01-PLAN.md — Context-aware directory functions and capture mode integration
82+
- [x] 04-02-PLAN.md — Discovery mode with dual-location source scanning
83+
84+
### Phase 5: Config Commands
85+
**Goal**: Developer experience commands for config initialization, validation, and introspection
86+
**Depends on**: Phase 3
87+
**Requirements**: CMD-01, CMD-02, CMD-03
88+
**Success Criteria** (what must be TRUE):
89+
1. `lazytail init` creates starter lazytail.yaml with helpful comments
90+
2. `lazytail config validate` reports config errors without starting the viewer
91+
3. `lazytail config show` displays effective merged configuration
92+
4. Init refuses to overwrite existing config without confirmation
93+
**Plans**: 2 plans
94+
95+
Plans:
96+
- [x] 05-01-PLAN.md — CLI subcommand infrastructure and init command
97+
- [x] 05-02-PLAN.md — Config validate and show commands
98+
99+
## Progress
100+
101+
**Execution Order:**
102+
Phases execute in numeric order: 1 -> 2 -> 3 -> 4 -> 5
103+
104+
| Phase | Plans Complete | Status | Completed |
105+
|-------|----------------|--------|-----------|
106+
| 1. Signal Infrastructure | 1/1 | Complete | 2026-02-03 |
107+
| 2. Config Discovery | 1/1 | Complete | 2026-02-03 |
108+
| 3. Config Loading | 2/2 | Complete | 2026-02-04 |
109+
| 4. Project-Local Streams | 2/2 | Complete | 2026-02-04 |
110+
| 5. Config Commands | 2/2 | Complete | 2026-02-05 |

.planning/STATE.md

Lines changed: 94 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,94 @@
1+
# Project State
2+
3+
## Project Reference
4+
5+
See: .planning/PROJECT.md (updated 2026-02-03)
6+
7+
**Core value:** Fast, keyboard-driven log exploration across multiple sources with live updates
8+
**Current focus:** Phase 5 complete - Config Commands
9+
10+
## Current Position
11+
12+
Phase: 5 of 5 (Config Commands)
13+
Plan: 2 of 2 in current phase
14+
Status: Complete
15+
Last activity: 2026-02-05 - Completed 05-02-PLAN.md
16+
17+
Progress: [██████████] 100%
18+
19+
## Performance Metrics
20+
21+
**Velocity:**
22+
- Total plans completed: 8
23+
- Average duration: 8 min
24+
- Total execution time: 1.05 hours
25+
26+
**By Phase:**
27+
28+
| Phase | Plans | Total | Avg/Plan |
29+
|-------|-------|-------|----------|
30+
| 01-signal-infrastructure | 1 | 8 min | 8 min |
31+
| 02-config-discovery | 1 | 12 min | 12 min |
32+
| 03-config-loading | 2 | 18 min | 9 min |
33+
| 04-project-local-streams | 2 | 15 min | 8 min |
34+
| 05-config-commands | 2 | 14 min | 7 min |
35+
36+
**Recent Trend:**
37+
- Last 5 plans: 10 min, 8 min, 7 min, 8 min, 6 min
38+
- Trend: Consistent ~8 min average
39+
40+
*Updated after each plan completion*
41+
42+
## Accumulated Context
43+
44+
### Decisions
45+
46+
Decisions are logged in PROJECT.md Key Decisions table.
47+
Recent decisions affecting current work:
48+
49+
- [Roadmap]: YAML chosen for config format (human-readable, nested structures)
50+
- [Roadmap]: .lazytail/ for project streams (mirrors .git/ pattern)
51+
- [Roadmap]: Both global and project storage coexist
52+
- [01-01]: Use signal-hook::flag for flag-based signal handling (non-blocking)
53+
- [01-01]: Register conditional_shutdown before flag setter (order for double Ctrl+C)
54+
- [01-01]: Stale marker cleanup logs errors but doesn't fail startup
55+
- [02-01]: Only lazytail.yaml signals project root (not .lazytail/ directory)
56+
- [02-01]: Global config checked before parent walk, but doesn't stop project search
57+
- [02-01]: Verbose mode shows full search path, not just results
58+
- [02-01]: Discovery runs early, before mode dispatch
59+
- [03-01]: Use serde-saphyr instead of unmaintained serde-yaml
60+
- [03-01]: 0.8 Jaro-Winkler threshold for typo suggestions
61+
- [03-01]: Project name takes precedence when merging configs
62+
- [03-01]: Sources kept in separate groups (project vs global)
63+
- [03-01]: Graceful degradation: empty Config when no configs exist
64+
- [03-02]: ProjectSource and GlobalSource added to beginning of SourceType enum
65+
- [03-02]: Disabled tabs created for missing config sources (shown grayed)
66+
- [03-02]: Config tabs prepended before CLI and discovery tabs
67+
- [03-02]: Captured renamed from Global in UI for clarity
68+
- [04-01]: Context-aware functions use _for_context variants for backward compatibility
69+
- [04-01]: Secure permissions (0700) on Unix only via cfg(unix)
70+
- [04-01]: Location indicator (project/global) shown in capture header
71+
- [04-02]: SourceLocation enum for tracking source origin (Project, Global)
72+
- [04-02]: Project sources shadow global sources with same name
73+
- [04-02]: scan_data_directory helper extracted for code reuse
74+
- [04-02]: watched_location parameter passed through for correct location assignment
75+
- [05-01]: colored 3.1 used instead of 2.7 (version not available)
76+
- [05-01]: Cli struct renamed from Args for clarity with subcommand field
77+
- [05-01]: Subcommand dispatch happens before stale marker cleanup
78+
- [05-02]: Closest config wins for config commands (load_single_file)
79+
- [05-02]: validate checks source file existence beyond YAML validity
80+
- [05-02]: show uses single sources: section (closest-wins semantics)
81+
82+
### Pending Todos
83+
84+
None.
85+
86+
### Blockers/Concerns
87+
88+
None - all planned phases complete.
89+
90+
## Session Continuity
91+
92+
Last session: 2026-02-05
93+
Stopped at: Completed 05-02-PLAN.md (all phases complete)
94+
Resume file: None

0 commit comments

Comments
 (0)