# acd: local completion daemon Builds fill-in-the-middle prompts in exactly the format the models were trained on (it shares [`../shared/`](../shared) with the training pipeline) and serves completions through a llama-server it manages. Editors talk to it over localhost HTTP. Design notes: [../docs/architecture.md](../docs/architecture.md). **You usually don't run this yourself:** the VS Code extension bundles it and runs it in *managed mode*. Run it standalone for external mode, for other editors, or when developing. ## Running standalone Requires Node ≥ 22.18 (runs TypeScript directly) and a `llama-server` binary (`brew install llama.cpp` on macOS, or a [llama.cpp release](https://github.com/ggml-org/llama.cpp/releases) on Linux). ```sh npm install npm start # node src/main.ts --config acd.config.json node src/acctl.ts status # or: mode simple|symbols|raw · model · on · off npm run smoke # end-to-end test (needs the models from ../models, via Git LFS) ``` `acd.config.json` uses `llama-server` from your PATH with `-ngl 99` (Apple GPU), and the models in `../models`. - **Linux / CPU:** copy it to `acd.config.local.json` (git-ignored), set `"binary"` to your llama-server and `"args": ["-t", ""]`, then run `node src/main.ts --config acd.config.local.json`. - **Serving another machine** (e.g. an M1 Max serving a laptop): set `"host": "0.0.0.0"` and point the editor's `serverUrl` at it, using `daemon.mode: "external"`. There's no auth, so only do this on a trusted network. - **Start on login:** [`acd.service`](acd.service) is a systemd user unit. ## Context modes | mode | prompt | models | |---|---|---| | `symbols` | repo header + language-service symbols (imports' signatures, repo-local types), from `../shared/symbols.ts`, the same code that built the training data. Requires the editor to send `workspaceRoot`; otherwise the request runs as `simple`. | stage-c | | `simple` | repo name + file path header | stage-c | | `raw` | plain suffix-first FIM | stage-b (spm), base-0.5b (psm) | The mode and model are global to the daemon and persisted in `acd.state.json`. VS Code, Zed and `acctl` all see the same toggle. **How symbols mode stays fast:** - Context is built in a worker thread (one TypeScript language service per workspace) and cached per *anchor*: the file, the enclosing top-level declaration and the import block. While you type inside one function the header is identical and the KV cache keeps hitting; the smoke test shows the same ~2 re-processed tokens per keystroke as `simple`. - When the anchor changes, the daemon waits up to `symbols.waitMs` for fresh context, else uses the file's previous context (stale-while-revalidate). - Member completions after `.` are off (`symbols.members`): every `.` would change the header and force a cold prefill. **`this.` repair** (`thisRepair.enabled`, any mode, needs `workspaceRoot`): when the identifier you're typing only resolves as a member of the enclosing class, the daemon completes as if `this.` were there. It returns `replaceBefore` + `filterText` so the editor replaces `getU` with `this.getUser(id)`. **Edit recordings:** `POST /v1/edits` appends opted-in editor edit events to `recording.dir` (default `recordings/`, git-ignored). These are the future training data for next-edit prediction. ## API - `POST /v1/fim`: `{ requestId?, repo, path, languageId?, prefix, suffix, prefixLineOffset?, mode?, singleLine?, maxLines? }` returns `{ text, mode, singleLine, timings, … }`. A newer request cancels the in-flight one; closing the connection cancels too. - `GET|PUT /v1/config`: `{ enabled, model, mode }`. Changing the model restarts llama-server. - `POST /v1/feedback`: editor events, written to the local log only when `telemetry.enabled`. - `POST /v1/edits`: `{ events }` from editors that opted in to edit recording. - The `/v1/fim` request may include `workspaceRoot` (absolute path on the daemon's machine). Responses may include `replaceBefore` / `filterText` (the `this.` repair) and `symbols: { status: hit|fresh|stale|none, items }`. - `GET /health`