Agents · Access management
We stopped making engineers wait for access
Role management via chat: an agent I built that makes non-production access self-serve, audited, and locked out of production.
- AI agents
- Slack
- Access management
- Least privilege
- In use
The problem
People across the firm need roles all the time, to reproduce a bug or demo a feature, and they can't grant one to themselves. Only the platform team can. So they raised a request with the platform team's on-call, or with someone they knew on that team, and waited, often for a role that turned out to be the wrong one, or for the first of several personas they needed.
Both sides lost: the teams asking lost time waiting, and the on-call spent theirs on repetitive, low-risk requests instead of focusing on their core responsibilities.
For non-production environments, none of that queueing should be necessary. Nothing there touches a customer; you just want to get your work done. That is why I built a skill for our internal AI assistant that grants non-production roles from a plain-language request in Slack, with no queue.
Roles and permissions, from zero
- Tenant. One customer's own space on a shared platform, with its own data, users and settings.
- Permission. A single action, such as viewing a report or inviting a user.
- Role. A named bundle of permissions, such as "admin" or "view-only".
- Granting. Giving a user a role in a specific product and tenant.
| Permission (made-up example) | View-only | Marketing user | Admin |
|---|---|---|---|
| View reports | Yes | Yes | Yes |
| Create and edit campaigns | No | Yes | Yes |
| Invite users and assign roles | No | No | Yes |
What already existed
I didn't start from scratch. Three things were already in place:
- Orca. Our internal AI assistant, built and maintained by another team. It already lived in Slack, and it spins up an AI coding agent to do the work and manages that agent's lifecycle.
- Skills. Orca's way of learning new jobs. A team registers a skill with a description of the requests it should handle, and the agent picks it up when a request matches.
- Our app and identity provider. The systems where users and their roles actually live, which only the platform team's tooling could change.
What was missing was a way for anyone to get a role without going through the platform team. That is the part I built: a skill for my team's use case, added to Orca, and the plumbing behind it.
The idea: just ask
The agent handles these requests in plain language in Slack. There is no form, no ticket and no new tool to learn, and you can ask for yourself or for a teammate. These are the kinds of requests people made during the trial:
- "Give a teammate admin access to one of our apps for a tenant."
- "Make a user a marketing user for workflows."
- "Give a user view-only access."
- "For this environment, what are my roles for this tenant?"
What it can do
| Capability | What it does |
|---|---|
| Roles | Sets, changes or removes a user's role in a product, and maps loose wording like "admin" or "view only" to the tenant's real role. |
| Invites | Invites a new user with a role, or re-sends an expired invite, once you confirm. |
| Enabling users | Reactivates a disabled user without changing their role. |
| Staff access | Grants internal staff access, or time-boxed edit access within a tenant. |
| Look-ups | Shows which roles someone holds, which roles a tenant offers, and licence totals and usage. |
| Bulk requests | Handles "view-only for all apps" by picking the lowest-privilege role in each app the tenant has, then lists exactly what it assigned. |
| Self-description | Explains what it can do when you aren't sure what to ask. |
How a request flows
A clear request just runs. The agent asks one short question only when something is missing or ambiguous, and it never guesses a role or an email address. If you don't name an environment, it uses the safer non-production one and tells you so.
Designing for safety first
Letting an AI agent change access sounds risky, so the guardrails were the main design work:
| Guardrail | What it means |
|---|---|
| Non-production only | Declines production requests, and the services behind it reject production calls by design, so it can't reach production even by mistake. |
| No guessing | Never infers an email address from a name or picks between ambiguous roles; it asks instead. |
| Allow-listed domains | Invites or changes only users on approved email domains. |
| No lock-outs | Blocks any removal that would leave a user with no role. |
| Least privilege | Declines the highest-privilege role and offers the next level down, and it hands removal of staff access to IT or the platform team. |
| Honest reporting | Reports an invite as "invited, must accept", never as "access granted", and re-reads the user's state after every change to report what they hold now. |
| No blind retries | Never retries a write automatically, and it serialises concurrent changes to the same tenant. |
| Audit trail | Logs every change with the requester's identity. |
| Protected attributes | Cannot set sensitive flags through the role and invite paths. |
How it's built
What the skill is made of
| Part | What it does |
|---|---|
| Trigger | Matches any request for a role change or access, so the agent picks the skill up from plain language. |
| SKILL.md | Lists every capability the skill exposes, as commands the coding agent can run. |
| Access.md | Writes down the nuances of every use case, so the agent never has to guess them. |
| Deterministic code | Holds everything deterministic as ordinary code, exposed to the agent through clients, helpers and the like, rather than leaving it to the model. |
How it stays safe
- Production is blocked in the services. Every API exposed for the skill is guarded by permissions so that it works only with non-production environments, so no wording of a request can get past it.
- New APIs wrap the existing ones. The APIs exposed for the skill are wrappers on top of the existing ones, so every existing check and nuance still runs, such as writing to the third-party auth service.
- Users never touch the APIs. Every call goes through the skill.
- Every request is validated first. The agent checks a request before it makes it.
- Unclear requests come back to you. When something is ambiguous, the agent asks, and that conversation happens in Slack.
- Two systems stay in step. Some changes touch both our app and our identity provider; if the sync fails, the previous value is restored.
Where it is now
Folks have started using it. Requests now rarely reach the platform team, and when one does, the team triggers the agent to handle it with this skill.
The point stays the same: access to non-production environments shouldn't mean waiting. With the agent it is self-serve and audited, and it is locked out of production.