The Option Surface Has Changed
AI reveals action paths that were always technically possible — but practically invisible.
As a hiker, I’ve learned that most trails don’t announce themselves as passable or impassable. What matters is whether you can see the next foothold. A sandstone face with grooves either reads as a ladder or a wall, depending on your experience, confidence, and tools. Psychologist James Gibson called these perceived action possibilities “affordances” — not properties of the terrain itself, but a relationship between the environment and the actor.
AI shifts this relationship in technical work. The systems, data, and constraints haven’t magically disappeared, but AI adds new handholds: intermediate steps, faster feedback loops, and lower-cost experimentation. Work that once looked like a sheer drop — rewriting a service, exploring a new domain, prototyping an idea that “wasn’t worth the effort” — now presents a series of manageable moves.
The Friction of High-Volume Code
This shift in perception eventually hits a hard wall: our legacy tooling. When you use AI agents like Claude Code or Codex, the nature of “the work” changes. Pull requests are no longer a few hundred lines — they can be thousands, sometimes tens of thousands.
This creates a scaling mismatch. We have replaced the “developer bottleneck” (writing the code) with a “validation bottleneck” (reviewing and linting it). If an agent can propose a massive refactor in seconds, but your linter traps you in a slow cycle — run, scan the error list, fix, run again — the “option” to use that agent effectively vanishes. To maintain the new speed of exploration, our safety rails must be as fast and autonomous as the agents building within them.
From Reporting to Remediation
This is why Checkstyle, despite being the industry standard for Java, now shows its age. It was designed for a world where humans wrote code slowly and checked it occasionally. In an AI-native workflow, Checkstyle’s limitations become active blockers:
- Deterministic Stalling: Checkstyle can detect formatting issues but cannot automatically fix problems that are trivially deterministic. This leads to “token waste,” where an AI agent must use expensive context and time to manually fix a bracket placement that a tool should have handled instantly.
- The Latency Tax: It can be slow on large codebases, especially on modern high-core machines. When an agent is waiting on a 25-year-old process to finish, the iterative “handhold” disappears. The agent then repairs the code, runs it again, and fixes any new issues found, repeating until the code passes muster.
With AI — and a bit of spare time — I started building Lintal: a fast, Checkstyle-compatible Java linter built on a fork of Ruff (the Rust-based Python linter).
| Feature | Checkstyle (Legacy Terrain) | Lintal (The New Affordance) |
|---|---|---|
| Performance | Adequate on small codebases; inefficient with high-core counts. | 2-4x faster; leverages Rust’s concurrency. |
| Correction | Report-only; creates “fix-it” tasks. | Auto-fix; resolves issues in the same pass. |
| Agent Synergy | Passive; agent must interpret logs, iterate on fixing issues. | Active; agent uses tool to “self-heal” code. |
| Cost | High “Token Spend” for manual fixes. | Zero-token deterministic formatting. |
Building Lintal
Once the option became visible, the work proved surprisingly structured. Taking on a project of this scale with AI isn’t about letting an agent “be creative” — it’s about making the affordances explicit.
Just like humans, AI agents need a clear goal and a way to measure progress. For Lintal, the first anchor was the Checkstyle test suite — not the source code, which is LGPL-licensed, but the tests themselves, which define the expected behavior. The initial task for the agents was to build machinery to execute and validate against that suite, including interpreting configuration embedded in comments — a non-trivial but well-scoped problem.
Next, the agents needed a way to see Java code the way a runtime tool would. Lintal includes a utility called dump_java_ast, which emits the Tree-sitter AST in a simple textual form.
This gives the agents direct visibility into what tokens and structures are being detected, making it possible to reason about formatting rules deterministically instead of guessing. Finally, the tests provide precise feedback: exact matches, missing findings, and false positives. It’s the equivalent of cairns on a foggy trail — small markers that confirm you’re still on the path.
Lintal also uses three open source projects as a test bed in CI: Aeron, Agrona, and Artio. All three use standard Checkstyle configurations. Running against real codebases exposes behaviors not encoded in the Checkstyle tests — another way to validate correctness without reference to the source code.
The New Activation Energy
Before AI, I wouldn’t have even considered taking on a project like this. Checkstyle has over a hundred tests just for indentation rules alone. The complexity didn’t change. The terrain didn’t change. What changed was the option value: the cost of exploration dropped low enough that the project went from “obviously not worth it” to “why not try?”
AI doesn’t eliminate hard problems. It lowers the activation energy required to engage with them. It reveals routes through terrain that used to look impassable — not because the mountain changed, but because you can finally see the trail.
Update — A Short Postscript
Lintal worked.
It became a genuine drop-in replacement for Checkstyle on the codebases I cared about: faster, auto-fixing, and far easier for an agent to drive than the 25-year-old process it replaced. The affordance was real, and the option paid off.
Then something else happened.
I stopped maintaining it and eventually removed it from GitHub. Not because it failed, but because my own work shifted. Rust replaced almost all of the Java I was writing, and a tool I no longer run myself is not one I can honestly keep standing behind.
In retrospect, that outcome reinforces the point of this article.
I started Lintal because AI lowered the cost of exploration enough that a project that once seemed unreasonable suddenly became worth attempting. The project succeeded. But by the time it did, the landscape had shifted again. The same forces that made building Lintal practical also made it practical to leave Java behind entirely.
I thought I was building a tool I would rely on for years. Instead, I built proof that the activation energy for projects like this had collapsed.
The affordance was real. It just led somewhere I wasn’t expecting.