Language Server Protocol

The Covenant language server (covenant-lsp) implements LSP 3.17 and provides IDE intelligence for .cvt files. It ships inside the covenant-cli binary — no separate installation needed.

Capabilities

CapabilityStatusNotes
Diagnostics (on save)✅ FullAll E/W/L codes
Diagnostics (on type)✅ Full< 100ms latency
Hover✅ FullType + domain + docs
Go-to-definition✅ FullFields, actions, events, errors
Find references✅ FullCross-file
Rename symbol✅ FullSafe rename with preview
Autocomplete✅ FullContext-aware
Signature help✅ FullFHE opcodes + stdlib
Code formatting✅ Fullcovenant fmt
Inline hints✅ FullType + domain labels
Semantic tokens✅ FullFull syntax theme
Code actions✅ Partial12 quick-fix actions
Inlay hints✅ FullDomain P/E labels
Workspace symbols✅ FullSearch all contracts
Document outline✅ FullFields, actions, events tree
Folding ranges✅ FullBlock folding
Call hierarchy🔲 PlannedV0.8
Type hierarchy🔲 PlannedV0.8

Installation

VS Code (Primary Support)

Install from the VS Code Marketplace:

# Via CLI
code --install-extension valisthea.covenant-lang

# Or search "Covenant" in the VS Code Extensions panel

The extension bundles covenant-lsp and starts it automatically when you open a .cvt file. No PATH configuration needed.

Minimum requirements: VS Code 1.85+, Node.js 18+ (for the extension host).

Neovim

Install with your plugin manager, then configure with nvim-lspconfig:

-- lazy.nvim
{
  "neovim/nvim-lspconfig",
  config = function()
    require("lspconfig").covenant_lsp.setup({
      cmd = { "covenant", "lsp" },
      filetypes = { "covenant" },
      root_dir = require("lspconfig.util").root_pattern("covenant.toml"),
    })
  end,
}

Treesitter grammar for Covenant (syntax highlighting):

:TSInstall covenant

IntelliJ / JetBrains IDEs

Install the “Covenant Language” plugin from JetBrains Marketplace. The plugin connects to covenant lsp via the LSP4IJ bridge. Requires IntelliJ 2024.1+ or any 2024+ JetBrains IDE.

Note: IntelliJ support is community-maintained. Feature parity with VS Code is ~80%. Code actions and quick-fixes have limited support.

Lint Detectors

The LSP runs 38 lint detectors across four categories. These appear as squiggles in the editor and in the Problems panel. See Diagnostics Catalog for the full list.

Security lints (L-SEC-001 to L-SEC-010)

The most important category. L-SEC-003 (reentrancy risk) detects the Checks-Effects-Interactions pattern violation — the pattern behind most DeFi exploits:

// L-SEC-003: external call before state update
action withdraw(amount: amount) only owner {
    transfer(caller, amount)      // <- external call FIRST
    balances[caller] -= amount    // <- state update SECOND (reentrancy!)
}

// Correct: CEI pattern
action withdraw(amount: amount) only owner {
    balances[caller] -= amount    // 1. Effects
    transfer(caller, amount)      // 2. Interaction
}

Privacy lints (L-PVT-001 to L-PVT-005)

L-PVT-001 fires when an event emits an encrypted value without the @confidential flag. This is a common mistake: the event value is encrypted in storage but the event itself would leak the ciphertext to public indexers.

Gas lints (L-GAS-001 to L-GAS-005)

L-GAS-001 detects map<address, bool> used as a whitelist — the standard pattern wastes gas. The suggestion: use set<address> which stores membership via trie, not individual storage slots.

Correctness lints (L-COR-001 to L-COR-008)

L-COR-007 warns when a guard uses block.timestamp. Miners can manipulate block.timestamp by up to ~15 seconds, which is enough to break deadline-based mechanics in high-frequency trading or MEV-sensitive contracts.

Hover

Hovering over any identifier shows:

  • Fields: type, domain (P/E/A), storage slot, default value
  • Actions: signature, guards, gas estimate
  • Events: fields, indexed status
  • Errors: parameters, common cause
  • FHE opcodes: gas cost, domain requirements, precompile address
  • Built-ins: description, type

Example hover for fhe_add:

fhe_add(a: encrypted<T>, b: encrypted<T>) -> encrypted<T>

Homomorphic addition. Domain: E -> E.
Precompile: 0x10. Gas: 8,000 (L1) / 400 pGas (Aster).
ERC-8227 §3.2.

Autocomplete

Context-aware completion:

  • After only → suggests field names of type address
  • After fhe_ → shows all FHE opcodes with signatures
  • After event → shows declared events
  • After revert_with → shows declared errors
  • After emit → shows declared events
  • Inside amnesia { } → shows destroy(), on_destroy
  • After @ → shows available annotations (pq_signed, prove_offchain, amnesia_eligible)

Configuration

The LSP reads covenant.toml in the workspace root:

[lsp]
# Lint severity overrides (error/warning/hint/off)
L-GAS-003 = "off"          # disable string error lint
L-SEC-005 = "warning"       # downgrade PQ recommendation

# Inline hints
inlay_hints = true
domain_labels = true        # show P/E/A labels on expressions
gas_estimates = true        # show gas cost hints on FHE ops

# Formatting
indent = "4spaces"          # or "2spaces", "tabs"
trailing_newline = true
max_line_length = 100

Performance

The LSP is designed for large workspaces:

MetricTarget
First-open diagnostic latency< 500ms
On-type diagnostic latency< 100ms
Completion latency< 50ms
Go-to-definition< 20ms
Workspace indexing (100 files)< 5s

The LSP maintains an in-memory cache of all parsed contracts. Incremental re-parsing only re-analyzes the changed file and its dependents.

Known Issues

  • V0.7: Rename symbol does not work across external contract references (only within the same file/import tree). Fixed in V0.8.
  • V0.7: IntelliJ integration does not show inline domain labels. Workaround: use hover.
  • V0.7: Workspace symbols does not index contracts inside node_modules. By design; add covenant.toml to project root.

Reporting Bugs

covenant lsp-report

This command generates a diagnostic bundle (LSP logs + contract snapshot) for filing issues at github.com/Valisthea/covenant-lang/issues.

See Also