Skip to content

Language Server (skyls)

skyls is a Language Server Protocol (LSP) implementation for Starlark files. It provides IDE features like diagnostics, completion, hover documentation, go-to-definition, and formatting.

Diagnostics

Real-time error detection including undefined names, unused variables, and style issues via skylint rules.

Completion

Autocomplete for keywords, builtins, modules, and document symbols. Context-aware suggestions.

Hover

Documentation on hover for functions and variables defined in the current file.

Formatting

Format documents using buildifier-compatible formatting via skyfmt.

Go to Definition

Jump to function definitions, variable assignments, and load statement sources.

Document Symbols

Outline view showing all functions and top-level variables in a file.

Terminal window
go install github.com/albertocavalcante/sky/cmd/skyls@latest

Verify the installation:

Terminal window
skyls --version

Install the Sky Starlark extension from the VS Code marketplace, or configure the generic LSP client:

  1. Install the vscode-languageclient extension
  2. Add to your settings.json:
{
"starlark.lsp.enabled": true,
"starlark.lsp.path": "skyls"
}

Add to your Neovim configuration:

-- lua/plugins/lsp.lua or init.lua
local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')
-- Register skyls if not already defined
if not configs.skyls then
configs.skyls = {
default_config = {
cmd = { 'skyls' },
filetypes = { 'starlark', 'bzl', 'bazel', 'star' },
root_dir = lspconfig.util.root_pattern(
'WORKSPACE',
'WORKSPACE.bazel',
'MODULE.bazel',
'.buckconfig',
'Tiltfile',
'.git'
),
settings = {},
},
}
end
lspconfig.skyls.setup({
on_attach = on_attach, -- your on_attach function
capabilities = capabilities, -- your capabilities
})

Add filetype detection in ~/.config/nvim/filetype.lua:

vim.filetype.add({
extension = {
star = 'starlark',
bzl = 'bzl',
bazel = 'bazel',
},
filename = {
['BUILD'] = 'bazel',
['BUILD.bazel'] = 'bazel',
['WORKSPACE'] = 'bazel',
['WORKSPACE.bazel'] = 'bazel',
['MODULE.bazel'] = 'bazel',
['BUCK'] = 'bzl',
['Tiltfile'] = 'starlark',
},
})

Add to ~/.config/helix/languages.toml:

[[language]]
name = "starlark"
scope = "source.starlark"
injection-regex = "starlark"
file-types = ["star", "bzl", "bazel", "BUILD", "WORKSPACE", "Tiltfile"]
comment-token = "#"
indent = { tab-width = 4, unit = " " }
language-servers = ["skyls"]
[language-server.skyls]
command = "skyls"

Add to your Zed settings (~/.config/zed/settings.json):

{
"lsp": {
"skyls": {
"binary": {
"path": "skyls"
}
}
},
"languages": {
"Starlark": {
"language_servers": ["skyls"]
}
}
}

Install the LSP package, then add to LSP settings:

{
"clients": {
"skyls": {
"enabled": true,
"command": ["skyls"],
"selector": "source.starlark | source.bazel"
}
}
}

Add to your Emacs configuration:

(use-package lsp-mode
:hook ((starlark-mode . lsp)
(bazel-mode . lsp))
:config
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection '("skyls"))
:major-modes '(starlark-mode bazel-mode)
:server-id 'skyls)))
Terminal window
skyls [options]
OptionDescription
--versionPrint version and exit
--helpShow help message

The server communicates over stdin/stdout using the JSON-RPC 2.0 protocol as defined by the LSP specification.

MethodSupport
initializeFull
initializedFull
shutdownFull
exitFull
MethodSupport
textDocument/didOpenFull
textDocument/didChangeFull (full sync)
textDocument/didCloseFull
textDocument/didSaveFull
MethodSupport
textDocument/hoverFunctions and globals in current file
textDocument/completionKeywords, builtins, modules, document symbols
textDocument/definitionSame-file definitions
textDocument/documentSymbolFunctions and top-level assignments
textDocument/formattingFull document formatting

skyls provides two types of diagnostics:

  • undefined-name: Reference to undefined variable or function
  • unused-variable: Local variable defined but never used

Buildtools-compatible lint rules including:

skyls provides context-aware completions:

  • Keywords: def, if, for, return, load, etc.
  • Builtins: len, range, str, dict, list, etc.
  • Modules: json, math, time
  • Document symbols: Functions and variables defined in the current file

When typing after a dot (e.g., json.), skyls completes module members:

json. # Completes: decode, encode, indent
math. # Completes: ceil, floor, round, sqrt, pow, log, exp, pi, e, inf

Inside a function body, parameters are included in completions:

def process(input_data, config):
# Typing 'in' suggests 'input_data'
# Typing 'co' suggests 'config'

skyls automatically detects the file type based on filename patterns:

PatternFile KindParser Mode
BUILD, BUILD.bazelBUILDBazel BUILD
*.bzlBzlBazel extension
WORKSPACE, WORKSPACE.bazelWORKSPACEBazel workspace
MODULE.bazelMODULEBazel module
BUCKBUCKBuck2 BUILD
TiltfileStarlarkGeneric
*.star, *.skyStarlarkGeneric
  1. Cross-file navigation: Go-to-definition only works within the same file
  2. Dialect-specific builtins: Custom dialect support is being implemented (see Custom Dialects)
  3. Signature help: Parameter hints while typing function calls
  4. Code actions: Quick fixes for diagnostics
  5. Workspace symbols: Find symbols across all files
  6. Rename: Refactoring support
  1. Verify skyls is in your PATH:

    Terminal window
    which skyls
  2. Check the server runs manually:

    Terminal window
    echo '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"capabilities":{}}}' | skyls
  1. Ensure the file is saved (diagnostics run on save)
  2. Check the editor’s LSP logs for errors
  3. Verify the file type is correctly detected

skyls caches parsed documents and only re-analyzes on changes. If you experience slowness:

  1. Check if the file is very large (>10,000 lines)
  2. Ensure you’re not editing in a directory with thousands of Starlark files
  3. Check system resources (memory, CPU)