We built offboarding software with zero AI. Here's why.
AccessExit generates offboarding checklists with rules, not a model — not because AI is bad, but because the output is an audit artifact, and three places in the code exist purely to stop the product claiming more than it can prove.
The question we get, in some form, every time we describe what we're building: so where's the AI?
It's a fair question in 2026. An offboarding tool is almost a caricature of a good LLM use case — unstructured inputs, a long tail of tools nobody has documented, a task that is mostly "read this messy context and produce a sensible list." We could ship that. It would demo well.
Our answer is a fifteen-line function that does the opposite of what you'd want from a model. It's called resolveVerification, and all it does is take a task that asked to be verified automatically and quietly downgrade it to "a human will have to check this."
That function is the whole argument, so let us explain how it got there.
What generating a checklist actually is
When you start a case in AccessExit, the checklist is produced by a pure function. Same inputs, same output, every time — a person's apps, their exit date, and your SLA policy in; an ordered list of tasks out. There's no randomness in it, and the ordering is deliberately stable: high-criticality apps first, then alphabetical, so two runs never disagree about what came where.
The knowledge that makes the list useful doesn't live in a model. It lives in a hand-written catalog of 22 tools, where each entry encodes the actual steps for that tool — suspend the Google account before deleting it, rotate the deploy keys someone created after removing them from the GitHub org, remember that Slack webhooks keep firing after you deactivate the person who installed them.
That catalog is code. It's versioned, it's diffable, and it's covered by tests. When someone eventually asks "why did the system tell us to do this?", the answer is a line in a file with a commit history, not a sampled distribution.
Where an LLM would genuinely help
We want to be honest about this rather than build a strawman, because there are real gaps a model would fill nicely.
The obvious one is matching messy inputs. When a workspace imports its app list, the names come in however someone typed them — "GH", "github.com", "Github (org)". Mapping those to catalog entries is exactly the fuzzy problem language models are good at, and our current answer is dumber than a model would be.
The second is the long tail beyond the 22. If you add a tool the catalog doesn't know, you get generic steps for its category with the app name pasted on the front. It's serviceable, and it's clearly worse than what a decent model would write for a tool it knows about.
So the honest version of our position isn't "AI wouldn't help here." It's that both of those helpful things happen upstream of the part that matters, and the part that matters can't tolerate them.
Three places the code refuses to say what you'd like it to
The product's output isn't the checklist. It's the receipt at the end — the artifact you hand to an auditor, an insurer, or a prospect's security team. Which means every sentence in it is something you may have to defend to someone who is not on your side. Once you accept that framing, the interesting parts of the codebase are all refusals.
The first is resolveVerification. A catalog entry can request API verification, but that request is checked against reality: unless the app is Google Workspace and the Google integration is actually connected, the task is rewritten to manual. The system will not describe a check as automated when no automation exists. Of the 22 tools, one qualifies.
The second is the receipt's assertion logic. There are exactly three things a completed case is allowed to say about itself, and the strictest one — everything was verified — requires that no task was left in a resolved-but-unchecked state. This trips people up in a way we like: marking a task "revoked" is not enough. If you say you removed something but nobody independently confirmed it, the receipt downgrades to "completed with unverified items" and names them. The only way to keep a clean assertion with a loose end is for a named human to explicitly accept that risk, on the record.
The third is a single word. Even the strongest assertion — every task verified, nothing outstanding — says "all known access for this person has been removed or transferred."
None of those three are hard engineering. They're each a handful of lines. They're just decisions that had to be made in the direction of claiming less, at moments where claiming more would have made the product look better.
The bar AI has to clear to earn a place here
We're not religious about this, and "no AI in v1" is a statement about v1. But the bar is specific: a model can help produce inputs a human then confirms. It cannot sit anywhere in the path between evidence and a claim.
If an LLM suggests that your "GH" row probably means GitHub, and a person says yes, nothing has been weakened — the receipt still rests on what a human confirmed. If an LLM decides that a task looks sufficiently handled and nudges the assertion, the entire artifact becomes worthless, because its value was never the summary. It was that the summary is boring, reproducible, and traceable to a specific piece of evidence and a specific person's name.
“The failure mode we're avoiding isn't a model hallucinating wildly. It's a model being reasonable.”
A plausible, confident sentence about access being removed that nobody can trace back to a check anyone performed — that's the one thing this product cannot ship, and no improvement in model quality fixes it, because it isn't an accuracy problem. It's a provenance problem. (We made the same call on BurnCap for a different reason: there, a hallucinated dollar figure would destroy the only thing a cost tool sells. Same refusal, different stakes.)
The generalizable version
We don't think determinism is a virtue in general. Most software is better with a model in it now, and we use them all day to build this one.
For an offboarding receipt, that line lands early. Our whole product is one screen that says a small number of dull, checkable sentences — and a lot of code making sure it never says a more impressive one. That's not a gap in the roadmap where the AI should go. It's the feature.