Files
autocomplete-model/daemon
HarvmasterandClaude Opus 5.5 3dc916834f
ci / build (push) Canceled after 0s
Daemon: a changed default model overrides the saved state (0.6.3)
In managed mode the extension switches models by rewriting the daemon config's
defaultModel and restarting it, but loadState() preferred the persisted model, so the
daemon came back on the old one every time. State now records the default it was saved
under; a different default wins.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01J39imRDT8L7xYbWzsVWd8A
2026-10-04 01:06:31 +00:00
..

acd: local completion daemon

Builds fill-in-the-middle prompts in exactly the format the models were trained on (it shares ../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.

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 on Linux).

npm install
npm start                       # node src/main.ts --config acd.config.json
node src/acctl.ts status        # or: mode simple|symbols|raw · model <name> · 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", "<physical cores>"], 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 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