# How to Debug Pipeline Issues Using cliLogWriter Output in no-mistakes

> Debug pipeline issues in no-mistakes by analyzing cliLogWriter output in cli.log. Inspect step-specific markers to pinpoint and resolve failures efficiently.

- Repository: [Kun Chen/no-mistakes](https://github.com/kunchenguid/no-mistakes)
- Tags: how-to-guide
- Published: 2026-07-03

---

**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`](https://github.com/kunchenguid/no-mistakes/blob/main/cmd/no-mistakes/main.go), the application bootstrap code configures the default `slog` logger to use the custom writer:

```go
// 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:

```go
// 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 returns `io.Discard` rather than panicking
- **Atomic appends**: The file is opened with `O_APPEND` flag, ensuring concurrent pipeline runs cannot corrupt the log with interleaved lines
- **Automatic creation**: The `O_CREATE` flag 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:

```bash

# 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`:

```bash

# 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`](https://github.com/kunchenguid/no-mistakes/blob/main/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.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/shellenv/shellenv.go) execution 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:

1. **Graceful fallback** – If the log directory cannot be created, the writer returns `io.Discard`, ensuring log-related errors never abort the pipeline
2. **Atomic appends** – The `O_APPEND` flag guarantees line-level atomicity, preventing log corruption during concurrent runs
3. **Centralized configuration** – The `paths` package 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:

```go
// 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:

```bash

# 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** in [`cmd/no-mistakes/main.go`](https://github.com/kunchenguid/no-mistakes/blob/main/cmd/no-mistakes/main.go) creates an `io.Writer` that persists all `slog` output to `$NM_HOME/.no-mistakes/logs/cli.log`
- **Defensive design** ensures the tool falls back to `io.Discard` if 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-mistakes` processes run concurrently
- **TUI correlation** is possible because [`internal/tui/axi_render.go`](https://github.com/kunchenguid/no-mistakes/blob/main/internal/tui/axi_render.go) renders 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`](https://github.com/kunchenguid/no-mistakes/blob/main/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`.