The problem starts simple. You open a file in your editor, start typing, and an AI agent in another terminal decides the same file needs changes. The agent writes, your buffer reloads, your unsaved work disappears. This happens because editors and AI coding tools operate in separate worlds. The editor tracks your keystrokes and buffer state. The AI tool sees only the filesystem.
Sidekick addresses this through a surprisingly minimal intervention: a command-line tool that sits between neovim and AI coding harnesses like Claude Code, Codex, opencode, pi, and Crush. When you launch neovim through sidekick, it opens a Unix socket at /tmp/<blake3(cwd)>-<pid>.sock. When an AI tool attempts a file edit, sidekick’s hook intercepts the operation, discovers all neovim instances opened from the same working directory by globbing the socket namespace, connects over msgpack-rpc, queries each instance for unsaved changes to the target file, and either allows or denies the edit.
The implementation is roughly 2,000 lines of Rust. No daemon, no background service, no persistent state beyond an append-only event log. The socket path uses BLAKE3 to hash the canonical working directory, which means every neovim instance launched from the same project becomes discoverable through filesystem enumeration alone. The RPC timeout is short, around 100 milliseconds, so stale sockets from crashed processes degrade gracefully to allow.
The Hook Surface
Sidekick leverages tool-use hooks exposed by AI coding harnesses. Claude Code provides PreToolUse, PostToolUse, and UserPromptSubmit hooks in its settings.json configuration. The PreToolUse hook fires before Edit, Write, or MultiEdit operations. Sidekick receives JSON on stdin describing the pending operation, queries neovim instances, and returns either success or an error with a human-readable message like “Edit blocked — file has unsaved changes.”
The hook contract for Claude Code looks like this in ~/.claude/settings.json:
{
"hooks": {
"PreToolUse": [
{
"matcher": "MultiEdit|Edit|Write",
"hooks": [{ "type": "command", "command": "sidekick hook" }]
}
],
"PostToolUse": [
{
"matcher": "MultiEdit|Edit|Write",
"hooks": [{ "type": "command", "command": "sidekick hook" }]
}
]
}
}
Codex uses a plugin-bundled hook system. The sidekick plugin lives in ~/plugins/sidekick and gets registered in the Codex marketplace config. Codex requires enabling plugin_hooks = true in ~/.codex/config.toml, after which it pipes hook events through the plugin to the sidekick hook binary.
opencode and pi use TypeScript extension systems. Sidekick ships bridge files that live in ~/.config/opencode/plugin/sidekick.ts and ~/.pi/agent/extensions/sidekick.ts respectively. These bridges intercept edit operations at the tool level and shell out to sidekick hook, translating between the harness’s native event format and the stdin JSON contract sidekick expects.
Crush registers hooks directly in crush.json. It only exposes PreToolUse, which means sidekick can deny edits but cannot trigger post-edit buffer refreshes or inject visual selections into prompts. The README documents this as an upstream limitation, not a configuration gap.
Buffer Refresh and Selection Injection
The denial path is half the feature. The other half runs after an edit succeeds. Sidekick’s PostToolUse hook connects to every neovim instance with the modified file open and issues a buffer reload command over RPC. The reload preserves cursor position and window state, so the typical :e! dance becomes invisible.
The RPC call uses neovim’s msgpack-rpc API. The Rust implementation opens a Unix socket connection, serializes a neovim command like checktime or a Lua expression that force-reloads specific buffers, deserializes the response, and closes the connection. The whole round trip completes in milliseconds.
The third capability is selection injection. When you visually select code in neovim and submit a prompt to Claude Code or Codex, sidekick queries neovim for the active visual selection or recent visual marks, reads the selected text, and returns it in a fenced context block:
[Selected from src/main.rs:45-67]
fn handle_hook(input: &str) -> Result<HookResponse> {
// ...
}
The AI harness receives this as additional context. For opencode and pi, which lack a native selection-injection hook, the bridge appends the context block directly to the user’s prompt text before submission.
What This Reveals About Missing Primitives
Sidekick works because neovim exposes an RPC interface. VS Code has a similar API through its extension host, though it requires a running extension rather than a standalone socket. Most terminal editors, including Helix and Kakoune, provide command-line interfaces for sending commands to running instances, though not all expose buffer state queries.
The pattern sidekick implements is not specific to neovim. Any editor that can answer “does this file have unsaved changes?” over IPC can participate. Any AI coding tool that can call a pre-edit hook can query. The gap is that no standard protocol exists for this interaction. Sidekick builds a point solution for neovim, and the README’s PHILOSOPHY.md sketches a longer roadmap covering Helix, Zed, and VS Code on the editor side, Aider, Goose, and Continue on the AI side.
The minimal contract would be:
- An editor exposes a socket or IPC channel at a discoverable path.
- The editor responds to a query:
{"method": "has_unsaved_changes", "params": {"path": "/abs/path/to/file"}}. - The response is
{"result": true}or{"result": false}. - Optionally, the editor accepts a reload command:
{"method": "reload_buffer", "params": {"path": "/abs/path/to/file"}}.
This is roughly 20 lines of protocol specification. Every editor would need an implementation, and every AI tool would need to call the hook. The benefit is that the human-agent collision problem gets solved once, at the protocol level, rather than through per-tool integrations.
The fact that this protocol does not exist is telling. Editors and AI coding tools evolved in parallel. Editors assumed exclusive control over file buffers. AI tools assumed the filesystem was the source of truth. Concurrent editing between a human and an agent was not a design consideration until recently.
Implementation Details Worth Studying
Sidekick uses BLAKE3 for directory hashing because it is faster than SHA-256 and collision-resistant enough for this use case. The socket naming scheme /tmp/<blake3(cwd)>-<pid>.sock gives you per-directory discoverability and per-process uniqueness. A glob like /tmp/a3f8b2c1*-*.sock finds every neovim instance launched from a given directory, regardless of which subdirectory you opened neovim from. The PID suffix prevents socket name collisions when multiple instances run from the same directory.
The msgpack-rpc implementation does not use neovim’s official client libraries. Sidekick implements the protocol directly in Rust using the rmp and rmpv crates. The wire format is simple: requests are msgpack arrays [type, msgid, method, params], responses are [type, msgid, error, result]. Neovim’s RPC documentation specifies the exact layout, and implementing it directly avoids pulling in heavyweight dependencies.
The timeout strategy is important. Sidekick sets a 100ms timeout on socket connections and RPC calls. If a neovim instance is unresponsive or the socket is stale, the hook does not block. This means sidekick degrades to allow rather than deny by default. A crashed neovim process leaves a socket in /tmp, but the hook will fail to connect, log the failure, and let the AI edit proceed. This is the correct behavior: false negatives (allowing an edit that should have been blocked) are tolerable, false positives (blocking an edit when no human is actively editing) are not.
The event log lives at sidekick/events.jsonl under your OS data directory, which resolves to ~/.local/share/sidekick/events.jsonl on Linux, ~/Library/Application Support/sidekick/events.jsonl on macOS. Events are appended as newline-delimited JSON: {"timestamp": "...", "event": "launch", "pid": 12345, "cwd": "..."}. The sidekick stats command reads this log and prints aggregated metrics: total launches, allows, blocks, refreshes, and top files by edit frequency. Analytics are local, best-effort, and never block the critical path.
Where This Goes Next
The roadmap in PHILOSOPHY.md proposes extending sidekick to other editors and AI tools. Helix has a command-line interface for sending commands to running instances but does not expose a persistent socket. Zed has an extension API and could likely implement the protocol through an extension. VS Code’s extension host could serve the same role, though it requires a running extension rather than a standalone process.
On the AI tool side, Aider runs as a command-line loop and could call a pre-edit hook before writing files. Goose and Continue are similar. The common thread is that these tools all write to the filesystem eventually, and that write is the interception point.
The longer vision is a protocol. Call it the Editor State Protocol, or ESP. Editors that implement ESP expose a Unix socket at $XDG_RUNTIME_DIR/editor-<hash>.sock or equivalent. AI tools that implement ESP call esp query <path> before editing and esp notify <path> after editing. The esp CLI is a thin client that discovers running editors, sends the query, and returns a yes/no answer. Editors register their sockets in a well-known location, and the discovery mechanism is filesystem-based, same as sidekick.
This is speculative, but the pieces exist. Neovim proves the editor side is feasible. Claude Code, Codex, and others prove the hook side is feasible. Sidekick proves the integration works. What remains is standardization.
The intermediate step is porting sidekick’s existing implementation to more editors and tools. The Action trait in src/action.rs abstracts the editor-specific logic. Adding Helix support means implementing a Helix action that shells out to helix --socket <path> --command has-unsaved-changes <file> or equivalent. Adding Aider support means contributing a pre-edit hook to Aider that calls sidekick hook before file writes.
Sidekick is a single developer’s answer to a collision problem that will only grow more common. AI coding tools are not going away. Human developers are not going away. The filesystem is not a sufficient coordination layer. Something has to mediate, and that something is either per-tool hacks or a protocol. Sidekick is the former, pointing toward the latter.