Blog

Agent-First Monorepo Practice

#agent-first#monorepo#terraform#ci

How we organize repository facts, dependencies, checks, and CI so agents can work with steadier context.

01

Monorepo

We chose a monorepo.

The reason was simple: we wanted the team to work inside one fact space. Product entrypoints, data paths, automation, delivery configuration, documents, and retrospectives live together. People collaborate there. Agents understand tasks there. A request should not have to pass through layers of spoken background before it becomes actionable; it should be able to see its boundaries, existing capabilities, and acceptance checks inside the repository.

Terraform follows the same belief.

Infrastructure, environment boundaries, dependency relationships, and delivery shapes should become versioned facts. Agent-first work needs agents to see as much of the real world as possible. When agents can see, they can reason. When they can read, they can continue. In practice, the ceiling is shaped not only by model quality, but also by how much truth we move from meetings, chats, and personal memory back into the repository.

For us, the repository is a workshop with the lights on. Every commit adds visibility. Every retrospective corrects a signpost.

When an agent walks in, it should read a running system and a durable work scene.

Agent-first monorepo
intent
  |
router -> facts -> action surface -> guard -> artifact
            ^                         |
            +--------- eval ledger ---+
02

When the repository grew, problems surfaced

At first, it was fast.

In the early days, the monorepo made the rhythm light. A request arrived and the entrypoint was nearby. Delivery changed and the configuration sat beside it. New teammates and agents entered through the same path. We liked that feeling: context gathered in one place, discussions could point to files, delivery could land on paths, and retrospectives could return to the same system.

Then the repository kept growing. New applications arrived. New checks arrived. Old plans arrived too. The repository moved from a clean desk to a factory under expansion. Every corner had material. Every aisle could lead to another aisle.

Dependencies became harder to manage.

A small change could touch runtime shape, data contracts, automation scripts, delivery flow, and document indexes. People could navigate with experience. Agents needed clearer signs. They read carefully, and they can misread carefully. They follow the nearest clue, and sometimes treat historical material as current fact. As the repository grows, that error gets amplified.

We started seeing recognizable patterns. Agents got lost in the repository, read older material first, and acted along a historical path. A capability already existed, while a new version appeared in a nearby directory. A local result looked finished, while the wider dependency surface remained unexamined.

These problems looked like repository scar tissue. Duplicate implementation added another shadow to the codebase. Implicit dependencies added review cost. Scattered entrypoints added another walk for the next task.

We treated these situations as rework signals. They told us the repository was growing, and the agent working environment had to become clearer at the same pace.

Fact layers
repo/
  entrypoints/
  facts/
  contracts/
  tools/
  checks/
  artifacts/
03

Building the feedback loop

Rework became an alarm.

The first rework felt like a manual reminder. Repeated rework felt like system telemetry. We started recording causes: distant entrypoints, hidden dependencies, scattered facts, late checks, weak CI signals. The useful question was not just where the agent went wrong; it was which part of the repository path had not been paved clearly enough.

That changed how we optimized the repository.

We asked how the next agent could enter the same type of task, find facts faster, identify dependencies earlier, and deliver with steadier evidence. That changed the engineering posture: rework stopped being only a cost and became an input for improving entrypoints, indexes, declarations, and checks.

Over time, rework signals became a steadier way to shape the repository. Entrypoints, dependencies, disclosure, checks, and CI moved into one loop, so the next task could give agents a clearer path first.

Feedback loop: writing rework back into the system
rework event
  |
  v
classify cause
  |
  +-- entrypoint too far  -> move facts closer
  +-- dependency hidden   -> declare contract
  +-- fact scattered      -> promote index
  +-- check too late      -> bind check
  +-- CI signal weak      -> add workflow signal
  |
  v
next agent run
04

The five practices that worked

Over time, we learned that useful optimization is rarely decorative.

It helps agents guess less, read more, wander less, and verify earlier.

Proximity principle

Adding a blog entry to a public site is a small but concrete task. The agent should first read that site's local notes, delivery manifest, and existing navigation copy, confirm whether the surface is public, static, or runtime-backed, then update the blog index, article page, and language dictionary. It starts at the worksite, then checks the global index for boundaries, instead of scanning the whole repository or borrowing a neighboring product page pattern by accident.

