SDKs... In an AI World
IMHO, for software development, AI is here to stay.
Some developers are seriously opposed to this, and that is certainly their prerogative. I expect that there will be plenty of developers who will be using agentic development techniques or other approaches to leverage LLMs in software development. Some of those developers might be reticent, only using such tools because an employer or a team expects it. Others will embrace it more strongly.
If you publish a library or an SDK, and you are not opposed to LLMs, you might want to consider catering both to human developers and to coding agents assisting those developers. Helping the agents often helps the developers, even those who avoid using coding agents themselves. In other words, consider what you can add to your offering that serve whoever is writing the code that uses it: human, deterministic code generator, or LLM.
Reference Material
For anything that is open source, make it easier to understand that source code.
Code comments are huge, both for documenting public APIs and for explaining the rationale behind non-obvious code. Having generated documentation from the API comments (e.g., JavaDocs, Dokka) can be helpful, even though agents might be reviewing the source code itself. If you are having agents generate the code, frontier models are fairly good at distilling their context down into comments, so long as your prompts and rules steer them to actually write such comments.
Robust test suites help demonstrate expectations to the agent, even without the agent running those tests. Being able to easily run tests can be useful for agents tasked with making contributions to your SDK, of course. But tests can provide functional illustrations of edge and corner cases that would be extremely tedious to explain in documentation. If you are having agents build tests, frontier models are pretty good about writing them, especially if you use coverage analysis (e.g., Jacoco, Kover) to steer them to write them.
If you are looking for other parties to create ports of your library, having clear and complete specifications will be critical, as the specification should be the definition of what is and what is not a faithful port. Your own implementation(s) of the specification are good references, but a language-neutral specification can disambiguate what is required for the port and what merely is convention in an implementation. Bonus points for having a conformance suite (e.g., test fixtures in JSON with expected results) that a port can use to determine if it indeed is implementing the specification correctly.
And, of course, overall project documentation is huge… so huge that I plan on dedicating another post to the subject.
Guardrails
I use the term “guardrails” for things that help prevent agents from making mistakes, or help agents identify mistakes if they get made anyway.
The best-case scenario is that agents’ training data includes your API… from back when the agent was trained. This is not dissimilar to how human developers rely on blog posts, Stack Overflow answers, and the like that may pre-date significant API changes. Make sure that everyone knows about your changes, including having reliable use of semantic versioning so everyone can more readily identify what is old and what is new. For Java/Kotlin APIs, leverage @Deprecated, ideally explaining replacement structures, so at build time consumers get informed directly about when they are using stuff that is out of date. And for Kotlin libraries and SDKs, use binary-compatibility-validator not only to identify where the API has changed, but to provide a high-density way for agents to learn about the API surface.
Static analysis rules (e.g., Lint, Detekt) are a way for you to programmatically point out “footguns” in ways that are easy for developers and agents to interpret. Better yet, once a project adopts your custom rules, hopefully they will be applied automatically on future project builds or invocations, so they provide defensive value over time. Agents can help you build such rules, if you are unfamiliar with how to create and publish them.
Some projects can even benefit from custom marker annotations, akin to the @IntRes and @RequiresPermission ones that Android developers know and love (or perhaps love/hate, depending on the day). Combine this with Gradle tasks or CLIs that can determine correctness based on how those annotated items are used, and now developers and agents can learn about issues in ways that static analysis rules alone might not catch.
For cases where your library or SDK detects issues at runtime, having robust errors will make it easier for developers and agents to pinpoint what is going wrong. If your library or SDK has multiple implementations across languages — either your own or third-party ports — aim for distinct error codes that can be consistent across those languages. This allows the knowledge of what the error conditions are and how to avoid them to itself be cross-platform. Relying instead on things like exception types make it more difficult to express the error conditions in ways that will make sense on platforms that might use different constructs to represent the error. And, especially if you are not using error codes, consider putting documentation URLs in error messages, to steer everyone exactly where to learn about what went wrong and how to fix it.
For other runtime messages, consider exposing an event listener API rather than dumping stuff to logs. Even if the default event listener just dumps to logs, the event listener will give developers and agents alternatives for surfacing events in ways that might help with diagnostics. See this classic post by Jesse Wilson for more on this concept. In general, though, anything you can do to help promote runtime observability will make it easier for agents to identify when things are not quite working as desired.
Ramps
I use the term “ramps” to refer to ways to make it easier for coding agents (and developers!) to create reliable code that interfaces with your library or SDK.
Consider publishing a library of test doubles for key types in your library or SDK. This often comes in the form of a -testing suffixed library that is a test-centric peer of your main library. Steer whoever creates client code for your library or SDK to write tests and use your test doubles rather than reaching for some mocking framework that might not accurately reflect the underlying assumptions that your code has about those types.
Having a roster of runnable sample apps that demonstrate how to interface with your library or SDK will give developers and agents a working reference of how stuff is supposed to work. Of course, you will need to make sure that these samples are kept up to date; agents can help with that as well. However, consider your licensing, as agents are likely to clone bits of sample code as part of their code-generation work — even if your SDK is proprietary, try to make the sample code have a permissive license (Apache 2.0, MIT, or even public domain/CC0), so it is safe for reuse.
But perhaps the single most powerful thing that you can offer is ways to make experimentation cheap. Developers and agents need ways to cheaply and easily determine if a particular approach is going to work, and the target project for using your library or SDK might not be a great host for such experiments. Whether it is offering a CLI (perhaps with a thin MCP server wrapper) or a way to use your stuff in a sandbox or a hosted playground, give developers and agents a good way of seeing what your code emits as output given certain input. Make sure that it is accessible by agents, not just human developers, even if this means that you wind up offering multiple interfaces to the same thing (e.g., CLI for agents, nicely-formatted Web playground for humans). Also, consider how to balance human needs (e.g., formatting) and agent needs (e.g., stable and easily parsed).
Trust, But Verify
We often rely on preview releases, 0.0.1 versions, and the like to get early feedback from developers on our work. Usability testing of your offering comes in the form of developers using it, then asking questions, filing bugs, and the like.
Similarly, you can determine how well coding agents can consume your library or SDK “simply” by having a coding agent try it. Create a bunch of tasks (new projects and additions to existing ones) and see where the agent succeeds and where it stumbles.
Ideally, agent validation is a part of the release process. For example, suppose you offer a CLI tool (usable by developers and agents) with an MCP wrapper (usable only by agents). If there is code drift, and the MCP wrapper is stale, that issue might only be detected by an agent.
Preview of Coming Attractions
This is the first of a few posts that I have planned to try to capture my high-level thoughts on how we can better support both developers and coding agents in the years to come.
Next time, as hinted at above, I will focus on documentation: what to write, how to format it, how to publish it, etc., to be usable effectively by developers and efficiently by coding agents.

