A comprehensive Language Server Protocol (LSP) implementation for Buildkite pipeline files, providing rich IDE features for productive pipeline development.
- β Hover Documentation - Rich contextual help with Markdown formatting for all pipeline properties and plugins
- β Document Symbols - Hierarchical pipeline navigation with step detection for quick navigation
- β Smart Autocompletion - Context-aware suggestions for properties, plugins, and step types with snippets
- β Enhanced Diagnostics - Multi-level validation with precise error locations and actionable messages
- β Signature Help - Contextual parameter hints for step types and plugin configurations
- β
Go-to-Definition - Navigate to step definitions from
depends_onreferences - β Code Actions - Quick fixes for common issues (add missing labels, fix empty commands, etc.)
- β Semantic Highlighting - Rich syntax highlighting for step types, properties, and plugin names
- β YAML Validation - Real-time YAML syntax validation
- β Schema Validation - Official Buildkite pipeline schema validation
- β Plugin Validation - Dynamic validation of 200+ plugin configurations from the Buildkite Plugin Directory
- β
Smart File Detection - Automatically activates for
.buildkite/files and common pipeline patterns
Install using Mason.nvim:
-- Install via Mason
:MasonInstall buildkite-ls
-- Or add to your Mason setup
require('mason').setup()
require('mason-lspconfig').setup({
ensure_installed = { 'buildkite_ls' }
})Download from GitHub Releases:
# Linux/macOS
curl -L https://github.com/mcncl/buildkite-ls/releases/latest/download/buildkite-ls_linux_amd64.tar.gz | tar xz
sudo mv buildkite-ls /usr/local/bin/
# Or use the install script
curl -fsSL https://raw.githubusercontent.com/mcncl/buildkite-ls/main/install.sh | bashgit clone https://github.com/mcncl/buildkite-ls.git
cd buildkite-ls
go build -o buildkite-ls ./main.go
# Install to PATH (optional)
sudo mv buildkite-ls /usr/local/bin/First install via Mason, then configure:
-- ~/.config/nvim/lua/buildkite-ls.lua or in your init.lua
-- Install and setup Mason
require('mason').setup()
require('mason-lspconfig').setup({
ensure_installed = { 'buildkite_ls' }
})
local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')
-- Add buildkite-ls to lspconfig
if not configs.buildkite_ls then
configs.buildkite_ls = {
default_config = {
cmd = { 'buildkite-ls' },
filetypes = { 'yaml' },
root_dir = lspconfig.util.root_pattern('.buildkite', 'pipeline.yml', 'pipeline.yaml', '.git'),
settings = {},
single_file_support = true,
},
}
end
-- Setup the language server
lspconfig.buildkite_ls.setup {
on_attach = function(client, bufnr)
-- Enable semantic tokens if supported
if client.server_capabilities.semanticTokensProvider then
vim.lsp.semantic_tokens.start(bufnr, client.id)
end
end,
}local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')
-- Add buildkite-ls to lspconfig
if not configs.buildkite_ls then
configs.buildkite_ls = {
default_config = {
cmd = { 'buildkite-ls' },
filetypes = { 'yaml' },
root_dir = lspconfig.util.root_pattern('.buildkite', 'pipeline.yml', 'pipeline.yaml', '.git'),
settings = {},
single_file_support = true,
},
}
end
-- Setup the language server
lspconfig.buildkite_ls.setup {
on_attach = function(client, bufnr)
-- Enable semantic tokens if supported
if client.server_capabilities.semanticTokensProvider then
vim.lsp.semantic_tokens.start(bufnr, client.id)
end
end,
}-- ~/.config/nvim/lua/plugins/buildkite.lua
return {
{
"neovim/nvim-lspconfig",
opts = {
servers = {
buildkite_ls = {
cmd = { "buildkite-ls" },
filetypes = { "yaml" },
root_dir = require("lspconfig.util").root_pattern(".buildkite", "pipeline.yml", "pipeline.yaml", ".git"),
single_file_support = true,
},
},
},
},
}Enable semantic tokens in your Catppuccin configuration:
require("catppuccin").setup({
integrations = {
native_lsp = {
enabled = true,
virtual_text = {
errors = { "italic" },
hints = { "italic" },
warnings = { "italic" },
information = { "italic" },
},
underlines = {
errors = { "underline" },
hints = { "underline" },
warnings = { "underline" },
information = { "underline" },
},
},
semantic_tokens = true,
}
})If you want to customize semantic token colors for Buildkite files:
-- Define custom semantic token highlights
vim.api.nvim_create_autocmd("ColorScheme", {
pattern = "*",
callback = function()
-- Buildkite-specific semantic token colors
vim.api.nvim_set_hl(0, "@lsp.type.keyword", { fg = "#f38ba8", bold = true }) -- Step types (command, wait, block)
vim.api.nvim_set_hl(0, "@lsp.type.string", { fg = "#a6e3a1" }) -- String values
vim.api.nvim_set_hl(0, "@lsp.type.property", { fg = "#89b4fa" }) -- YAML properties
vim.api.nvim_set_hl(0, "@lsp.type.variable", { fg = "#f9e2af" }) -- Environment variables
vim.api.nvim_set_hl(0, "@lsp.type.function", { fg = "#cba6f7" }) -- Plugin names
vim.api.nvim_set_hl(0, "@lsp.type.namespace", { fg = "#fab387" }) -- Step keys and labels
vim.api.nvim_set_hl(0, "@lsp.type.operator", { fg = "#89dceb" }) -- YAML operators (:, -)
vim.api.nvim_set_hl(0, "@lsp.type.comment", { fg = "#6c7086", italic = true }) -- Comments
end,
})The language server provides these semantic token types for rich highlighting:
| Token Type | Used For | Example |
|---|---|---|
keyword |
Step types and boolean values | command:, wait:, true, false |
string |
Labels, commands, and string values | "Build App", "make test" |
property |
YAML property keys | timeout_in_minutes:, branches: |
variable |
Environment variables | env:, env values |
function |
Plugin names with versions | docker#v5.13.0, cache#v2.4.10 |
namespace |
Step identifiers | key:, label: values |
operator |
YAML structural elements | :, -, | |
comment |
YAML comments | # This is a comment |
Create a VS Code extension or add to your settings.json:
{
"yaml.schemas": {
"https://raw.githubusercontent.com/buildkite/pipeline-schema/main/schema.json": [
"pipeline.yml",
"pipeline.yaml",
".buildkite/pipeline.yml",
".buildkite/pipeline.yaml"
]
}
}Note: Full VS Code extension coming soon.
Hover Documentation: Get detailed help for any pipeline property:
steps:
- label: "Build" # Hover shows: Human-readable name for the step
command: "make build" # Hover shows: Shell command(s) to execute
timeout_in_minutes: 30 # Hover shows: Maximum time the step can runSmart Autocompletion: Context-aware suggestions:
- Top-level properties (
steps,env,agents) - Step properties (
label,command,plugins,depends_on) - Plugin names with versions (
docker#v5.13.0,cache#v2.4.10) - Step types (
command,wait,block,input,trigger)
Document Symbols: Navigate your pipeline structure:
- Pipeline sections (
env,agents,steps) - Individual steps with their labels
- Step types (Command Step, Wait Step, Block Step, etc.)
Go-to-Definition: Jump from step references to definitions:
steps:
- label: "Build"
key: "build-step"
- label: "Test"
depends_on: "build-step" # Ctrl+click to jump to build stepCode Actions: Quick fixes for common issues:
- Add missing
labelto steps - Add missing
keyto steps - Fix empty
commandvalues - Convert single commands to command arrays
- Add missing step types
Enhanced Diagnostics: Precise error reporting:
- Schema validation errors with exact locations
- Plugin configuration validation
- Step dependency validation
- Multi-level severity (Error, Warning, Info)
steps:
- label: "Build"
command: "make build"
agents:
queue: "default"
- label: "Test"
command: "make test"
depends_on: "build"
artifact_paths: "coverage/*"env:
NODE_ENV: production
steps:
- label: ":rocket: Build"
command: "npm run build"
key: "build"
plugins:
- docker#v5.13.0:
image: "node:18"
volumes:
- ".:/app"
workdir: "/app"
- cache#v2.4.10:
key: "npm-{{ checksum 'package-lock.json' }}"
paths:
- "node_modules"
- wait: "Ready to deploy?"
- block: "Deploy to production?"
prompt: "Deploy the build to production?"
- label: ":truck: Deploy"
command: "./deploy.sh"
depends_on: "build"env:
NODE_ENV: production
APP_VERSION: "1.0.0"
agents:
queue: "default"
os: "linux"
steps:
- label: ":hammer: Build"
key: "build"
command:
- "npm ci"
- "npm run build"
- "npm run test"
artifact_paths: "dist/**/*"
plugins:
- docker#v5.13.0:
image: "node:18-alpine"
volumes: [".:/app"]
workdir: "/app"
- wait: "Build complete"
- input: "Release version"
key: "release-input"
fields:
- text: "version"
required: true
default: "1.0.0"
- label: ":package: Package"
command: "docker build -t myapp:${BUILDKITE_BUILD_NUMBER} ."
depends_on:
- "build"
- "release-input"
- block: ":rocket: Deploy to production?"
prompt: "This will deploy to production. Are you sure?"
- trigger: "deploy-pipeline"
async: false
build:
message: "Deploy ${BUILDKITE_MESSAGE}"
commit: "${BUILDKITE_COMMIT}"
branch: "${BUILDKITE_BRANCH}"The language server automatically fetches schemas for popular plugins. For custom plugins:
- Plugin schemas are cached locally after first fetch
- Internet access required for initial plugin validation
- Supports 200+ plugins from the Buildkite Plugin Directory
The language server activates for:
- Any
.ymlor.yamlfile inside a.buildkite/directory - Files named:
pipeline.yml,pipeline.yaml,buildkite.yml,buildkite.yaml - Can be configured to activate on specific file patterns
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Add tests for new functionality
- Ensure all tests pass (
go test ./...) - Commit your changes (
git commit -am 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Submit a pull request
git clone https://github.com/mcncl/buildkite-ls.git
cd buildkite-ls
go mod download
go test ./...MIT License - see LICENSE file for details.
- Built with go.lsp.dev/protocol for LSP implementation
- Schema validation powered by gojsonschema
- Plugin schemas from the Buildkite Plugin Directory
- YAML parsing with gopkg.in/yaml.v3
Happy Building! π