All posts
Product / Security

Role-based access control for autonomous agents: what we built and why

Abstract RBAC permissions hierarchy visualization with layered access control shapes

When we started talking to engineering leaders about using autonomous agents on their production repositories, the first question was almost never "does the agent write good code?" It was "who authorized that change, and how do I know?"

That question deserves a real answer. An agent that can open pull requests on production code has real authority over what goes into your codebase. Engineering organizations that take access control seriously for their human developers need to apply the same discipline to their agents. A developer who accidentally commits to a protected branch without review gets flagged. An agent that does the same thing and then says "the authorization model was unclear" is not a valid defense.

This is what we built, and the choices we made along the way.

The core model: jobs run as principals

In Codepylon's RBAC model, every agent job runs as a named principal. The principal is not "Codepylon the application" and it is not a generic service account. It is a specific policy entity that has been given a specific set of permissions on a specific set of repositories, as granted by a human admin in your organization.

Each principal has three dimensions of permission: which repositories it can read and write, which agent types it can invoke (Pylon-Migrate but not Pylon-Patch, for example, or all agents), and which branch patterns its PRs are allowed to target. An org might configure a principal called migration-agent that can read and write to a specific set of legacy services, can invoke Pylon-Migrate only, and can only open PRs targeting branches that match the pattern pylon/migrate/*. An engineer who wants to run a migration job assigns the task to that principal. The agent cannot target main directly, cannot run a security scan, and cannot touch any repo outside the configured set.

Principals are created and managed by organization admins, not by developers. Developers can invoke an agent job using a principal they have been granted the right to use, but they cannot grant themselves new permissions or create new principals. This mirrors the way access control works for human developers on most well-run engineering teams: individuals can exercise the permissions they have, but they cannot escalate their own access.

Authorization chain: from ticket to PR

Most Pylon jobs originate from a ticket: a Jira issue, a Linear task, or a GitHub issue. When a developer assigns a ticket to a Pylon agent, that assignment is the authorization event. The agent's job record is stamped with: the initiating human (their Codepylon identity, mapped to their GitHub or GitLab identity), the principal under which the job runs, the ticket reference, and the timestamp. This chain is immutable and visible in the Codepylon job log.

When the agent opens a PR, the PR body includes a provenance block that shows the same information: job ID, initiating human, principal, ticket reference. This makes it possible for any reviewer looking at the PR to understand immediately who authorized this work and under what policy. You do not need to go look up a separate audit log to understand a PR's origin.

We made this provenance visible on the PR itself because security reviews of PRs should not require separate tooling. If an auditor or a senior engineer is reviewing a PR opened by an agent, they should have everything they need to assess authorization in the PR itself.

The branch protection question

One of the design decisions we spent the most time on: should Pylon be able to merge its own PRs?

The short answer is no, not by default, and we strongly recommend keeping it that way. An agent that can both open and merge PRs bypasses the human review step entirely. For specific narrow cases, like automated dependency patches that have passed a full test run, some organizations may want to enable auto-merge on Pylon PRs that meet certain criteria. We support that through a separate configuration gate that requires explicit admin opt-in, and it is limited to Pylon-Patch jobs only.

For all other job types, Pylon opens a PR and requests a human reviewer. The reviewer approves or requests changes. The merge is a human action. We are not arguing that human review is always necessary for correctness. We are saying that for most engineering organizations, the control model requires a human in the merge loop, and building a tool that defaults to bypassing that review creates organizational risk that is separate from technical risk.

Audit logging and what it captures

Every action a Pylon agent takes is logged with enough context to reconstruct what happened and why. The log entries cover: job start (principal, initiating user, ticket, target repo, agent type), each file read during context indexing, each file included in the generated diff, test run results, PR open event with PR URL and branch, review response events (comment received, commit pushed in response), and job close (merged, abandoned, failed).

The file read log is something that came up repeatedly in our conversations with security-conscious teams. They wanted to know not just what the agent changed, but what it looked at. An agent that reads your authentication module while working on a billing task is doing something that a team might want to know about, even if the final diff does not touch auth. We log every file read during context selection and make that log available in the job detail view.

Audit logs are immutable and are available for export to your SIEM in JSON format. We also support webhook delivery of log events for teams that want to integrate agent activity into their existing security monitoring stack.

Where the model is still developing

A few things we want to be honest about.

The current model assumes a single organization. Multi-tenant scenarios, where a single Codepylon installation serves multiple distinct engineering teams with separate compliance requirements, are possible but require more configuration work than we would like. We are working on a better model for that, but it is not there yet.

The principal model maps cleanly to org-level RBAC. It maps less cleanly to team-level RBAC in organizations where different teams own different repos and need fine-grained control over which agents can run on which repos. We handle this today via repo allowlists on each principal, but a cleaner team-scoped model is on the roadmap.

We are also aware that "who authorized the job" is a necessary but not sufficient answer to the access control question. The harder question is "what was the agent allowed to reason about and decide on its own, and where did it need human input?" That is a capability governance question that goes beyond RBAC and into the design of the agent's judgment boundaries. We have some structure for that, particularly around the review response limits described in other posts, but we think the right frameworks for agent capability governance are still early and we expect our model here to evolve.