How to Debug Pipeline Issues Using cliLogWriter Output in no-mistakes
The cliLogWriter function in no-mistakes captures all pipeline diagnostics to $NM_HOME/.no-mistakes/logs/cli.log, enabling you to debug failures by inspecting appended log entries with step-specific markers.
The no-mistakes CLI tool provides a robust logging mechanism through its cliLogWriter implementation, which serves as the single source of truth for pipeline execution diagnostics. Understanding how to access and interpret this log output is essential for troubleshooting complex Git-centric workflows when the terminal UI truncates messages or when processes fail silently in CI environments.
Understanding cliLogWriter and Log File Location
The logging infrastructure is initialized early in the application lifecycle to ensure no diagnostic messages are lost. According to the source code in kunchenguid/no-mistakes, the CLI entrypoint installs a structured logger that directs all output through a dedicated file writer.
How the Logger is Initialized
In cmd/no-mistakes/main.go, the application bootstrap code configures the default slog logger to use the custom writer:
// cmd/no-mistakes/main.go
slog.SetDefault(slog.New(slog.NewTextHandler(cliLogWriter(), nil)))
This setup ensures that every component—including pipeline steps, subprocess executors, and the TUI renderer—writes to the same diagnostic stream.
Safe Path Resolution and Fallback Behavior
The cliLogWriter() function (lines 93-105) implements defensive programming to prevent log-related crashes from aborting pipeline execution:
// cmd/no-mistakes/main.go – lines 93-105
func cliLogWriter() io.Writer {
p, err := paths.New()
if err != nil {
return io.Discard
}
f, err := os.OpenFile(p.CLILog(), os.O_CREATE|os.O_WRONLY|os.O_APPEND, 0o644)
if err != nil {
return io.Discard
}
return f
}
Key implementation details:
- Graceful degradation: If the paths cannot be resolved or the log file cannot be opened (for example, before running
no-mistakes init), the function returnsio.Discardrather than panicking - Atomic appends: The file is opened with
O_APPENDflag, ensuring concurrent pipeline runs cannot corrupt the log with interleaved lines - Automatic creation: The
O_CREATEflag ensures the log file and directory structure are created on first write
Locating and Reading Pipeline Logs
The paths.New() call constructs a Paths value that computes runtime file locations based on the $NM_HOME environment variable.
Default Log File Path
The CLILog() method resolves the concrete file location to:
$NM_HOME/.no-mistakes/logs/cli.log
When $NM_HOME is unset, this defaults to ~/.no-mistakes/logs/cli.log. The file is opened with write-only and append permissions (0o644), preserving a complete chronological history of all CLI invocations.
Real-time Log Inspection with tail
To debug an active pipeline failure, monitor the log file while the command executes:
# Run the pipeline
NM_HOME=$HOME/.no-mistakes no-mistakes run &
# Follow log output in real-time
tail -n +0 -f $NM_HOME/.no-mistakes/logs/cli.log
This approach captures progress information, errors, and detailed step diagnostics that may scroll past too quickly in the terminal interface.
Filtering and Debugging Pipeline Steps
Pipeline implementations in internal/pipeline/steps/*.go emit structured messages via the shared slog logger, making the CLI log file searchable by execution phase.
Step-Specific Markers
The pipeline code prefixes messages with step identifiers, allowing you to isolate specific failure points:
[rebase]– Git rebase operations and conflict detection[push]– Remote synchronization and ref updates[ci]– Continuous integration monitoring and agent coordination
Filter for specific pipeline stages using grep:
# Isolate rebase-related errors
grep '\[rebase\]' $NM_HOME/.no-mistakes/logs/cli.log
# Monitor CI agent status
grep '\[ci\]' $NM_HOME/.no-mistakes/logs/cli.log
Correlating with TUI Status
When the terminal UI (internal/tui/axi_render.go) shows a run as "parked" or "awaiting-agent", the log file contains the underlying awaiting_agent messages. This correlation helps distinguish between:
- Stuck subprocesses (visible in
internal/shellenv/shellenv.goexecution logs) - Missing remote configurations
- Authentication or permission failures
Why cliLogWriter is Reliable for Debugging
The cliLogWriter implementation provides three critical reliability guarantees for production debugging:
- Graceful fallback – If the log directory cannot be created, the writer returns
io.Discard, ensuring log-related errors never abort the pipeline - Atomic appends – The
O_APPENDflag guarantees line-level atomicity, preventing log corruption during concurrent runs - Centralized configuration – The
pathspackage computes the location once, ensuring all components (CLI, daemon, agents) agree on the same file path
Programmatic Access Examples
For automated monitoring or custom debugging scripts, access the log file programmatically:
// Example: Read last 500 bytes of the log
logPath, _ := paths.New()
data, _ := os.ReadFile(logPath.CLILog())
fmt.Printf("Recent log entries:\n%s", string(data[len(data)-500:]))
For CI environments where you need to archive logs after failure:
# Copy logs after a failed run
cp $NM_HOME/.no-mistakes/logs/cli.log ./debug-artifacts/no-mistakes-$(date +%s).log
Summary
- The
cliLogWriter()function incmd/no-mistakes/main.gocreates anio.Writerthat persists allslogoutput to$NM_HOME/.no-mistakes/logs/cli.log - Defensive design ensures the tool falls back to
io.Discardif the log file is unavailable, preventing crashes during early initialization - Step-specific markers (
[rebase],[push],[ci]) in the log file allow targeted filtering of pipeline stages - Atomic append operations preserve log integrity when multiple
no-mistakesprocesses run concurrently - TUI correlation is possible because
internal/tui/axi_render.gorenders the same underlying log messages shown in the CLI log file
Frequently Asked Questions
Where does no-mistakes store its CLI log files?
The tool stores logs at $NM_HOME/.no-mistakes/logs/cli.log, defaulting to ~/.no-mistakes/logs/cli.log when the environment variable is unset. The paths.New() function in internal/paths/paths.go resolves this location consistently across all components.
Why is my no-mistakes command not writing to the log file?
If you run no-mistakes before executing no-mistakes init, the cliLogWriter() function may return io.Discard because the log directory does not exist. The tool intentionally fails silently to io.Discard rather than crashing, so ensure you have initialized the environment or manually created the .no-mistakes/logs directory structure.
How do I view logs while a pipeline is still running?
Use the tail -f command to follow the log file in real-time. Because the file is opened with O_APPEND, you can safely read it while the process writes new entries, making this ideal for debugging long-running rebase or CI monitoring operations.
What do the bracketed tags in the log file mean?
Tags like [rebase], [push], and [ci] indicate which pipeline step emitted the message. These markers are generated by the step implementations in internal/pipeline/steps/*.go and allow you to filter the log for specific workflow stages using tools like grep.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →