Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Multi-Repo Agentic Workflows: Guardrails, Fast Classifiers, and the Sub-50ms Boundary

How a Cross-Project Lean Sprint Unified Neural Intent Classification with Deterministic CLI Performance

Who this is for — system architects, CLI designers, and AI engineers orchestrating autonomous multi-agent pipelines across multiple decoupled repositories.

Read this if — you want to bridge natural language intent into strict CLI interfaces without sacrificing millisecond-level responsiveness, or you manage multi-agent development workflows across repository boundaries.
Skip this if — you only write standalone single-repo scripts with no performance constraints.

Takeaways

  1. The Sub-50ms Boundary is Absolute: Synchronous keystroke and shell tab-completion paths must remain 100% deterministic (<5 ms); model inference (~200–500 ms) belongs strictly at command invocation time.
  2. GBNF Grammar Constraints Eliminate Hallucination: Constraining local model decoders with BNF grammars guarantees 100% schema validity, ensuring an agent or user argument maps strictly to a declared enum or explicitly abstains.
  3. The Zero-Coding Host Reviewer Pattern: When a host orchestrator restricts itself to read-only diff inspection and delegates all file edits to low-cost worker agents, context bloat disappears and token velocity quadruples.
  4. Plan-First Read-Only Gating Catches Protocol Bugs Early: Forcing subagents to output a concrete file and test plan before granting write access catches missing flags, schema collisions, and test omissions before dirtying the working tree.
  5. Clean Multi-Repo Separation Requires Stable CLI Contracts: Separate tools (harnez, neus, lmcoder) should communicate over bounded JSON CLI contracts rather than internal library imports or shared memory.

1. The Architectural Dilemma: Natural Intent vs. CLI Rigor

As agentic developer tools evolve, a fundamental ergonomic tension emerges:

  • Strict Command-Line Interfaces demand precise flags, canonical enums, and exact syntax (harnez agent start --role developer).
  • Autonomous Agents & Human Users express intent in fuzzy, natural language (harnez agent start --role "review the PR diff" or harnez agent start explorer "audit the SQL queries").

When an agent guesses a near-miss argument (such as --role explorer instead of --role advisor), conventional CLIs fail abruptly with unknown role "explorer". In a long multi-agent workflow, these tiny syntax collisions cause failed turns, retry loops, and human frustration.

The naive solution is tempting: “Why not put an LLM in the shell’s auto-complete function or argument parser to dynamically classify every keystroke?”

In this case study, we walk through the empirical research, the performance constraints that shattered this naive approach, and the robust multi-repo architecture built to solve it.


2. The Empirical Reality: The Sub-50ms Boundary

Before writing code, we dispatched parallel research agents across three repositories:

  • neus: A Go-based neural search and AST-indexing engine.
  • lmcoder: A local model lifecycle manager serving llama.cpp instances (127.0.0.1:8736 fast chat, :8734 primary chat, :8746 embeddings).
  • harnez: The multi-agent harness and developer CLI.

The research subagents benchmarked local small models (Qwen2.5-0.5B and Qwen2.5-1.5B) executing GBNF-constrained enum classification on local AMD APU hardware:

Model / StrategyLatency (p50 / p95)Cold StartSchema ValidityExact Match Rate
Qwen2.5-0.5B (GBNF Enum)176 ms / 279 ms703 ms100%34.8% (95.7% safe outcome)
Qwen2.5-1.5B (GBNF Enum)285 ms / 410 ms1.52 s100%56.5% (82.6% safe outcome)
Multi-field Extraction1.45 s / 2.10 s—100%70.0%
flowchart LR
    subgraph Budget["Human Keystroke Budget (<50 ms)"]
        K[Keystroke / Tab] --> Fast[Cobra Offline Prefix Match < 2 ms]
        Fast --> OK[Instant Shell Completion]
    end

    subgraph Neural["Neural Model Inference (176 - 285 ms)"]
        K2[Keystroke / Tab] --> LLM[Local Fast LLM :8736]
        LLM -.-> Lag["Severe Terminal Lag & Stutter (Unacceptable)"]
    end

