# Debug Server
Each Deft runtime can expose an in-process **debug server** that
external processes (the shell app, editors, VS Code extensions,
custom tooling) connect to via TCP. The protocol is JSON-RPC 2.0
over newline-delimited TCP.
Use cases:
- Live introspection from an external REPL.
- Editor integration: list defs, get source, inspect variables,
complete symbols.
- Step-debugger backends.
- Hot-reload workflows.
## `debug/*` Stdlib functions
| Function | Returns | Purpose |
|---|---|---|
| `[debug/serve :name $port]` | server resource | Start a debug server |
| `[debug/stop $server]` | nil | Stop a server |
| `[debug/list]` | list | List active debug servers |
## Starting a Server
def srv [debug/serve :my-app 8765] echo "debug server on :8765"
External processes can now connect to `127.0.0.1:8765` and start
sending JSON-RPC requests.
## The Protocol
JSON-RPC 2.0 over newline-delimited TCP. Each request is a
single-line JSON object; each response is a single-line JSON object.
```json
{
"jsonrpc": "2.0",
"id": 1,
"method": "eval",
"params": { "code": "(+ 1 2)" }
}
```
```json
{
"jsonrpc": "2.0",
"id": 1,
"result": { "value": 3, "print": "" }
}
```
Notifications (no `id`) are used for events the server emits
spontaneously — trace output, breakpoints firing, etc.
## Common Methods
| Method | Purpose |
|---|---|
| `eval` | Evaluate a code string in the runtime |
| `list-defs` | List defs in the current namespace |
| `list-vars` | List vars in the current namespace |
| `inspect` | Inspect a named value |
| `get-source` | Get the source code of a def |
| `complete` | Complete a symbol at a cursor position |
| `reload` | Reload a module |
See `packages/stdext/src/debug-host.dft` for the host-side
implementations and `packages/stdext/src/debug-client.dft` for a
Deft-level client you can embed in your own tooling.
## Connecting a Client
Any TCP-speaking process can connect. A minimal Deft client:
import "deft/stdext/debug-client" as dbg def session [dbg/connect 8765] set result [dbg/eval $session "(+ 1 2)"] echo $result~value # => 3 set defs [dbg/list-defs $session] for name $defs { echo $name } dbg/_close $session
`packages/stdext/src/debug-client.dft` provides a full client with
reconnect, retry, and request/response correlation.
## The Shell's Use
The TUI's `shell` app uses the debug protocol to provide an
in-process REPL. When you "attach" the shell to a runtime, it
spawns a child runtime running a debug server, then drives it from
the shell panel:
# packages/stdext/src/repl.dft (simplified) def create {|name| if [runtime/exists? $name] { return $name } if [err? [runtime/create $name]] { return nil } runtime/spawn $name [launcher-path] %{ :repl-name $name } | }
The launched REPL host opens a debug server on a per-name port;
the shell connects and routes user input through `eval`.
## Editor Integration
The editor app connects to the active shell's debug server to
provide:
- Symbol completion (`complete` method)
- Go-to-definition (`inspect` + `get-source`)
- Inline documentation (`get-source` + `info/props`)
- Eval-in-REPL (`eval`)
See `packages/editor/src/editor.dft` and
`packages/stdext/src/debug-client.dft` for the production code.
## Limits
- Max 8 debug servers per process.
- Max 16 sessions per server.
- Sessions are line-buffered; very large eval payloads should be
chunked.
## Lifecycle
def srv [debug/serve :dev 8765] # ... server runs in the background, dispatching requests on the # event loop ... debug/stop $srv # graceful shutdown
`debug/stop` closes the listener and all active sessions. Sessions
get a clean EOF; they should reconnect if they want to keep talking.
## Quick Reference
| Form | Purpose |
|---|---|
| `[debug/serve :name $port]` | Start server |
| `[debug/stop $server]` | Stop server |
| `[debug/list]` | Active servers |
| Client: `dbg/connect $port` (from stdext/debug-client) | Connect |
| Client: `dbg/eval $session $code` | Eval |
| Client: `dbg/list-defs $session` | List defs |
| Client: `dbg/_close $session` | Disconnect |