A monorepo is a convenient way to manage multiple services in a single repository, and it is a dangerous environment for an autonomous agent that does not understand service boundaries. The convenience of shared libraries and unified CI cuts both ways: a change to a shared utility can affect five services at once, and an agent working on a billing bug might inadvertently import a function from an auth library that violates the intended dependency boundary.
We built Codepylon's monorepo scoping system to solve a specific failure mode we kept seeing in early tests: the agent would be given a task scoped to one service, would pull in context from structurally adjacent services during its reasoning, and would sometimes generate a diff that modified a shared library in a way that affected services outside the job scope. The change might even be correct in isolation. But touching code owned by another team, in a service not mentioned in the ticket, is exactly the kind of unexpected side-effect that destroys trust in an automated tool.
How we define service boundaries in a monorepo
We support three ways to declare service boundaries, and we recommend using them in combination.
Directory-based ownership is the simplest. A CODEOWNERS file or a Pylon-specific .pylon/ownership.yaml declares which directories belong to which team. When a job is scoped to a service, the agent knows from the ownership map which top-level directories it may write to. Writing outside those directories requires explicit scope expansion, either in the job configuration or via a confirmation prompt that pauses the job.
Dependency boundary declarations go a level deeper. Some shared libraries are intended to be consumed read-only: the billing service can call shared/pricing, but it should not modify it. Modifying a shared library to solve a billing bug is a scope violation, even if the billing directory is within the job's write boundary. We support a readonly_deps declaration in the ownership config that marks certain packages as off-limits for writes from jobs scoped to any consuming service.
Graph-derived boundaries are the third layer. Even without explicit configuration, Codepylon's dependency graph knows which services import which shared libraries. When a job is scoped to a service, we compute the boundary as: the service's own packages, plus any packages that the service has exclusive ownership of (not imported by any other service). Packages imported by multiple services are flagged as shared and treated as read-only unless explicitly unlocked.
What happens when the agent hits a boundary
When Pylon's context selection or diff generation identifies that completing a task requires modifying a file outside the job's write boundary, it stops and reports the conflict before opening any PR.
The conflict report contains: which file outside the boundary was identified as needing modification, which service owns it, why the agent determined a change there was necessary, and what the consequence of not modifying it is (will the job be incomplete? will tests fail?). Based on that report, the team has three options.
Option one: expand the job scope explicitly. The developer opens a new job that includes the shared library as an in-scope target, which brings the library's owning team into the review loop for any changes there. The review request goes to the owning team, not just the initiating team. This is the right path when the shared library genuinely needs to change.
Option two: refactor to avoid the shared library modification. Sometimes the agent's initial approach was unnecessarily reaching into shared code. With a different approach, the same fix can be accomplished within the service's own boundaries. The agent, upon receiving the boundary conflict, attempts an alternative approach that stays within scope before reporting it as a hard stop.
Option three: accept a partial job. If the agent can complete 80% of the task within the boundary and the remaining 20% requires touching out-of-scope code, the PR contains the in-scope changes with a clear description of what still needs to be done and in which service. The reviewer can merge the partial PR and decide separately how to handle the out-of-scope portion.
Shared library pinning
A related problem in monorepos: shared library version pinning. When one service pins a shared library to a specific version for stability reasons and another service wants to update that library, the agent needs to know about the pin before suggesting any update to the library.
We track version pin annotations in the ownership config and in the dependency graph metadata. When a job would modify a shared library, we check for consuming services that have explicitly pinned to a version and note them in the PR body. The reviewer needs to know that merging this change will affect pinned consumers, even if those consumers are not in the PR diff.
This is especially relevant for Pylon-Patch jobs that are remediating a CVE in a shared library. A security patch might be urgent, but forcing a version bump on a pinned consumer without the owning team's awareness is not the right way to handle it. The PR surfaces the pin conflict and suggests that the owning team of the pinned service be added as reviewers.
Monorepo-specific CI configuration
In a monorepo, running the entire test suite for every change is often impractical. Most teams use affected-service detection to run only the tests for services touched by a given commit. Pylon respects your CI's affected-service configuration: when a job diff touches files only in the billing service, we run the billing service tests, not the full suite.
The exception is when the diff touches a shared library. Changes to shared libraries trigger test runs for all consuming services, because the impact is cross-service. This is expensive, and it is also correct. A shared library change that breaks one of its consumers is a regression that needs to be caught before merge, even if the broken consumer's tests were not in the original job scope.
We have seen cases where teams were tempted to short-circuit this by excluding certain tests from agent-triggered CI runs. We understand the motivation: agent jobs produce a lot of small PRs, and running full cross-service tests on each one is time-consuming. Our recommendation is to invest in optimizing your affected-service test infrastructure rather than weakening the test coverage for agent-generated changes. A partial test suite gives false confidence, and the failure mode when that confidence is wrong tends to be a production incident in a service that "wasn't part of the change."
When scoping is not the problem
One thing we want to be clear about: monorepo scoping protects against unintended cross-service changes. It does not protect against incorrect changes within the intended scope. A well-scoped job can still produce a diff that has logic errors or breaks existing tests. The scoping system is about reducing the blast radius when something goes wrong, not about guaranteeing correctness.
The correctness guarantee comes from the test suite. Scoping and tests work together. Scoping keeps the diff contained to a reviewable set of files. Tests verify that the contained diff does what it claims. Both need to be in good shape for agent jobs in a monorepo to be trustworthy.