# LSP Container Configuration ## Status - **bash-language-server**: ✅ Working - Fixed crash by adding `start` command - **docker-language-server**: ✅ Working - Fixed by adding `start --stdio` command - **marksman**: ✅ Working - Fixed by adding `server` command ## Architecture Notes ### Why LSP Containers Don't Run Continuously The bash, docker, and markdown LSP servers are **stdio-based LSP servers**. This means: 1. They communicate via stdin/stdout (not network sockets) 2. Each LSP client needs its own process instance 3. They exit when the client disconnects (end of stdin) This is **by design** and is the standard way LSP servers work: ``` Crush Session 1 → docker run -i bash-lsp → [bash-language-server process] Crush Session 2 → docker run -i bash-lsp → [bash-language-server process] ``` Each session needs its own container instance because the stdio connection is 1-to-1. ### Startup Performance Despite creating new containers for each session, startup is fast because: 1. **Docker images are pre-built**: No build time 2. **Container creation is fast**: < 1 second typically 3. **Layers are cached**: All dependencies already present The main delay only happens on the first startup when the image is built. ### Alternatives for Persistent Containers If you truly need persistent containers to avoid all startup delay, you would need: #### Option 1: TCP-based LSP Servers - Modify LSP servers to listen on TCP ports instead of stdio - Run containers in detached mode with exposed ports - Connect to existing containers Pros: Zero startup delay, true persistent containers Cons: Requires modifying LSP servers or finding TCP-compatible alternatives #### Option 2: Proxy Wrapper (Complex) - Run containers in detached mode with a proxy process - Proxy handles multiple Crush sessions - Routes stdio between Crush and LSP servers Pros: Persistent containers, no LSP server modifications Cons: Complex implementation, potential performance overhead, single point of failure #### Option 3: Current Implementation (Recommended) - Run on-demand with `docker run -i --rm` - Each Crush session gets its own container - Fast startup with pre-built images Pros: Simple, reliable, standard LSP architecture Cons: ~1 second startup per session ## Configuration The current `crush.json` configuration: ```json { "lsp": { "bash": { "command": "docker", "args": ["run", "-i", "--rm", "kneldevstack-aimiddleware-bash-language-server", "start"] }, "docker": { "command": "docker", "args": ["run", "-i", "--rm", "kneldevstack-aimiddleware-docker-language-server", "start", "--stdio"] }, "markdown": { "command": "docker", "args": ["run", "-i", "--rm", "kneldevstack-aimiddleware-marksman", "server"] } } } ``` ### Key Points - `-i`: Interactive mode (required for stdio) - `--rm`: Remove container after exit (cleanup) - Command arguments: `start`, `start --stdio`, `server` (varies by LSP) ## Troubleshooting ### "Container keeps crashing" If you see LSP containers restarting repeatedly, check: 1. **Is the container configured for detached mode?** - LSP servers should NOT run in detached mode - They should be started on-demand via `docker run -i` 2. **Is the command specified?** - `bash-language-server` needs `start` - `docker-language-server` needs `start --stdio` - `marksman` needs `server` 3. **Check crush.json configuration** - Ensure all command arguments are included - See configuration section above ### Testing LSP Servers Test each LSP manually: ```bash # Test bash LSP echo '{}' | timeout 2 docker run -i --rm kneldevstack-aimiddleware-bash-language-server start # Test docker LSP echo '{}' | timeout 2 docker run -i --rm kneldevstack-aimiddleware-docker-language-server start --stdio # Test marksman echo '{}' | timeout 2 docker run -i --rm kneldevstack-aimiddleware-marksman server ``` Expected: Exit code 124 (timeout), meaning the LSP server is running and waiting for input.