This document covers everything needed to use KotlinSense effectively. See README.md for a quick overview.
/plugin install kotlinsense
/kotlinsense:install
This downloads kotlin-language-server from GitHub Releases and installs it to ~/.kotlin-language-server/. The binary is symlinked into ~/.local/bin/ so it is available in your PATH.
Requirements:
java -version to check — install from adoptium.net if missing)/kotlinsense:status
Expected output:
KOTLINSENSE STATUS
──────────────────────────────────
Binary: ✓ kotlin-language-server found at /Users/you/.local/bin/kotlin-language-server
Java: ✓ Java 21.0.9 found
LSP: ✓ .lsp.json loaded — watching .kt and .kts files
KotlinSense is ready. Type errors and diagnostics will appear
automatically after each .kt file edit in Claude Code.
If kotlin-language-server is not found after install, add ~/.local/bin to your PATH:
echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.zshrc && source ~/.zshrc
Replace .zshrc with .bashrc if you use bash.
Run in PowerShell:
PowerShell -ExecutionPolicy Bypass -File scripts/install-kotlin-ls.ps1
The installer copies kotlin-language-server to %USERPROFILE%\.kotlin-language-server\bin\ and adds that directory to your user PATH automatically. Restart your terminal after install.
Downloads and installs the kotlin-language-server binary on your machine.
What it does:
kotlin-language-server is already installed — skips if found (use --force to reinstall)server.zip from the official fwcd/kotlin-language-server GitHub Releases~/.kotlin-language-server/~/.local/bin/kotlin-language-serverWhat gets installed:
~/.kotlin-language-server/
├── bin/
│ └── kotlin-language-server # launch script (not a jar — resolves lib/ automatically)
└── lib/
├── server-1.3.13.jar
├── kotlin-compiler-2.1.0.jar
└── ... # all required jars
Example output:
Installing Kotlin Language Server v1.3.13...
Downloading kotlin-language-server...
Extracting...
Installation complete!
Binary: /Users/you/.kotlin-language-server/bin/kotlin-language-server
Symlink: /Users/you/.local/bin/kotlin-language-server
Verify: kotlin-language-server --version
Checks whether KotlinSense is correctly installed and ready.
What it checks:
kotlin-language-server binary exists in PATH~/.local/bin is in PATH (macOS/Linux)Example output — ready:
KOTLINSENSE STATUS
──────────────────────────────────
Binary: ✓ kotlin-language-server found at /Users/you/.local/bin/kotlin-language-server
Java: ✓ Java 21.0.9 found
PATH: ✓ ~/.local/bin is in PATH
KotlinSense is ready.
Example output — needs attention:
KOTLINSENSE STATUS
──────────────────────────────────
Binary: ✗ kotlin-language-server NOT found in PATH
Java: ✓ Java 21.0.9 found
PATH: ✗ ~/.local/bin is NOT in PATH
Run /kotlinsense:install to install the language server binary.
Uses KotlinSense’s code intelligence to navigate and explore your Kotlin project.
Available operations:
Find where a class, function, property, or object is declared.
Where is [ClassName / functionName] defined?
Searches for class Foo, interface Foo, object Foo, fun foo, val foo, var foo across all .kt files.
Find every place a symbol is used in the project.
Where is [symbol] used?
Searches for the symbol name across all .kt files in the project.
Get the inferred type of an expression or the documentation for a symbol.
What is the type of [expression]?
Reads the relevant file and explains the type based on Kotlin’s type inference rules.
List all classes, interfaces, functions, and top-level properties declared in a file.
What are all the functions in [file]?
Reads the file and extracts all declarations.
Find all classes that implement an interface or extend a base class.
What classes implement [InterfaceName]?
Searches for : InterfaceName patterns across the project.
Note: Navigation works best with a full Gradle project open. Run ./gradlew build at least once so generated code (Room DAOs, Hilt components) is available for analysis.
KotlinSense connects Claude Code to kotlin-language-server via the Language Server Protocol (LSP). The connection is configured in .lsp.json at the plugin root and activates automatically when the plugin is enabled.
Claude Code edits a .kt or .kts file
↓
PostToolUse event fires
↓
kotlin-language-server analyzes the change via LSP
↓
Diagnostics (errors, warnings) returned to Claude Code
↓
Claude sees: "error: Unresolved reference 'foo' at MainActivity.kt:42"
↓
Claude fixes the error immediately — same turn, no manual compile step
After every .kt or .kts file edit, Claude sees:
?. or !!overrideThe .lsp.json file at the plugin root:
{
"kotlin": {
"command": "kotlin-language-server",
"args": [],
"extensionToLanguage": {
".kt": "kotlin",
".kts": "kotlin"
},
"initializationOptions": {
"storagePath": "${workspaceFolder}/.kotlin-ls"
},
"restartOnCrash": true,
"maxRestarts": 3,
"startupTimeout": 60000
}
}
restartOnCrash: true ensures the server recovers automatically if it crashes — important for JVM-based servers which can timeout under GC pressure on large projects.
error: unresolved reference: 'FooClass'
Causes: Missing import, typo, or the class is generated (Room, Hilt) and Gradle has not built yet.
Fixes:
import com.example.FooClass./gradlew build if the class is generatedbuild.gradle.ktserror: type mismatch: inferred type is String but Int was expected
Fix: Add explicit conversion:
str.toInt() // String → Int
num.toString() // Int → String
num.toLong() // Int → Long
error: only safe (?.) or non-null asserted (!!.) calls are allowed on a nullable receiver
Fixes (prefer in this order):
nullableObj?.method() // safe call — returns null if null
nullableObj?.property ?: defaultValue // Elvis — provide a fallback
nullableObj?.let { obj -> obj.method() } // let block — only runs if non-null
nullableObj!!.method() // non-null assertion — crashes if null, use sparingly
error: val cannot be reassigned
Fix: Change val to var if the value must change. Prefer val (immutable) by default.
error: 'foo' hides member of supertype and needs 'override' modifier
Fix:
override fun foo() { ... }
override val bar: String = "value"
error: suspend function 'collect' should be called only from a coroutine or another suspend function
Fix:
// In ViewModel
viewModelScope.launch {
repository.flow.collect { value -> ... }
}
// In Fragment/Activity
viewLifecycleOwner.lifecycleScope.launch {
viewModel.uiState.collect { state -> render(state) }
}
warning: GlobalScope usage is strongly discouraged
Fix:
viewModelScope.launch { ... } // in ViewModel
lifecycleScope.launch { ... } // in Fragment/Activity
coroutineScope { ... } // in suspend functions
KotlinSense includes a kotlin-android-patterns skill that provides reference patterns for writing idiomatic, LSP-clean Kotlin code in Android projects.
private val _uiState = MutableStateFlow<UiState>(UiState.Loading)
val uiState: StateFlow<UiState> = _uiState.asStateFlow()
viewLifecycleOwner.lifecycleScope.launch {
viewLifecycleOwner.repeatOnLifecycle(Lifecycle.State.STARTED) {
viewModel.uiState.collect { state -> render(state) }
}
}
sealed class UiState {
object Loading : UiState()
data class Success(val data: List<Item>) : UiState()
data class Error(val message: String) : UiState()
}
@Composable
fun MyScreen(viewModel: MyViewModel = viewModel()) {
val uiState by viewModel.uiState.collectAsStateWithLifecycle()
MyContent(state = uiState, onAction = viewModel::handleAction)
}
@HiltViewModel
class MyViewModel @Inject constructor(
private val repository: MyRepository
) : ViewModel()
For the full pattern reference, see the kotlin-android-patterns skill which is automatically loaded by Claude when working on Kotlin files with this plugin active.
Navigate to your Android project root (the directory containing settings.gradle.kts).
On first open, kotlin-language-server indexes your project. This takes:
| Project size | Indexing time |
|---|---|
| Small (1–2 modules) | 15–30 seconds |
| Medium Android app (3–5 modules) | 30–60 seconds |
| Large multi-module project | 60–120 seconds |
Diagnostics start appearing after indexing completes.
Generated code (Room DAOs, Hilt components, Navigation args, Parcelize) only exists after Gradle has run annotation processors. If you see unresolved reference errors on generated classes:
./gradlew build
Then reopen or re-edit the affected file.
Make any edit to a .kt file — even adding a blank line. The LSP will analyze the change and inject diagnostics into Claude’s context. Claude will then see and fix any errors automatically in the same turn.
KotlinSense/
├── .claude-plugin/
│ ├── plugin.json # Plugin manifest
│ └── marketplace.json # Marketplace manifest
├── .lsp.json # LSP server config — connects Claude Code to kotlin-language-server
├── commands/
│ ├── install.md # /kotlinsense:install
│ ├── status.md # /kotlinsense:status
│ └── navigate.md # /kotlinsense:navigate
├── scripts/
│ ├── install-kotlin-ls.sh # macOS/Linux installer
│ ├── install-kotlin-ls.ps1 # Windows PowerShell installer
│ └── verify-install.sh # Binary + Java environment check
├── skills/
│ ├── kotlinsense-usage/ # How the plugin works, known limitations
│ ├── kotlin-diagnostics/ # Common diagnostics with causes and fixes
│ └── kotlin-android-patterns/ # Idiomatic ViewModel, StateFlow, Compose, Hilt patterns
├── README.md # Quick overview and install guide
├── DOCUMENTATION.md # This file — full reference
├── CHANGELOG.md # Version history
└── LICENSE # MIT
commands/*.md) define the user-facing workflow. They give Claude step-by-step instructions for what to check, run, and report.skills/*/SKILL.md) are reference knowledge loaded automatically by Claude when working on Kotlin files. They contain diagnostic rules, fix patterns, and Android-specific guidance — without requiring the user to invoke them manually..lsp.json is the core of the plugin — it tells Claude Code how to start kotlin-language-server and which file extensions to watch. Everything else is guidance layered on top of the live LSP connection./kotlinsense:status — check binary and Java are found/kotlinsense:install~/.local/bin to PATH and restart terminalexport PATH="$HOME/.local/bin:$PATH"
which kotlin-language-server
If still not found, run /kotlinsense:install. If already installed, check the symlink:
ls -la ~/.local/bin/kotlin-language-server
ls -la ~/.kotlin-language-server/bin/kotlin-language-server
Normal on first project open — the server indexes all source files. Wait for indexing to complete before expecting diagnostics. Large multi-module Android projects take longer.
Room DAOs, Hilt components, Navigation args, and Parcelize implementations are generated by annotation processors at build time. They don’t exist as source files, so the language server can’t find them until Gradle has run.
Fix:
./gradlew build
Then edit the affected .kt file to trigger a fresh LSP analysis.
.lsp.json has restartOnCrash: true and maxRestarts: 3 — the server will restart automatically up to 3 times. If crashes persist:
java -version (17+ required)kotlin-language-server uses 512 MB–1 GB for large projects/kotlinsense:install --forceKMP projects are partially supported. The language server indexes the commonMain, androidMain, and jvmMain source sets. iosMain and native targets have limited support. Expect some false positives in shared code that uses platform-specific expect/actual declarations.