Map
↑acai.sh blog

Specsmaxxing β€” Acceptance Criteria as the Primary Artifact

Wiki summaryspec-driven-developmentai-codingacceptance-criteria ↳ show in map Markdown
title
Specsmaxxing β€” Acceptance Criteria as the Primary Artifact
type
summary
summary
acai.sh's author on numbered acceptance-criteria IDs as the missing link between agent-written code and a stable spec
parent
acai-blog
tags
spec-driven-development, ai-coding, acceptance-criteria
created
2026-05-03
updated
2026-05-03

A founder's-essay-shaped post from the author of acai.sh arguing that the bottleneck in agent-assisted development isn't model quality or context window β€” it's that the spec lives in the developer's head and gets relitigated every session. The proposed fix is mechanical: number every requirement, reference those numbers in the code that satisfies them, and track acceptance coverage alongside test coverage.

The article is a recovery-from-overengineering story. The author calls the previous phase "AI psychosis" β€” pulled in directly from HandyAI's "Your CEO is suffering from AI psychosis" piece but applied self-critically. Specifically: drafting elaborate PRDs/TRDs, building skill libraries, recruiting "an army" of subagents, breaking the "vibe-coding sound barrier" with a 1.5-hour unattended run. Output worked but was still sloppy. The diagnosis: "using AI to build AI harnesses for building products, rather than just using AI to build the damn product."

The serendipity moment

The pivot is a small observation. A subagent unprompted started numbering requirements:

AUTH-1: Accepts `Authorization: Bearer <token>` header
AUTH-2: Tokens are user-scoped...
AUTH-3: Rejects with 401 Unauthorized

…and referencing those tags in the implementation:

// AUTH-1
const authHeader = req.headers["authorization"];
// AUTH-2
const isAuthorized = verifyBearerToken(authHeader);
// AUTH-3
if (!isValid) return res.status(401).json({ error: "Unauthorized" });

The author's first reaction is the conventional one β€” this is tight coupling, refactoring nightmare. The second-thought reframe is that the coupling is the point: the tags become a navigation index, a reviewer's checklist, an artifact that says exactly where in the codebase a requirement is satisfied or tested. The tags get a name: ACIDs (Acceptance Criteria IDs), the central concept worth pulling out as acceptance-criteria-ids.

feature.yaml

The article positions a YAML format as the sweet spot between unstructured .md (no IDs, no machine readability) and EARS / Gherkin (rigid, tedious to write):

feature:
    name: imaginary-api-endpoint
    product: api
    description: ...

components:
    AUTH:
      name: Authn and Authz
      requirements:
        1: Accepts Authorization header with `Bearer <token>`
        1-1: Token must be non-expired, non-revoked
        2: Respects the scopes configured for the owner
        2-note: See `access-tokens.SCOPES.1` for complete list of supported scopes

constraints:
    ENG:
      description: Cross-cutting or under-the-hood requirements
      requirements:
        1: All actions are idempotent
        2: All HTTP 2xx JSON responses wrap their payload in a root `data` key

The schema separates components (functional requirements) from constraints (cross-cutting). IDs are stable hierarchical numbers. *-note siblings hold cross-references. deprecated and replaced_by flags carry history inline rather than in git.

The thought experiment

The piece's strongest argument is buried in the "Future Gazing" section. Imagine code generation is instant, free, and deterministic on prompt input. If output is unsatisfactory you don't hand-edit β€” you extend the prompt. In that limit, the only thing of lasting value is the acceptance criteria. The spec.

The author then makes a chronological move: in the past we wrote down procedures (code), then invariants (unit tests), then deltas (prompts). All three are becoming "largely disposable, or invisible, when they used to be the primary object of our attention." The spec is what survives. It already exists in heads and conversations; the choice is just whether to write it down before the bug report or after.

This is the same shape of argument as Rawquery's "average is all you need": when an artifact becomes cheap, attention moves to the upstream artifact that still has to be authored. Code is becoming the cheap artifact; specs become the expensive one.

From specsmaxxing β†’ testmaxxing β†’ reactive

Two follow-on phases the author sketches:

  1. Testmaxxing. When code generation outpaces reading speed, confidence-that-it-matches-spec becomes the bottleneck β€” so QA and observability ROI explodes. Acai.sh, today, is only the spec-to-implementation half; the QA-feedback half is on the roadmap.
  2. Reactive software factories. Specs + tight QA + reliable CI = the LLM can react autonomously to a failed test or alert without human intervention. The author notes "every well-funded software team on earth is currently busy building their own bespoke solution for this." Charlie Labs, botctl, superhq, flue are all distinct stabs at parts of this surface.

Comparison-to-others section worth knowing

The author rates four adjacent tools, which doubles as a future-ingest reading list:

  • GitHub SpecKit β€” characterized as "vibe coding with extra steps." Augments agents with prompts and skills, doesn't track ACID-style alignment.
  • OpenSpec β€” the rejection here is philosophical: OpenSpec says specs describe how systems currently behave. Acai says specs describe how systems should behave; current behavior is transient.
  • Kiro β€” converts unstructured markdown into EARS syntax. Author dislikes both endpoints; feature.yaml is positioned as the middle.
  • Traycer.ai β€” uses plain .md files; Acai is more opinionated about format.

Pragmatic limits the author calls out

  • Stable numbering is load-bearing. Re-numbering a spec means re-aligning code references. The deprecated and replaced_by flags exist for this reason.
  • One spec per feature β€” cross-cutting feature specs travel across repos (frontend / backend / microservice), but committing to a single feature boundary upfront is a discipline cost.
  • No design/UI in specs. "Specs are for behavior, and constraints, and nothing else." Get it working to-spec first; nail-polish last.
  • Adoption requires the YAML format, plus the dashboard for the review surface (the OSS includes a self-hosted server option).

Honest readout

The strongest claim is the small one: numbered acceptance criteria with code-side references make agent output reviewable in a way unstructured .md doesn't. The dashboard, push workflow, and "reactive software factory" framing are the upsell β€” fair to the post but not load-bearing on whether ACIDs themselves are useful. You can adopt the ID-and-reference convention without buying any of the rest.

The recovery-from-AI-psychosis framing is the second valuable thing. It's the author saying out loud what Lalit, Cantrill, and Bennett have all said in their own ways: there is a stable point between vibe-coding and agent-armies, and finding it requires throwing out a lot of work.

See also