Quickstart
By the end of this page you'll have started a readable CLI session, then asked the daemon two compiler-backed questions: "what symbol is this?" and "who uses it?" The lifecycle commands render readable summaries by default; raw analysis requests still return JSON-RPC payloads.
The walkthrough uses the headless backend because it works on Linux terminals,
CI runners, and agent loops after the Linux headless tarball is installed. If
IDEA or Android Studio is already open on the project with the plugin
installed, swap --backend=headless for --backend=idea and skip the
start/stop steps. The plugin reuses the IDE's analysis session — no second
daemon to babysit.
Before you begin
You need:
- Kast installed through the Linux headless bundle, or through Homebrew plus the IDEA plugin on macOS (see Install)
- A Kotlin workspace on your machine — Gradle or plain
- The absolute path to that workspace root
About Gradle discovery
With settings.gradle(.kts) or build.gradle(.kts) at the root,
headless discovery uses Gradle's project model. Without those
files, kast falls back to conventional source roots and a
source-file scan. The Gradle path matters most for multi-module
builds.
Step 1: Start the headless backend
Run commands from your project root or any subdirectory below it. Kast
walks up to the nearest Gradle or .kast marker when --workspace-root
is omitted. The first call is the slow one — the daemon discovers your
project and indexes Kotlin files. After that, you're hitting a warm
session.
| Start the daemon | |
|---|---|
sequenceDiagram
participant You
participant CLI as "kast CLI"
participant Daemon as "Analysis daemon"
participant K2 as "K2 engine"
You->>CLI: up
CLI->>Daemon: Start process
Daemon->>K2: Bootstrap session
K2-->>Daemon: Indexing complete
Daemon-->>CLI: READY
CLI-->>You: Rendered status summary
The first start indexes every Kotlin file. Later commands reuse the warm state — the cost you pay here buys you fast lookups for the rest of the session.
The default output is meant to be read. In an interactive terminal, headings and inline code are styled; in logs and captured output, the same summary is rendered as plain text:
Kast up
=======
- Workspace: /workspace
- Started new daemon: yes
Selected runtime
----------------
- Backend: headless
- Runtime state: READY
Use --output json on lifecycle and install commands when a script needs
the original structured payload.
Step 2: Resolve a symbol
Pick a Kotlin file and a byte offset that lands on a symbol name. kast
returns the fully qualified name, kind, signature, and source location
of the declaration at that offset.
How to get an offset
The fast way: grep -bo 'functionName' src/main/kotlin/App.kt
prints the byte offset of every match.
| Resolve a symbol | |
|---|---|
{
"result": {
"fqName": "com.example.App.processOrder",
"kind": "FUNCTION",
"returnType": "OrderResult",
"parameters": [
{ "name": "orderId", "type": "String" }
],
"location": {
"filePath": "/workspace/src/main/kotlin/App.kt",
"startLine": 12, "startColumn": 5
}
}
}
fqName and kind are compiler identity, not text matches. Every later
command can stay anchored to this declaration without ambiguity.
Step 3: Find references
Same file, same offset. Ask for every reference across the workspace.
| Find references | |
|---|---|
{
"result": {
"declaration": {
"fqName": "com.example.App.processOrder",
"kind": "FUNCTION"
},
"references": [
{
"filePath": "/workspace/src/.../CheckoutController.kt",
"startLine": 45,
"preview": "app.processOrder(orderId)"
}
],
"searchScope": {
"exhaustive": true,
"candidateFileCount": 12,
"searchedFileCount": 12
}
}
}
searchScope.exhaustive: true is the part that matters. kast walked
every candidate file. The reference list is complete for this workspace
— not a sample, not a best effort.
Step 4 (optional): stop the daemon
Free the resources when you're done.
What just happened
Four commands. You:
- Started a daemon that indexed your Kotlin codebase into a live K2 session.
- Resolved a cursor position to a real declaration with type info — no string match.
- Got every reference back as JSON-RPC, with proof the search was exhaustive.
- Shut the daemon down cleanly.
The CLI defaults to readable summaries for lifecycle work and keeps JSON
where JSON is the contract: kast rpc and explicit --output json calls.
No regex, no guessing, no "we might have missed some."
Next steps
- Understand symbols —
everything
kastwill tell you about a declaration - Trace usage — references, call hierarchy, type hierarchy
- Kast for agents — these same commands from an LLM