Skip to content

Enable AL-LSP for Claude Code#652

Merged
haoranpb merged 2 commits into
features/al-lspfrom
features/claude-al-lsp
May 28, 2026
Merged

Enable AL-LSP for Claude Code#652
haoranpb merged 2 commits into
features/al-lspfrom
features/claude-al-lsp

Conversation

@haoranpb
Copy link
Copy Markdown
Collaborator

Stacked on top of #651 (Copilot AL-LSP).

Adds per-task AL Language Server support for Claude Code, mirroring the Copilot integration. Uses Claude's --plugin-dir flag to load a per-task plugin folder under <repo>/.claude/plugins/al-lsp/ — no marketplace registration, no ENABLE_LSP_TOOL global state, no cross-run plugin leakage.

What's in the plugin folder

<repo>/.claude/plugins/al-lsp/
├── .claude-plugin/plugin.json   # minimal manifest (only `name` is required)
└── .lsp.json                    # `{ "altool": { "command": "al", "args": [...], "extensionToLanguage": {".al": "al"} } }`

Claude's LSP schema differs from Copilot's: no lspServers wrapper, and extensionToLanguage instead of fileExtensions. Symbol-path resolution and the artifact-cache fallback are shared with the Copilot path.

Changes

  • agent/shared/lsp.py — split into build_copilot_lsp_config (unchanged) + new build_claude_lsp_plugin. Common _prepare_lsp helper.
  • agent/claude/agent.py — accepts al_lsp, calls the new builder, passes --plugin-dir, records al_lsp_enabled in ExperimentConfiguration.
  • commands/run.py + commands/evaluate.py — add --al-lsp to claude commands.
  • .github/workflows/claude-evaluation.yml — adds al-lsp boolean input; Install AL Tool step now runs for al-mcp OR al-lsp; altool bumped to 18.0.36.64936-beta; requeue payload propagates the flag.
  • tests/test_lsp_config.py — restructured into TestCopilotLspConfig (11) + TestClaudeLspPlugin (11). Claude class covers plugin layout, Claude-specific schema, container vs artifact-cache priority, error path.
  • EXPERIMENT.md — surfaces al-lsp alongside al-mcp.

Diff stat: 9 files, +237 / -68.

Verification

  • uv run pytest -q434/434 pass (was 423 on features/al-lsp; +11 new Claude tests).
  • uv run pre-commit run --all-files — clean.
  • Structural smoke-test — built the plugin folder for BCApps-5633 via the live build_claude_lsp_plugin call. plugin.json + .lsp.json on disk match the expected Claude schema; altool launchlspserver args resolved from the BC artifact cache.
  • altool launchlspserver itself is already verified on Enable AL-LSP for evaluation #651 (24 LSP endpoints, full initialize capabilities response). The Claude side only changes how the LSP routing is consumed, not how altool serves it.

Cannot live-test locally

Node/npm is not installed on the local Windows machine, so claude --plugin-dir <path> cannot be exercised end-to-end here. CI runners install Claude via npm install -g @anthropic-ai/claude-code and will be the first live --al-lsp validation. The plugin-folder layout matches the reference installer in BC-DeveloperExperience\eng\operations\Install-AlLspPlugin.ps1.

bcbench and others added 2 commits May 28, 2026 08:55
Mirrors the Copilot AL-LSP integration for Claude Code. Per-task isolation
via Claude's --plugin-dir flag — no marketplace registration, no ENABLE_LSP_TOOL
global state, no cross-run plugin leakage.

- agent/shared/lsp.py: split build_lsp_config into build_copilot_lsp_config
  (writes .github/lsp.json, auto-discovered by Copilot CLI) and
  build_claude_lsp_plugin (writes a per-task plugin folder under
  <repo>/.claude/plugins/al-lsp/). Both share _resolve_symbol_paths /
  _build_lsp_args via a tiny _prepare_lsp helper.
- agent/claude/agent.py: call build_claude_lsp_plugin, pass --plugin-dir to
  claude, record al_lsp_enabled in ExperimentConfiguration.
- commands/run.py + commands/evaluate.py: add --al-lsp to the claude commands.
- .github/workflows/claude-evaluation.yml: add al-lsp boolean input; Install
  AL Tool now triggers on al-mcp OR al-lsp; altool bumped to the version that
  supports launchlspserver; requeue payload propagates the flag.
- tests/test_lsp_config.py: split into TestCopilotLspConfig and
  TestClaudeLspPlugin (22 tests total); the Claude class verifies plugin
  folder layout, Claude's distinct schema (no lspServers wrapper,
  extensionToLanguage instead of fileExtensions), and the priority order
  (compiler folder > artifact cache).
- EXPERIMENT.md: surface al-lsp alongside al-mcp in the workflow inputs list.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Reviewer feedback: instead of two writers (.github/lsp.json for Copilot,
.claude/plugins/al-lsp/ for Claude), use `--plugin-dir <path>` for both
agents and ship a single plugin folder shape under <repo>/.bcbench/al-lsp-plugin/.

Both CLIs look for the manifest at .claude-plugin/plugin.json, both accept
--plugin-dir for ad-hoc per-session loading, so the only delta is the
.lsp.json schema (Copilot wraps in 'lspServers' and uses 'fileExtensions';
Claude has no wrapper and uses 'extensionToLanguage'). That branch lives in
a single ten-line _lsp_config_for() switch.

- agent/shared/lsp.py: collapse build_copilot_lsp_config + build_claude_lsp_plugin
  into one build_al_lsp_plugin(entry, category, repo_path, agent_type, ...). 113
  -> 95 LoC despite the new parameter.
- agent/copilot/agent.py: drop the .github/lsp.json auto-discovery path; now
  passes --plugin-dir <path> like Claude.
- agent/claude/agent.py: same call shape, same plugin folder.
- tests/test_lsp_config.py: parametrize across both AgentType values so every
  shared behavior is verified for both agents in one class (10 shared tests x 2
  agents + 2 schema-specific tests = 22). 227 -> ~150 LoC, same coverage.

Live-verified: copilot --plugin-dir <plugin> now logs
'Loaded 1 LSP servers from 1 plugins' and reads our LSP config exactly the
same way Claude would.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@haoranpb haoranpb merged commit 1ff2075 into features/al-lsp May 28, 2026
1 check passed
@haoranpb haoranpb deleted the features/claude-al-lsp branch May 28, 2026 12:01
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant