Refactor safely
kast never writes code behind your back. Every mutation follows
plan → hash → apply: you ask for a change, kast returns an
edit plan plus content hashes of the files it read, you eyeball the
plan, then send it back for application. If any file changed on
disk in between, the hashes won't match and the daemon refuses to
write. Conflict-aware, fully auditable, no surprises.
The plan → hash → apply flow
The sequence below is the full round-trip for a guarded rename. The
same flow applies to any mutation that returns fileHashes.
sequenceDiagram
title Guarded Mutation Round Trip
participant U as "You / Agent"
participant CLI as "kast CLI"
participant D as "Daemon"
U ->> CLI: raw/rename (file, offset, newName)
CLI ->> D: raw/rename
D -->> CLI: edit plan + fileHashes
CLI -->> U: Review edits
Note over U: Verify edits and hashes
U ->> CLI: raw/apply-edits (plan + hashes)
CLI ->> D: raw/apply-edits
D -->> D: Verify hashes match disk
D -->> CLI: Applied result
CLI -->> U: Success
U ->> CLI: raw/resolve (verify new name)
CLI ->> D: raw/resolve
D -->> CLI: Updated symbol identity
Rename a symbol
raw/rename computes every text edit needed to rename a symbol across
the workspace — without writing anything. The response carries
fileHashes you can pipe straight into apply-edits.
The response contains the full edit plan:
{
"edits": [
{
"filePath": "/workspace/src/Sample.kt",
"startOffset": 20,
"endOffset": 25,
"newText": "welcome"
},
{
"filePath": "/workspace/src/Sample.kt",
"startOffset": 48,
"endOffset": 53,
"newText": "welcome"
}
],
"fileHashes": [
{
"filePath": "/workspace/src/Sample.kt",
"hash": "fd31168346a51e49dbb21eca8e5d7cc897afe7116bb3ef21754f782ddb261f72"
}
],
"affectedFiles": ["/workspace/src/Sample.kt"]
}
fileHashes captures the content hash of every affected file at
plan time. Hold onto these — you'll send them back when you apply.
Tip
Rename defaults to dryRun: true. Set dryRun: false in the
JSON-RPC request to compute and apply in one call. The CLI
always uses dry-run so you can review before writing.
Apply edits
Once you've reviewed the plan, send it back with the same
fileHashes. The daemon re-reads each file, recomputes the hash,
and rejects the request if anything drifted.
Save a raw/apply-edits request containing the reviewed edits
and fileHashes into rename-plan.json.
{
"method": "raw/apply-edits",
"id": 2,
"jsonrpc": "2.0",
"params": {
"edits": [
{
"filePath": "/workspace/src/Sample.kt",
"startOffset": 20,
"endOffset": 25,
"newText": "welcome"
},
{
"filePath": "/workspace/src/Sample.kt",
"startOffset": 48,
"endOffset": 53,
"newText": "welcome"
}
],
"fileHashes": [
{
"filePath": "/workspace/src/Sample.kt",
"hash": "fd31168346a51e49dbb21eca8e5d7cc897afe7116bb3ef21754f782ddb261f72"
}
]
}
}
When the hashes match, the daemon writes the edits and responds:
{
"applied": [
{
"filePath": "/workspace/src/Sample.kt",
"startOffset": 20,
"endOffset": 25,
"newText": "welcome"
},
{
"filePath": "/workspace/src/Sample.kt",
"startOffset": 48,
"endOffset": 53,
"newText": "welcome"
}
],
"affectedFiles": ["/workspace/src/Sample.kt"]
}
If a file changed between plan and apply, the daemon returns an error instead of writing partial edits. Re-run the rename to get a fresh plan with current hashes.
Verify the result
Conflict detection guarantees the edits kast wrote match the
edits kast planned. It does not guarantee the result still
compiles. After any non-trivial refactor, run diagnostics on the
affected files — or re-resolve the renamed symbol to confirm
identity survived.
kast rpc '{"jsonrpc":"2.0","id":1,"method":"raw/diagnostics","params":{"filePaths":["/absolute/path/to/src/Sample.kt"]}}'
kast rpc '{"jsonrpc":"2.0","id":1,"method":"raw/resolve","params":{"position":{"filePath":"/absolute/path/to/src/Sample.kt","offset":20}}}'
If diagnostics surface an unexpected error — or resolve returns a
different symbol — read the stale-results troubleshooting
entry before trying another rename. The
daemon may need a raw/workspace-refresh via kast rpc to pick up edits made outside
its observation window.
Optimize imports
raw/optimize-imports removes unused imports and sorts the rest for
the files you name. Same plan-and-apply shape as rename: you get an
edit plan with fileHashes, you review, you apply.
Same shape as rename — edits, fileHashes, affectedFiles.
Send to apply-edits when ready.
Next steps
- Validate code — run diagnostics after your refactor to confirm the workspace compiles cleanly
- Conflict-rejected apply — what to do when the daemon refuses to write because hashes drifted