Adding a public blog entry
public-site/
  README
  delivery.manifest
  navigation.copy
  pages/
    blogs/
      index
      article

task("add blog entry")
  -> read public-site/README
  -> read public-site/delivery.manifest
  -> update navigation.copy
  -> add pages/blogs
  -> run local checks

Declare dependencies

A user workspace may call content, entity, and document capabilities. Those relationships used to live in habit and environment wiring. Now the caller declares upstream capabilities, target environments, and injected variables in its delivery manifest. After reading it, an agent can see which URLs are injected by the platform, which dependencies follow the same environment, which ones use a stable entry, and which fields are only local placeholders.

Dependency ledger for a user workspace
consumer: user_workspace
requires:
  content_service:
    inject_as: CONTENT_BASE_URL
    environment: same_or_stable
  entity_service:
    inject_as: ENTITY_BASE_URL
    environment: stable_entry
  document_service:
    inject_as: DOCUMENT_BASE_URL
    environment: same_or_stable

agent_check:
  impact_surface = requires.keys()

Disclose upward

A local delivery manifest makes one directory readable. Cross-domain tasks need a map. We roll local manifests into a capability map, dependency summary, runtime state, and document reference index. When agents route a task, they read the map first and then land in the target directory. If a task could belong to the public site, the user workspace, or a data collection job, the first route should come from generated facts rather than directory-name guessing.

From local manifest to global map
app.delivery.manifest
      |
      v
fact_generator
  +-- capability_map
  +-- dependency_summary
  +-- runtime_state
  +-- doc_reference_index
      |
      v
agent_route(task) -> target_unit

Checks over documents

This article is a useful example. Changing article content, article routes, navigation entrypoints, and language dictionaries should resolve into lint, build, static page generation, and a browser smoke check. Documentation says the page should be readable; checks prove the page opens. The build proves routes and types still hold; the browser proves readers are not staring at an error screen.

Acceptance path for this blog change
changed:
  src/content/blogPosts
  src/pages/blogs
  src/navigation
  src/i18n

resolve_checks(changed)
  -> lint
  -> build
  -> static_page_generation
  -> browser_smoke("/blogs/agent-harness-monorepo")

Use CI well

After the PR is sent, CI takes over the repetitive and strict checks people tend to skip: generated fact drift, path quality baselines, preview delivery, and runtime checks. The agent submits code and a bundle of evidence. Reviewers do not only see a claim that the work is done; they see a chain from changed files, to check entrypoints, to run results, to the final artifact.

Evidence chain after a PR
pull_request
  |
  +-- generated_fact_drift
  +-- quality_baseline
  +-- preview_delivery
  +-- runtime_checks
  |
reviewer sees:
  artifact + evidence + verdict
05

Boundaries and bills grow together

After these optimizations landed, the strongest change came from work behavior itself. Agents started to behave more like teammates who had done the onboarding. They looked for the nearest entrypoint, then read the global index. They treated dependencies as readable facts. Reviewers could also understand why an agent acted, what it read, and where it still missed context.

Duplicate implementation became easier to catch early. Local notes, generated indexes, and checks reminded agents that existing capabilities should be reused, extended, or connected, rather than quietly copied.

Repository scar tissue became manageable. Each wrong turn, each rework event, and each CI failure could return to entrypoints, dependencies, disclosure, checks, and pipelines as a guardrail for the next run.

We increasingly believe AI can help teams manage infra, inspect logs, break down development requests, and keep improving agent development efficiency. As long as the repository keeps exposing facts, the useful boundary of agents keeps expanding. It can read delivery manifests and understand environment boundaries; inspect logs and isolate an error window; turn a request into paths, checks, and acceptance criteria; and feed one failure back into the guardrails for the next run.

This path is exciting. The team gives more facts to agents. Agents return more evidence to the team. They begin to feel like colleagues who know where the material lives and when a question belongs to a check.

At the same time, the token bill grows with perfect honesty. The more capable the agent becomes, the more the bill behaves like an ambitious teammate, reminding us every month that efficiency has weight.