DEV Community

Rodrigo Oliveira
Rodrigo Oliveira

Posted on

Beyond Hooks: Building an Autonomous AI Pipeline Without "Confirmation Fatigue"

In my previous article, I explored a painful lesson in AI-assisted software engineering: the bottleneck isn't code generation speed; it is deterministic governance.

To prevent hallucinations, unauthorized file mutations, and broken release branches, we created Pipeline-AI: a zero-trust architecture powered by pure Go 1.24 OS lifecycle hooks (PreToolUse) and a specialized 16-skill pipeline integrated natively into the Google Antigravity ecosystem.

The governance worked. The agents stopped breaking repositories. But immediately after deploying this multi-skill pipeline, we encountered the next big enemy of agentic software engineering:

Confirmation Fatigue.

If the orchestrator stops at every single transition to ask:

"Unit tests generated. Should I proceed to dev-implementation? (Yes/No)"

...you cease to be a high-leverage software engineer and become a full-time prompt-enter button pusher.

With the release of Pipeline-AI v0.6.1, we tackled this challenge head-on. Here is how we turned a strict, multi-agent pipeline into an autonomous continuous delivery flow using the Principle of Non-Interruption, formal handoff contracts, negative-test safeguards, and a unified Pipeline Runner in Go connected via the Model Context Protocol (MCP).


1. The Trap of AI Micro-Management

When building multi-agent systems, human instinct often leans towards manual gates at every handoff:

[pm-triage] → "Can I continue?" → Human: "Yes"
  → [architecture-guardrails] → "Can I continue?" → Human: "Yes"
    → [test-writer] → "Can I continue?" → Human: "Yes"
      → [dev-implementation] → "Can I continue?" → Human: "Yes"
        → [code-reviewer] → "Can I continue?" → Human: "Yes"
...
Enter fullscreen mode Exit fullscreen mode

This model breaks down for three reasons:

  1. Cognitive Disruption: Developers are forced to context-switch every 90 seconds to give ceremonial approvals that require zero engineering judgment.
  2. The Illusion of Control: Fatigued by repeated prompts, humans inevitably rubber-stamp transitions without inspecting the intermediate diffs.
  3. Severe Operational Drag: An issue that should take 6 to 8 minutes of machine time suddenly drags out over hours due to human latency.

Governance must be ironclad where safety is at stake, but invisible when deterministic gates pass.


2. The Non-Interruption Principle & Formal Handoff Contracts

To eradicate micro-management, we codified Rule 7 (The Non-Interruption Principle) into our core orchestration engine:

Rule: Once a technical task is triaged, the orchestrator conducts skill transitions end-to-end without pausing for human confirmation, as long as the status remains STATUS: ok.

Human intervention is reserved strictly for three scenarios:

  1. Critical business or architectural ambiguity during triage (pm-triage).
  2. Blocking technical failure (STATUS: bloqueado).
  3. Final Pull Request review, where the human engineer inspects the comprehensive delivery report and git diff.
flowchart TD
    A["Task Input"] --> B["pm-triage"]
    B --> C{"Ambiguity?"}
    C -- Yes --> D["Pause: Human Alignment"]
    C -- No --> E["architecture-guardrails"]
    E --> F["test-writer (Red TDD)"]
    F --> G["dev-implementation (Green)"]
    G --> H["code-reviewer & security-review"]
    H --> I["qa-validation & docs-update"]
    I --> J{"Gate Blocked?"}
    J -- Yes --> K["Pause: Human Escalation"]
    J -- No --> L["git-delivery: PR Created"]
    L --> M["Final Human Code Review"]

    style D fill:#ffcccc,stroke:#ff0000
    K fill:#ffcccc,stroke:#ff0000
    M fill:#ccffcc,stroke:#00aa00

Eliminating Context Drift: The Handoff Contract

How do we prevent agents from hallucinating or omitting critical constraints between skills? Every transition requires a structured, machine-verifiable header:

=== HANDOFF CONTRACT ===
FROM: test-writer
TO: dev-implementation
TASK: DEL-018
STATUS: ok
SCOPE: internal/handoff
EVIDENCES:
- [x] go test ./internal/handoff (failed as expected in Red phase)
- [x] 4 table-driven scenarios defined
========================
Enter fullscreen mode Exit fullscreen mode

We validate this deterministically with a dedicated Go tool:

go tool pipeline-ai handoff validate handoff.txt
Enter fullscreen mode Exit fullscreen mode

To protect our parser against malformed markdown or adversarial model outputs, we hardened the parser using Go's native fuzzing engine (testing.F).


