Unity development toolkit — for Neovim.
Completes the methods Unity invokes through reflection (Awake, Start,
Update, OnCollisionEnter, …) with the correct signature and body. C# LSPs
do not know about these "magic" methods; unitykit fills that gap.
It covers the MonoBehaviour, ScriptableObject and UnityEditor.Editor message
sets, runs as an nvim-cmp source, and reports its own status through
:checkhealth unitykit.
- What it does
- Requirements
- Installation
- Usage
- Configuration
- Health check
- Troubleshooting
- Limitations
- Uninstalling
- Documentation
- License
-
Suggests Unity messages while you type inside a class body: MonoBehaviour (36 messages), ScriptableObject (6) and Editor (13).
-
Inserts the selected message together with its signature and body:
void Start() { █ }
-
The body can also be a single line:
void Start() { █ }. -
Hides messages that are already written (can be disabled).
-
Resolves the class type from the C# LSP first; without an LSP it scans the class declaration, so indirect inheritance such as
class Player : BaseEnemyalso works. -
Writes no files and leaves no trace in your project or Neovim config.
| Requirement | Note |
|---|---|
| Neovim ≥ 0.10 | Uses the vim.lsp.get_clients and vim.health APIs. |
| nvim-cmp | The only required dependency. |
| Unity project | Assets/ and ProjectSettings/ProjectVersion.txt must exist at the root. |
| C# LSP (optional) | Roslyn is recommended. Without one, the plugin only works in classes that declare : MonoBehaviour, : ScriptableObject or : Editor directly. |
The steps below are meant for someone installing the plugin for the first time. Each step builds on the previous one.
nvim --version | head -1 # must be v0.10 or later
git --versionIf nvim-cmp is not installed yet, add it first (lazy.nvim example):
-- lua/plugins/cmp.lua
return {
"hrsh7th/nvim-cmp",
dependencies = { "hrsh7th/cmp-nvim-lsp", "hrsh7th/cmp-buffer" },
config = function()
require("cmp").setup()
end,
}Create lua/plugins/unitykit.lua:
return {
"AliFuatAkyemis/unitykit.nvim",
dependencies = { "hrsh7th/nvim-cmp" },
config = function()
require("unitykit").setup()
end,
}Restart Neovim; lazy.nvim downloads the plugin. unitykit.nvim should appear in
the :Lazy window.
If you use a plugin manager other than lazy.nvim, adapt the same
dependencies+require("unitykit").setup()pair to your spec format.
require("unitykit").setup() registers the source with cmp, but priority is
set on the cmp side:
require("cmp").setup({
sources = {
{ name = "unitykit", priority = 1000 },
{ name = "nvim_lsp" },
{ name = "buffer" },
},
})cmp does not read a priority field from the source table; priority is only
configured in the sources list. unitykit.setup() registers the source once
per process; repeated calls only update the configuration.
unitykit is a Neovim plugin; it is not installed into the Unity project as a package. The Editor side only needs project file generation and, optionally, Unity opening files in Neovim.
-
Generate project files. In Unity open
Edit ▸ Preferences ▸ External Toolsand under Generate .csproj files for tick at least Registry packages and Local packages. Then press Regenerate project files..slnand.csprojfiles appear at the project root; the C# LSP reads them (the LSP is optional — unitykit works without it). -
IDE package (recommended). Install the
Visual Studio EditororJetBrains Rider Editorpackage fromWindow ▸ Package Manager ▸ Unity Registry. These packages provide the Regenerate project files button and external editor integration. -
Make Neovim the external editor (optional). Unity cannot launch Neovim directly; a small wrapper script is required:
# ~/bin/unity-nvim (chmod +x ~/bin/unity-nvim) #!/usr/bin/env bash exec alacritty -e nvim "+call cursor($2, $3)" "$1"
Select this script via
External Tools ▸ External Script Editor ▸ Browse. Unity passes the file name, line and column as arguments; replace the terminal emulator in the script with the one you use.
Nothing is installed from Neovim into Unity; no changes are made under
Assets/,Packages/orProjectSettings/. Step 1 is only needed for the C# LSP, not for unitykit itself.
Open a C# file (inside a Unity project) and run:
:checkhealth unitykitA healthy setup shows:
- OK Neovim 0.10+ ...
- OK nvim-cmp is installed
- OK Source: unitykit is registered
- OK Unity project root: /path/to/project
- OK C# LSP: roslyn (when an LSP is available)
Finally, type Sta inside a class body and open the completion list; the
Start() suggestion should arrive with its body.
- Open a
.csfile inside a Unity project. - Type a few letters of a message name inside a class body.
- Pick it from the nvim-cmp list; the signature and body are inserted as a snippet.
Completions are only offered when:
- the buffer
filetypeiscs(configurable), - the buffer is a regular file (
buftypeempty andmodifiable), - the file is under a Unity root,
- the cursor is inside the body of a recognized Unity class.
If the class type cannot be determined (for example indirect inheritance without
: MonoBehaviour and without an LSP), no suggestions appear — this is a
deliberate limitation: it stays silent rather than offering wrong suggestions.
All keys are optional.
require("unitykit").setup({
filetypes = { "cs" },
body = "block", -- "block" | "line"
access = "none", -- "none" | "private" | "public" | "protected"
hide_implemented = true,
priority = true, -- sortText prefix; not the cmp source priority
timeout_ms = 1500,
})| Key | Default | Description |
|---|---|---|
filetypes |
{ "cs" } |
Filetypes for which suggestions are offered. |
body |
"block" |
"block" for a multi-line body, "line" for a single line. |
access |
"none" |
Access modifier added to messages that do not declare their own. |
hide_implemented |
true |
Removes message names already present in the class from the list (case-sensitive). |
priority |
true |
Gives items sortText = "0" .. name, so Unity messages sort above LSP items. |
timeout_ms |
1500 |
How long to wait for an LSP response. Completion is not blocked; the regex result returns immediately and a valid LSP response overwrites it afterwards. |
setup returns the merged config table. Invalid body / access values warn
and fall back to the default. Source registration succeeds once; if nvim-cmp is
not loaded at that moment, the next setup() call retries the registration.
require("unitykit").is_registered() reports the registration state.
Details: :help unitykit-config.
:checkhealth unitykitReports the Neovim version, nvim-cmp, the registered source, the Unity root of
the active buffer and the C# LSP clients. The context source (lsp / fallback),
class name and type are shown only when present in the cache; :checkhealth
does not resolve context and sends no LSP requests.
| Symptom | Likely cause / fix |
|---|---|
| No suggestions at all | :checkhealth unitykit — is the source registered, is the file under a Unity root? |
Source: unitykit is not registered |
setup() ran before nvim-cmp was loaded. Call setup() inside config = function() and restart Neovim. |
| Suggestions appear at the bottom of the list | Add priority = 1000 to the cmp sources list; setup({ priority = true }) only affects sortText. |
| Unity root not found | The project root must contain Assets/ and ProjectSettings/ProjectVersion.txt; files outside that tree do not work. |
| No suggestions for indirect inheritance | Install a C# LSP (Roslyn) and make sure .sln / .csproj files are generated. |
blink.cmpis not supported. Only an nvim-cmp source exists, so installations using blink.cmp will not see suggestions.- Message lists ship with the plugin (static); they are not updated automatically per Unity version.
- Only three class types are recognized: MonoBehaviour, ScriptableObject and
UnityEditor.Editor.
The plugin writes no files, cache directory or Unity project settings. To remove it, revert only the lines you added:
-
Delete the plugin spec — remove
lua/plugins/unitykit.lua(or the block from the file where you added the spec). -
Remove the cmp source registration — remove the
{ name = "unitykit", priority = 1000 }line fromrequire("cmp").setup({ sources = ... }). -
Remove the
setup()call if present — if you configured the plugin elsewhere withrequire("unitykit").setup({...}), drop that block. -
Clean the plugin from disk — restart Neovim and run:
:Lazy clean
This deletes plugins that no longer have a spec (including unitykit.nvim). To remove it by hand:
rm -rf ~/.local/share/nvim/lazy/unitykit.nvim. -
Verify —
:checkhealth unitykitshould now say "not found", and the plugin should no longer appear in the:Lazylist.
Notes on leftovers:
- If you use
lazy-lock.json, theunitykit.nvimentry drops out by itself after:Lazy clean; if it does not, delete that line from the file. - There is nothing to clean up in the Unity project: nothing is written under
Assets/,Packages/orProjectSettings/. The.sln/.csprojfiles mentioned in step 4 belong to Unity and are needed by the LSP; uninstalling unitykit does not require deleting them. - All plugin state is kept in memory (buffer cache, cmp registration) and disappears when Neovim exits.
- Help:
:help unitykit(source:doc/unitykit.txt) - Design:
docs/superpowers/specs/2026-10-27-unitykit-completion-design.md
MIT — see the LICENSE file.