The Architectural Takeaway

Synchronous shell completion must never depend on neural inference.

Interactive tab-completion must remain strictly deterministic, instant (<5 ms), and offline. Neural classification belongs exclusively at command invocation time—resolving natural language after the user presses Enter.


3. The Multi-Repo Assembly Line: Step-by-Step Architecture

To implement this vision without coupling codebases, we established a strict contract boundary across neus and harnez.

flowchart TD
    subgraph CLI_Invocation["User / Subagent Command Invocation"]
        CMD["harnez agent start 'review the commit diff'"]
    end

    subgraph Step1["Step 1: Harnez Argument Cascade"]
        CMD --> CheckExact{"1. Exact Match in spec/agent.yaml?"}
        CheckExact -->|Yes| Direct["Direct Role (developer, reviewer...)"]
        CheckExact -->|No| CheckAlias{"2. Static Alias Match?"}
        CheckAlias -->|Yes (e.g. explorer -> advisor)| AliasRole["Resolved Canonical Role"]
        CheckAlias -->|No| CheckOmitted{"3. Role omitted entirely?"}
        CheckOmitted -->|Yes| PromptInfer["Extract prompt summary"]
        CheckOmitted -->|No| RawArg["Use raw unknown argument"]
    end

    subgraph Step2["Step 2: External Neus Classify Contract"]
        PromptInfer --> NeusCLI["neus classify --json --classes orchestrator,developer,reviewer,advisor '<input>'"]
        RawArg --> NeusCLI
        NeusCLI --> FastLMCoder["lmcoder Resident Service (127.0.0.1:8736)"]
        FastLMCoder --> GBNF["GBNF Grammar Constraint (+ unknown abstention token)"]
    end

    subgraph Step3["Step 3: Policy Enforcement"]
        GBNF --> Result{"Result Class"}
        Result -->|Canonical Role| SpawnCheck["CheckSpawn Policy & Permission Verification"]
        Result -->|Abstain / Timeout / Error| Fallback["Show Known Roles & Aliases Catalog"]
        SpawnCheck --> SessionLaunch["Start Isolated Subagent Session"]
    end

1. neus classify: A Stable, Bounded Interface

Instead of importing internal Go packages across repo boundaries, neus exposes a clean CLI command:

neus classify --json --classes orchestrator,developer,reviewer,advisor "audit SQLite performance"

Output:

{
  "class": "advisor",
  "input": "audit SQLite performance",
  "classes": ["orchestrator", "developer", "reviewer", "advisor"],
  "model": "",
  "latency_ms": 536,
  "source": "model"
}

If the input is an exact or unique prefix match (e.g. "review"), it short-circuits in <1 ms with "source": "prefix". If the model is uncertain, it selects the private unknown grammar token and exits with code 2 (abstention).

2. harnez: The Dynamic Resolver Cascade

When harnez agent start is called:

  1. Exact match: Checks canonical roles defined in spec/agent.yaml.
  2. Static aliases: Checks rich aliases (e.g. coder $\rightarrow$ developer, explorer $\rightarrow$ advisor).
  3. Prompt Auto-Inference: When --role is omitted, the prompt is sent to neus classify with a 1.5s bounded timeout. If classified as reviewer or advisor, Harnez prints an advisory notice and sets the role, falling back safely to developer.
  4. Positional Ergonomics: harnez agent start explorer "audit queries" automatically extracts the leading role token without requiring --role.

4. The Agentic Sprint in Action: Guardrails & Review Discipline

The implementation was delivered using the Lean Fresh-Handoff Sprint workflow. The Host Orchestrator operated under strict invariants:

Invariant 1: Zero Coding by the Orchestrator

The host never edited Go source files, YAML configs, or test fixtures. All changes were authored by dispatched codex:luna:med developer subagents. This kept the orchestrator’s context window pristine and dedicated entirely to diff review.

Invariant 2: Plan-First Read-Only Gating

