Editor integration
@actup/lsp is a Language Server Protocol server. It is pure and offline — it never touches the network in the hot path. It provides, for uses: refs in workflow / composite-action files:
- Diagnostics: floating refs (
@main), non-semver tags, and a bare pinned SHA with no# <ref>comment. - Code action: unpin — rewrite a
@<sha> # v4pin back to@v4. - Hover: action identity, ref classification (semver / SHA / floating branch / non-semver), the offline advisory, and the recorded ref for a commented SHA pin.
The network "is this outdated / what is latest" check is intentionally not in the language server — that needs a tag cache + provider and lives in the actup CLI/engine.
The server only activates for files that are workflow YAML (**/.github/workflows/*.yml / *.yaml) or a composite action (action.yml / action.yaml).
Running the server
The @actup/lsp package is part of this workspace and is not published standalone. Run it directly with Bun:
bun /path/to/actup-ts/packages/lsp/src/server.tsIt speaks LSP over stdio. A correctly framed initialize returns:
{ "serverInfo": { "name": "actup-lsp" }, "capabilities": { "textDocumentSync": 2, "codeActionProvider": true, "hoverProvider": true } }If you do not want a Bun dependency, the VS Code extension ships a Node-bundled copy of the server (see below) — no Bun needed there.
VS Code
Use the bundled extension in packages/vscode-extension (it embeds both the client and a Node build of this server). See that package's README for build / install. No separate LSP setup is required.
Neovim
Neovim's built-in LSP client can start the server directly. Add to your config (Lua), adjusting the absolute path:
local server = "/path/to/actup-ts/packages/lsp/src/server.ts"
vim.api.nvim_create_autocmd("FileType", {
pattern = "yaml",
callback = function(args)
local name = vim.api.nvim_buf_get_name(args.buf)
-- Only attach for workflow / action files (matches the server's own filter).
if not (name:match("%.github/workflows/.*%.ya?ml$") or name:match("action%.ya?ml$")) then
return
end
vim.lsp.start({
name = "actup-lsp",
cmd = { "bun", server },
root_dir = vim.fs.root(args.buf, { ".git", ".github" }),
})
end,
})Hover (K), code actions (vim.lsp.buf.code_action()) and diagnostics (vim.diagnostic.*) then work as usual. No nvim-lspconfig entry is needed, but you can wrap the same cmd in a custom configs definition if you prefer that workflow.
Zed
A Zed extension lives in editors/zed/ (a Rust crate compiled to WebAssembly). Like Neovim, it can't bundle the JS server, so it expects an actup-lsp command on PATH — a one-line wrapper:
#!/bin/sh
exec bun /path/to/actup-ts/packages/lsp/src/server.ts "$@"Make it executable and put it on your PATH (e.g. ~/.local/bin/actup-lsp).
Install the extension as a dev extension:
cargo build --release --target wasm32-wasip2ineditors/zed/(Zed also builds it for you on install).- Zed → command palette → zed: install dev extension → select the
editors/zed/directory.
Zed then starts the actup-lsp server for YAML buffers; the server's own filter means only workflow / action.yml files get diagnostics, hover and the unpin/bump/pin quick-fixes.
Verified: the extension compiles cleanly to wasm32-wasip2 (zed_extension_api 0.7) — the structural contract Zed loads. It has not been run inside a live Zed, and it is not published to the Zed extension registry; treat the install steps as standard Zed dev- extension usage, not an actup guarantee.
What is verified
The server command above is verified to answer an LSP initialize over stdio with the capabilities shown, and the diagnostics / code action / hover behaviour is covered by the package's in-memory test suite. The Neovim snippet uses only stock vim.lsp APIs and the server's documented stdio contract; it has not been auto-tested inside a live Neovim, so treat the exact keymaps as your normal Neovim setup, not an actup guarantee.