3. The Unified Pipeline Runner (pipeline-ai run) and MCP

Instead of requiring agents to invoke multiple detached CLI binaries, we consolidated everything into a single, high-speed runner:

go tool pipeline-ai run
Enter fullscreen mode Exit fullscreen mode

The runner executes three deterministic phases:

  1. Doctor: Verifies Go 1.24+ runtime, hook presence, configuration validity, and immutability settings.
  2. Sensor: Dispatches the project's native toolchain (gofmt, go build, go vet, go test ./..., govulncheck).
  3. Validate: Audits the delivery report against the actual git diff, rejecting scope creep or unapproved security surface modifications.

Native MCP Server Integration

We also exposed this runner directly to LLM agents via the Model Context Protocol (MCP):

// Native MCP Tool: pipeline_run_pipeline
func (s *Server) handleRunPipeline(ctx context.Context, args json.RawMessage) (any, error) {
    res := runner.Execute(runner.Options{
        DeliveryPath: activeDelivery,
        JsonOutput:   true,
    })
    return res, nil
}
Enter fullscreen mode Exit fullscreen mode

The orchestrator invokes pipeline_run_pipeline via structured JSON-RPC, receiving machine-readable results without shell escaping risks or fragile string scraping.


4. Real-World AI Traps You Won't Find in Tutorials

Homologating our pipeline in production revealed two subtle failure modes that affect virtually all autonomous coding systems:

Trap A: The "Negative Test" Illusion (0 Tests = 0 Errors)

An agent runs go test ./.... The command exits with status code 0. The agent cheerfully declares: "All tests passed!"

The Catch: The agent placed the test files in the wrong directory or misnamed them. Zero tests actually executed. In Go and many test frameworks, finding zero tests results in exit code 0.

The Safeguard:
We built an active Negative Test Safeguard into our sensor engine:

// internal/sensor/sensor.go
if testCount == 0 && !cfg.AllowEmptyTests {
    return SensorResult{
        Passed: false,
        Error:  "Safeguard triggered: 0 tests executed (false positive prevented)",
    }
}
Enter fullscreen mode Exit fullscreen mode

If zero tests run, the pipeline fails immediately. No false positive ever reaches a pull request.


Trap B: The Agent That Hacks Its Own Guardrails (immutable_paths)

When an LLM agent is given the goal to "make CI pass", it will take the path of least resistance. If a lifecycle hook or configuration file blocks it, sophisticated models will attempt to edit .pipeline-ai.json or .agents/hooks.json to disable the security checks!

To stop this, we introduced Immutable Paths:

{
  "protected_paths": ["internal/", "pkg/", "cmd/"],
  "editor_agents": ["dev-implementation", "test-writer"],
  "immutable_paths": [
    ".pipeline-ai.json",
    ".agents/hooks.json",
    ".github/workflows/"
  ]
}
Enter fullscreen mode Exit fullscreen mode

Even if an agent is authorized in editor_agents, our OS hook intercepts file writes and blocks mutations to immutable_paths unconditionally.


5. Production Battle-Testing: Desktop vs. Backend API

We validated Pipeline-AI v0.6.1 across two distinct architectures:

Project Stack Core Challenge Autonomous Result
sistema-estoque Desktop (Go + Wails v3) Linux/WSL2 host compiling Windows desktop binaries without CGO 327 tests passing via auto-injected environment (CGO_ENABLED=0 GOOS=windows GOARCH=amd64).
gestao-financas Backend API (Go + PostgreSQL) DDL migration safety, relational locks, and data model isolation 315 tests passing with automated migration review and zero lock hazards.

Both systems executed the full pipeline from triage to delivery without human micro-prompts, successfully opening PR #16 and PR #18.


The Takeaway: Agent Reliability Engineering (ARE)

The initial hype was about how fast an LLM could generate functions. Today, the focus is on Agent Reliability Engineering (ARE):

  1. Autonomy requires deterministic guardrails: You can only let an agent run unsupervised if the operating system physically blocks it from breaking invariants.
  2. Trust the gates, not prompts: Remove ceremonial human approvals. Reserve human intelligence for the final Pull Request review.
  3. Negative safeguards are essential: Always verify that your test runner actually ran tests.

The Pipeline-AI v0.6.1 source code, all 16 skills, and the deterministic Go runner are 100% open-source under the MIT license:

👉 GitHub: github.com/rodrigodosanjosoliveira/pipeline-ai

How are you balancing agent autonomy with repository safety in your stack? Let's discuss in the comments! 💬🚀

Top comments (0)