Every developer worker was first launched in read-only mode ("read-only: plan ticket XXX..."). The orchestrator reviewed the plan (schema fields, test cases, error paths) before issuing a resume command with write authority.

[Host]   harnez agent start --role developer --model codex:luna:med "read-only: plan ticket 686..."
[Worker] Emits concrete plan: files, GBNF enum handling, test mock strategy.
[Host]   Reviews plan -> "Plan approved; implement milestone M1 now..."
[Worker] Implements, runs tests, commits, and reports back.

Invariant 3: Quota-1 Test Budget

Workers were bounded to a single full test suite run (make test-q1) before committing. When tests failed, the worker had to inspect the captured failure log, correct the root cause, and re-verify once rather than thrashing in an infinite loop.


5. Honest Post-Mortem: Real Bugs Caught in the Loop

No engineering system is built without friction. Here are the candid failures encountered and resolved during this session:

graph TD
    subgraph Bug1["Bug 1: Test Server Goroutine Hang"]
        B1[Worker writes HTTP timeout test] --> H1[httptest.Server handler blocks indefinitely]
        H1 --> TO[Go test hits 10-minute timeout]
        TO --> F1[Fix: Bound handler wait with context cancellation]
    end

    subgraph Bug2["Bug 2: Abstention Token Assertion Inversion"]
        B2[Worker adds 'unknown' to GBNF grammar] --> A2[Test asserts JSON classes omits 'unknown']
        A2 --> TF[Test fails on class list mismatch]
        TF --> F2[Fix: Align test assertions with abstention schema]
    end

    subgraph Bug3["Bug 3: Test Environment Pollution"]
        B3[Live prompt inference added to CLI] --> T3[Legacy CLI tests fail expecting static stderr]
        T3 --> F3[Fix: Inject deterministic abstaining classifier in unit tests]
    end
  1. The Goroutine Server Hang: A simulated network timeout test spawned an HTTP test server that waited indefinitely, triggering Go’s 10-minute test timeout. The worker diagnosed the stuck channel, bounded the handler to 1s, and re-verified cleanly.
  2. Abstention Assertion Inversion: The developer added unknown as a private grammar token for model refusals, but wrote tests asserting that the public class list excluded unknown. Reviewing the diff during milestone inspection caught the failure immediately.
  3. Legacy Test Pollution: Adding prompt auto-inference caused existing unit tests to capture classifier logs on stderr. Injecting a mock classifier during test suite execution isolated the tests from ambient host model state.

6. The Result: Unified, Observable Ergonomics

By the end of the sprint, the entire subagent workflow was verified live:

# 1. Starting an agent with natural language prompt (inferred role: advisor)
$ harnez agent start "audit the sqlite indexing queries in neus"
harnez: inferred role "advisor" (aliases: explorer, planner) from prompt
[session info: id=01a103... name=codex-01a103 role=advisor]

# 2. Positional role shorthand
$ harnez agent start review "check diff on HEAD~1"
[session info: id=01a104... name=codex-01a104 role=reviewer]

# 3. Fuzzy substring session resumption
$ harnez agent resume classify "run the CLI tests again"
harnez: matched session "neus-classify-dev" (id: 01a10277-43c9...)
[resuming session neus-classify-dev...]

# 4. Contextual directory resumption
$ cd /home/uwe/projects/neus && harnez agent resume "continue with M2"
harnez: resuming latest active session "neus-classify-dev" (last active 2m ago)

7. Rules for the Multi-Repo Fleet

  1. The Performance Fence: Any operation running on a keystroke or shell tab-completion hook must complete in under 5 ms. Never invoke neural models or external network sockets synchronously.
  2. The Grammar Guard: When interfacing natural language with code execution, never parse raw unstructured LLM text. Constrain outputs with GBNF or JSON Schemas, and always provide an explicit unknown abstention path.
  3. The Orchestrator’s Fence: Keep host orchestrators out of the code editor. Review diffs, run verification targets, update tickets, and delegate implementation to low-cost, disposable subagents.