The 170,000-Line Go CLI That Treats AI Agents as First-Class Users
Most CLI tools bolt on `--json` and call it Agent support, but Agents choke on string-based errors, flat command structures, and missing intent routing. lark-cli demonstrates that structured error contracts, trust-layered commands, and embedded Agent manuals directly raise Agent success rates—and that these contracts must be enforced by lint, not documentation, because a silently changed error type causes an Agent to loop and fail in front of a user.
lark-cli spans 170,000 lines of Go, 200+ commands, and 18 business domains, but its real weight is architectural. Every design decision starts from the premise that an AI Agent is a second-class user, not an afterthought. Commands are split into three trust layers with a `+` prefix isolating stable Shortcuts from raw API calls. A six-phase execution pipeline handles identity resolution, scope pre-checks, and validation before any business logic runs, so the Agent never has to guess about permissions or parameter formats.
The error system is the standout: nine exhaustive, lint-enforced categories return structured JSON on stderr, letting Agents route on `type` and `subtype` fields instead of parsing human-readable strings. Skill files embedded in the binary give Agents intent-routing tables and prerequisite checks that `--help` never could. Security treats every Agent-supplied flag as untrusted input, with a virtual filesystem layer, output scanning, and mandatory dry-run support.
A factory pattern with lazy-loaded function fields makes 200+ commands independently testable without a DI framework. The output envelope unifies data, metadata, and system notifications like version updates into a single JSON structure. Taken together, these patterns form a transferable blueprint for any CLI that will be called by coding agents.
Agent-Native design is not a feature flag; it is a second user persona that reshapes error contracts, command topology, and security posture from the first line of code.
String-based error handling is the single biggest failure point for Agent-facing CLIs—once an Agent routes on error text, any wording change becomes a breaking change.
Lint-enforced error contracts are a higher-reliability mechanism than documentation or code review because they prevent regressions at the CI level, where Agents cannot silently break.
The three-layer command system solves a real coordination problem: Agents need to know which commands carry framework guarantees and which are thin API wrappers with no safety net.
Embedding Skill files in the binary solves version skew between the CLI and the Agent's operating knowledge—an upgraded CLI cannot leave an Agent reading stale instructions.
Treating Agent input as untrusted is not paranoia; prompt injection and looped retries make Agents a fundamentally different threat model than human typists at a terminal.
Factory patterns with function fields are underused in Go CLIs; they give the testability of dependency injection without the complexity of a framework.
The `_notice` envelope field is a quiet but powerful pattern: system notifications piggyback on the success response rather than requiring a separate channel or breaking output parsing.
Most CLI tools stop at 'add a `--json` flag'; lark-cli shows that structured output is table stakes, and the real work is in structured errors, layered commands, and Agent-readable manuals.
An Agent that cannot distinguish a missing-scope error from a network timeout will retry the wrong remediation and erode user trust—error taxonomy is a reliability primitive, not a UX nicety.