Architectural Patterns in no-mistakes: 11 Design Patterns Powering the AI-Driven Go Daemon

The no-mistakes project employs eleven distinct architectural patterns—including Command, Factory, Strategy, Pipeline, Observer, and Dependency Injection—to create an extensible, testable, and concurrent AI-driven pipeline system.

The no-mistakes repository is a Go-based CLI application that runs as a long-lived daemon, orchestrating AI-driven steps through a sophisticated pipeline. By deliberately separating concerns and leveraging established architectural patterns, the codebase maintains safety under concurrent execution while remaining extensible for new AI providers and pipeline steps.

Command Pattern: Structured CLI with Cobra

All user-facing commands in no-mistakes are built using the cobra framework, implementing the Command pattern. Each sub-command—such as daemon start or axi run—exists as a concrete command object that encapsulates its own execution logic and flag parsing.

In internal/cli/daemon_cmd.go, the newDaemonCmd function constructs the command hierarchy and wires each command's RunE handler:

// internal/cli/daemon_cmd.go
func newDaemonCmd() *cobra.Command {
    cmd := &cobra.Command{
        Use:   "daemon",
        RunE: func(cmd *cobra.Command, args []string) error {
            // execution logic
        },
    }
    return cmd
}

Singleton Pattern: Process-Wide Mutual Exclusion

To guarantee that only one daemon instance owns a given NM_HOME directory, no-mistakes implements a Singleton pattern through an exclusive OS file lock. The acquireSingletonLock function in internal/daemon/lock.go creates a process-wide lock before any destructive startup work begins.

// internal/daemon/lock.go
lock, err := acquireSingletonLock(paths)
if err != nil {
    log.Fatalf("cannot start daemon: %v", err)
}
defer lock.Release()

This ensures mutual exclusion across processes, preventing concurrent daemon instances from corrupting shared state.

Factory Pattern: Pluggable Step and Agent Creation

The architecture relies heavily on Factory methods to decouple object creation from usage, enabling runtime customization of the pipeline.

StepFactory

The StepFactory type in internal/daemon/manager.go produces the ordered list of pipeline steps:

type StepFactory func() []pipeline.Step

Callers can inject a custom factory or fall back to the default steps.AllSteps implementation, allowing teams to modify pipeline behavior without altering core logic.

AgentFactory

Similarly, the newPipelineAgent function constructs agent chains (including steering and fallback layers) based on resolved configuration:

func newPipelineAgent(ctx context.Context, cfg *config.Config) (agent.Agent, error)

Strategy Pattern: Runtime Agent Selection

The Strategy pattern enables interchangeable AI providers at runtime. In internal/config/config.go, the ResolveAgent method selects the concrete implementation—Claude, Codex, or others—based on configuration.

The selected strategy is then wrapped with steering logic and fallback chains in newPipelineAgent, allowing the pipeline core to remain agnostic of specific AI providers while supporting multiple strategies simultaneously.

Pipeline and Chain-of-Responsibility: Step Execution Flow

The core execution engine implements a Pipeline pattern (a variant of Chain-of-Responsibility) where steps are linked in an ordered slice. Each step implements the Step interface defined in internal/pipeline/pipeline.go:

type Step interface {
    Name() types.StepName
    Execute(*StepContext) (*StepOutcome, error)
}

The executor iterates through the slice, handing control to each step sequentially via the Execute method. This structure allows steps to be added, removed, or reordered without modifying the execution engine.

Observer Pattern: Asynchronous Event Broadcasting

For decoupling the daemon from its consumers, no-mistakes employs the Observer (Publish-Subscribe) pattern. The RunManager in internal/daemon/manager.go exposes a Subscribe method that registers channels for event delivery:

sub, unsub := daemonManager.Subscribe(runID)
defer unsub()

for ev := range sub {
    fmt.Printf("Run %s event: %s\n", ev.RunID, ev.Type)
}

The broadcast method pushes events to all subscribers, enabling multiple UI or external listeners to receive updates without blocking the pipeline.

State Pattern: Durable Session Management

Review and fix phases utilize the State pattern through RunSessions, which maintain durable session IDs per role (reviewer/fixer). The StepContext.RunAgentSession method in internal/pipeline/pipeline.go either initiates a cold run or reuses an existing session:

func (ctx *StepContext) RunAgentSession(agent Agent, sessionID string) (Result, error)

This effectively switches between state objects based on availability, preserving context across pipeline iterations.

