Folks, today I’m excited to introduce my new project!

First, I should say that I primarily write in Kotlin. In Kotlin, we have a problem with viewing and exploring the source code of third-party libraries. I’ve used TypeScript, Go, and Kotlin, and I can say that I envy those who code in TypeScript, because agents, when working with it, can simply dive into node_modules, ripgrep that directory and find the needed code right away, literally instantly, in the downloaded caches.

Compared to this, Kotlin, especially multiplatform, is torture. Agents previously couldn’t view source code at all, they just hallucinated code. Now they’ve gotten smarter and try to solve problems themselves when they don’t know the API of some library or need to find the right function overload, through filesystem search. But even with all permissions, caches, and assuming all dependencies are already downloaded, this is very difficult for them. Finding a single dependency can take up to 10-15k context tokens, so…

Introducing ksrc!

This is a CLI utility that allows agents to view the source code of any Kotlin libraries in a single line

With ksrc, your agent will check source code like this:

$ ksrc search "pro.respawn.apiresult:core*" -q "recover"
pro.respawn.apiresult:core:2.1.0!/commonMain/pro/respawn/apiresult/ApiResult.kt:506:42:public inline infix fun <T> ApiResult<T>.recover(
...

$ ksrc cat pro.respawn.apiresult:core:2.1.0!/commonMain/pro/respawn/apiresult/ApiResult.kt --lines 480,515
...
@JvmName("recoverTyped")
public inline infix fun <reified T : Exception, R> ApiResult<R>.recover(
    another: (e: T) -> ApiResult<R>
)
...

2 commands -> source found, with filtering by version and dependency, and automatic downloading and unpacking.

What did it look like without ksrc?

Without ksrc, in practice the search looked like this for my agents:

$ rg --files -g "ApiResult.kt" /Users/nek/.gradle/caches

$ rg "ApiResult\\.recover|recover\\(" /Users/nek/Developer/Respawn/Backend

$ rg --files -g "*apiresult*" /Users/nek/.gradle/caches

$ ls /Users/nek/.gradle/caches
9.2.1		CACHEDIR.TAG	journal-1
build-cache-1	jars-9		modules-2

$ rg --files -g "*apiresult*" /Users/nek/.gradle/caches/modules-2/files-2.1

$ rg --files -g "*apiresult*" /Users/nek/.gradle/caches/jars-9

$ fd -i apiresult /Users/nek/.gradle/caches/modules-2
/Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult/
/Users/nek/.gradle/caches/modules-2/metadata-2.107/descriptors/pro.respawn.apiresult/
$ ls /Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult
core			core-iosarm64		core-jvm
core-android		core-iossimulatorarm64	core-wasm-js
$ ls /Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult/core-jvm
2.1.0
$ ls /Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult/core-jvm/2.1.0
193901bf1e2ecee192d92363d99b2e056467be28
938d7fb2b3cbd2806baac501f75182b9734ee5e1
ac2afbf602985d4257dcae7a6b90713585291627
b8101c9a149083295b708f4010e7c501840c5d8d
$ ls /Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult/core-jvm/2.1.0/193901bf1e2ecee192d92363d99b2e056467be28
core-jvm-2.1.0-sources.jar
$ jar tf /Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult/core-jvm/2.1.0/193901bf1e2ecee192d92363d99b2e056467be28/core-jvm-2.1.0-sources.jar | rg "ApiResult"
commonMain/pro/respawn/apiresult/ApiResult.kt
$ unzip -p /Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult/core-jvm/2.1.0/193901bf1e2ecee192d92363d99b2e056467be28/core-jvm-2.1.0-sources.jar commonMain/pro/respawn/apiresult/ApiResult.kt | rg -n "recover"
...
$ unzip -p /Users/nek/.gradle/caches/modules-2/files-2.1/pro.respawn.apiresult/core-jvm/2.1.0/193901bf1e2ecee192d92363d99b2e056467be28/core-jvm-2.1.0-sources.jar commonMain/pro/respawn/apiresult/ApiResult.kt | nl -ba | sed -n '490,510p'
...
public inline infix fun <reified T : Exception, R> ApiResult<R>.recover(
   another: (e: T) -> ApiResult<R>
)
...

15 (!) steps, tons of thinking tokens, tons of garbage in context, and random unarchived junk files in your system - just to see a single method!

All because of Gradle’s “brilliant” cache organization system: agents need to dig through hashed folders that Gradle creates, thousands of directories in modules-2.1 and so on. The process looks like this:

And if there are no sources, then you generally need to use something like javap to decompile the sources, just to see what a single function looks like in some library from Google.

My utility packs all the steps described above into two commands: ksrc search and ksrc cat - and outputs a beautifully formatted result that an agent can combine with other commands and enhance with scripts.

Integration with AI Agents

I’ve also prepared a Claude plugin with a skill for your agents, so they can immediately use it when needed, on their own, without your participation or prompting, and also a skill for Codex.

Codex wrote this utility itself for itself and completely independently in Go - a language in which I understand absolutely nothing, have never written or read a single line in my life. And it packaged it into a single file that you just need to download using the script on GitHub, and configured the integration with agents for you.

In the near future, I’ll work on publishing through Homebrew and some option for Linux. I’d be happy to hear your feedback on social media. For those who develop in Kotlin, I hope this will be as useful as it is for me.