Dependency Injection: Testable Component Wiring

The RunManager implements Dependency Injection through its constructor, NewRunManager, which explicitly receives implementations of the database layer, path utilities, and step factories:

func NewRunManager(db db.DB, paths paths.Paths, factory StepFactory) *RunManager

This explicit wiring eliminates hidden global state and facilitates unit testing by allowing mock implementations to be injected during test execution.

Context Cancellation: Graceful Shutdown Propagation

All long-running operations respect Go's context.Context for cancellation propagation. In internal/daemon/manager.go, the resumeRecoveredRun function creates a cancellable context using context.WithCancelCause:

runCtx, cancel := context.WithCancelCause(parentCtx)

This context flows through the entire pipeline, ensuring that shutdown signals propagate correctly to AI agents and subprocesses, enabling graceful termination.

Adapter Pattern: Cross-Platform Abstraction

Platform-specific behaviors are isolated using the Adapter pattern through Go's build constraints. Files like internal/winproc/harden_windows.go and internal/daemon/lock_unix.go provide OS-specific implementations selected at compile time:

  • *_windows.go implements Windows service hardening
  • *_unix.go implements Unix file locking

This approach presents a unified API to the rest of the application while handling platform differences transparently.

Repository Pattern: Data Persistence Abstraction

The internal/db package implements the Repository pattern, providing a clean API for persistence without exposing SQL details to business logic. Functions like GetActiveRuns and UpdateRunErrorStatus abstract the underlying storage mechanism, allowing the daemon to interact with data through domain-oriented methods rather than database queries.

Adding a Custom Pipeline Step

To extend the pipeline, implement the Step interface and register it in the factory:

// mystep.go
type MyStep struct{}

func (s *MyStep) Name() types.StepName { return "my-step" }

func (s *MyStep) Execute(ctx *pipeline.StepContext) (*pipeline.StepOutcome, error) {
    // Custom logic
    return &pipeline.StepOutcome{ExitCode: 0}, nil
}

// Register in factory
func AllSteps() []pipeline.Step {
    return []pipeline.Step{
        &steps.Checkout{},
        &steps.MyStep{},  // New step
        &steps.Review{},
    }
}

Summary

  • Command Pattern structures the CLI using Cobra with discrete command objects for each operation.
  • Singleton Pattern ensures single-daemon execution through OS-level file locking in internal/daemon/lock.go.
  • Factory Pattern decouples step and agent creation via StepFactory and newPipelineAgent in manager.go.
  • Strategy Pattern enables runtime selection of AI providers through config.ResolveAgent.
  • Pipeline Pattern executes ordered steps via the Step interface in internal/pipeline/pipeline.go.
  • Observer Pattern facilitates asynchronous event broadcasting through RunManager.Subscribe.
  • State Pattern manages durable agent sessions through StepContext.RunAgentSession.
  • Dependency Injection makes RunManager testable via explicit constructor parameters.
  • Context Cancellation ensures graceful shutdowns through context.WithCancelCause.
  • Adapter Pattern handles platform differences via build-constrained files.
  • Repository Pattern abstracts data access in the internal/db package.

Frequently Asked Questions

What is the purpose of the StepFactory in no-mistakes?

The StepFactory is a function type defined in internal/daemon/manager.go that produces a slice of pipeline.Step objects. It decouples the pipeline construction from execution, allowing developers to inject custom step sequences or modify the default steps.AllSteps behavior without changing the core daemon logic.

How does no-mistakes ensure only one daemon runs at a time?

The application implements a Singleton pattern using an exclusive OS file lock. The acquireSingletonLock function in internal/daemon/lock.go creates a lock file in NM_HOME before startup, preventing multiple instances from running concurrently and potentially corrupting shared state.

Can I swap the AI provider without modifying the core pipeline?

Yes. The Strategy pattern implemented in internal/config/config.go via ResolveAgent allows runtime selection of AI providers (Claude, Codex, etc.). The selected agent is wrapped with steering and fallback logic in newPipelineAgent, enabling interchangeable strategies without altering the pipeline's step execution code.

How does the daemon communicate progress to the CLI?

Communication uses the Observer pattern through the RunManager.Subscribe method. The CLI registers a channel to receive events, and the daemon broadcasts updates asynchronously via the broadcast method. This decouples the producer (daemon) from consumers (CLI, UI) and supports multiple simultaneous listeners.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →