Actual Computer Setup Skill
Sets up actual.inc (Actual Computer) as a Loki inference
provider. Actual turns the user's own hardware into a private inference cluster
and exposes an OpenAI-compatible API two ways: a hosted end-to-end-encrypted
relay at https://api.actual.inc (authenticated with an ac_ key), and a local
on-device daemon at http://127.0.0.1:8080 (no auth on loopback). This skill
does not install the Actual daemon for the user — device authorization requires
a human in a browser.
When to Use
- User wants to add actual.inc as an inference provider (cloud relay or local).
- User has an
ac_ key and wants Loki routed through their Actual cluster.
- User wants fully-local, on-device inference via the Actual daemon.
- Troubleshooting: Actual requests failing with cryptic 400s or empty streams.
Prerequisites
- Loki has first-class
actual provider support (provider id actual,
aliases actual-computer, actualcomputer, aci). Do NOT configure Actual
as a custom_providers / providers.actual.* entry on current Loki — the
built-in provider owns the name and handles base-url normalization, the
Responses transport, and local no-auth automatically.
- Relay mode: an Actual account and an
ac_ inference key from
https://actual.inc/user/keys.
- Local mode: the user has installed the daemon
(
curl -fsSL "https://actual.inc/install" | bash) and completed device
authorization by running actual once and opening the printed
https://actual.inc/device?code=... URL in a browser. Relay that URL to the
user and WAIT — never invent an email or authorize on their behalf. Codes
expire in 5 minutes; re-run actual for a fresh one.
How to Run
Relay / API mode
- Put the key in
.env (secrets only — never config.yaml):
append ACTUAL_API_KEY=ac_... to ~/.loki/.env.
- Verify the key and discover models with
terminal:curl -s https://api.actual.inc/v1/models -H "Authorization: Bearer $ACTUAL_API_KEY"
- Select provider + model:
loki config set model.provider actual
loki config set model.default "MODEL_ID_FROM_DISCOVERY"
- Verify end-to-end:
loki chat -Q -q "Reply with exactly: ACTUAL_OK" --provider actual -m MODEL_ID
Local mode
- Human has installed + authorized the daemon (see Prerequisites).
- Download and load a model (scriptable once authorized):
actual models search "qwen2.5 0.5b instruct gguf" --limit 8 --no-prompt
# Downloads REQUIRE an explicit quantization (409 ambiguous_model_download otherwise):
actual models download "Qwen/Qwen2.5-0.5B-Instruct-GGUF/Q4_K_M"
actual models list # note the INSTALLED name (differs from download id)
actual models load "qwen2.5-0.5b-instruct-q4_k_m" # load by installed name
- Point Loki at the daemon.
ACTUAL_BASE_URL with a loopback host flips the
built-in provider into local no-auth mode automatically — no key needed:
append ACTUAL_BASE_URL=http://127.0.0.1:8080 to ~/.loki/.env, then:loki config set model.provider actual
loki config set model.default "INSTALLED_MODEL_NAME"
- Verify (reduced toolset — see context-window pitfall below):
loki chat -Q -q "Reply with exactly: LOCAL_OK" --provider actual -m INSTALLED_NAME -t file,web
Quick Reference
| Thing |
Value |
| Hosted relay |
https://api.actual.inc/v1 (normalized from bare host automatically) |
| Local daemon |
http://127.0.0.1:8080/v1 (no auth on loopback) |
| Key env var |
ACTUAL_API_KEY (ac_...) |
| Base URL env var |
ACTUAL_BASE_URL (loopback host ⇒ local no-auth mode) |
| Provider id / aliases |
actual / actual-computer, actualcomputer, aci |
| Transport |
Responses API (codex_responses) — built-in, do not override |
| Cluster pinning |
X-Cluster-ID header via providers.actual.extra_headers in config.yaml |
| Model size guide |
0.5B Q4_K_M ~470MB (toy), 7-8B Q4_K_M ~4.5GB (daily driver), 32B ~20GB |
Pitfalls
- reasoning_effort trap (handled by Loki since the first-class provider).
Actual's SGLang/vLLM backends accept only
none/low/medium/high/max;
xhigh/ultra used to fail with a cryptic
Expecting value: line 1 column 1 (char 0) (a wrapped HTTP 400). The
built-in provider clamps xhigh→high and ultra→max on the wire. If a
request still 400s this way on an old Loki, set a per-model cap:
agent.reasoning_overrides.<model>: high in config.yaml.
- Context-window overflow on small local models. Loki' default toolset
is ~26k tokens of schemas plus a ~9k-token system prompt. A model loaded
with a 32k context overflows before the first turn, and llama.cpp-family
servers emit a bare
data: [DONE] — Loki reports
Provider returned an empty stream with no finish_reason. This is NOT an
SSE bug. Fixes: restrict tools (-t file,web), load the model with a
larger n_ctx, or pick a >=64k-context model for the full toolset.
Upstream tracking: #51448 (do not file new issues; add evidence there).
Related but distinct: #65631 (HTTP-200 SSE carrying a 400), #56516
(reasoning-only streams).
- Download ids vs installed names.
actual models download takes
repo/QUANT and 409s without an explicit quantization;
actual models load takes the INSTALLED name from actual models list.
- Reasoning models returning empty content. GLM/Qwen reasoning variants
emit thinking in a separate
reasoning field and can burn a small
max_tokens entirely on reasoning. Give generous max_tokens before
assuming failure.
- Do not create a custom provider named
actual. Older setup guides
(pre first-class support) wrote providers.actual.* config blocks. On
current Loki the built-in provider wins the name; stale custom blocks
are ignored or conflict. Remove them and use the env vars + model.provider
flow above.
Verification
# Relay:
loki chat -Q -q "Reply with exactly: ACTUAL_OK" --provider actual -m MODEL
# Local (small model — reduced toolset):
loki chat -Q -q "Reply with exactly: LOCAL_OK" --provider actual -m MODEL -t file,web
# Provider status (local no-auth shows key_source=local-offline):
loki status
For other OpenAI-compatible clients (e.g. OpenCode), see
references/opencode.md.
1---2name: actual-setup3description: Set up Actual Computer (actual.inc) inference in Loki.4license: MIT5---67# Actual Computer Setup Skill89Sets up [actual.inc](https://actual.inc) (Actual Computer) as a Loki inference10provider. Actual turns the user's own hardware into a private inference cluster11and exposes an OpenAI-compatible API two ways: a hosted end-to-end-encrypted12relay at `https://api.actual.inc` (authenticated with an `ac_` key), and a local13on-device daemon at `http://127.0.0.1:8080` (no auth on loopback). This skill14does not install the Actual daemon for the user — device authorization requires15a human in a browser.1617## When to Use1819- User wants to add actual.inc as an inference provider (cloud relay or local).20- User has an `ac_` key and wants Loki routed through their Actual cluster.21- User wants fully-local, on-device inference via the Actual daemon.22- Troubleshooting: Actual requests failing with cryptic 400s or empty streams.2324## Prerequisites2526- Loki has **first-class `actual` provider support** (provider id `actual`,27 aliases `actual-computer`, `actualcomputer`, `aci`). Do NOT configure Actual28 as a `custom_providers` / `providers.actual.*` entry on current Loki — the29 built-in provider owns the name and handles base-url normalization, the30 Responses transport, and local no-auth automatically.31- Relay mode: an Actual account and an `ac_` inference key from32 https://actual.inc/user/keys.33- Local mode: the user has installed the daemon34 (`curl -fsSL "https://actual.inc/install" | bash`) and completed device35 authorization by running `actual` once and opening the printed36 `https://actual.inc/device?code=...` URL in a browser. Relay that URL to the37 user and WAIT — never invent an email or authorize on their behalf. Codes38 expire in 5 minutes; re-run `actual` for a fresh one.3940## How to Run4142### Relay / API mode43441. Put the key in `.env` (secrets only — never config.yaml):45 append `ACTUAL_API_KEY=ac_...` to `~/.loki/.env`.462. Verify the key and discover models with `terminal`:47 ```bash48 curl -s https://api.actual.inc/v1/models -H "Authorization: Bearer $ACTUAL_API_KEY"49 ```503. Select provider + model:51 ```bash52 loki config set model.provider actual53 loki config set model.default "MODEL_ID_FROM_DISCOVERY"54 ```554. Verify end-to-end:56 ```bash57 loki chat -Q -q "Reply with exactly: ACTUAL_OK" --provider actual -m MODEL_ID58 ```5960### Local mode61621. Human has installed + authorized the daemon (see Prerequisites).632. Download and load a model (scriptable once authorized):64 ```bash65 actual models search "qwen2.5 0.5b instruct gguf" --limit 8 --no-prompt66 # Downloads REQUIRE an explicit quantization (409 ambiguous_model_download otherwise):67 actual models download "Qwen/Qwen2.5-0.5B-Instruct-GGUF/Q4_K_M"68 actual models list # note the INSTALLED name (differs from download id)69 actual models load "qwen2.5-0.5b-instruct-q4_k_m" # load by installed name70 ```713. Point Loki at the daemon. `ACTUAL_BASE_URL` with a loopback host flips the72 built-in provider into local no-auth mode automatically — no key needed:73 append `ACTUAL_BASE_URL=http://127.0.0.1:8080` to `~/.loki/.env`, then:74 ```bash75 loki config set model.provider actual76 loki config set model.default "INSTALLED_MODEL_NAME"77 ```784. Verify (reduced toolset — see context-window pitfall below):79 ```bash80 loki chat -Q -q "Reply with exactly: LOCAL_OK" --provider actual -m INSTALLED_NAME -t file,web81 ```8283## Quick Reference8485| Thing | Value |86|---|---|87| Hosted relay | `https://api.actual.inc/v1` (normalized from bare host automatically) |88| Local daemon | `http://127.0.0.1:8080/v1` (no auth on loopback) |89| Key env var | `ACTUAL_API_KEY` (`ac_...`) |90| Base URL env var | `ACTUAL_BASE_URL` (loopback host ⇒ local no-auth mode) |91| Provider id / aliases | `actual` / `actual-computer`, `actualcomputer`, `aci` |92| Transport | Responses API (`codex_responses`) — built-in, do not override |93| Cluster pinning | `X-Cluster-ID` header via `providers.actual.extra_headers` in config.yaml |94| Model size guide | 0.5B Q4_K_M ~470MB (toy), 7-8B Q4_K_M ~4.5GB (daily driver), 32B ~20GB |9596## Pitfalls97981. **reasoning_effort trap (handled by Loki since the first-class provider).**99 Actual's SGLang/vLLM backends accept only `none/low/medium/high/max`;100 `xhigh`/`ultra` used to fail with a cryptic101 `Expecting value: line 1 column 1 (char 0)` (a wrapped HTTP 400). The102 built-in provider clamps `xhigh→high` and `ultra→max` on the wire. If a103 request still 400s this way on an old Loki, set a per-model cap:104 `agent.reasoning_overrides.<model>: high` in config.yaml.1052. **Context-window overflow on small local models.** Loki' default toolset106 is ~26k tokens of schemas plus a ~9k-token system prompt. A model loaded107 with a 32k context overflows before the first turn, and llama.cpp-family108 servers emit a bare `data: [DONE]` — Loki reports109 `Provider returned an empty stream with no finish_reason`. This is NOT an110 SSE bug. Fixes: restrict tools (`-t file,web`), load the model with a111 larger `n_ctx`, or pick a >=64k-context model for the full toolset.112 Upstream tracking: #51448 (do not file new issues; add evidence there).113 Related but distinct: #65631 (HTTP-200 SSE carrying a 400), #56516114 (reasoning-only streams).1153. **Download ids vs installed names.** `actual models download` takes116 `repo/QUANT` and 409s without an explicit quantization;117 `actual models load` takes the INSTALLED name from `actual models list`.1184. **Reasoning models returning empty content.** GLM/Qwen reasoning variants119 emit thinking in a separate `reasoning` field and can burn a small120 `max_tokens` entirely on reasoning. Give generous max_tokens before121 assuming failure.1225. **Do not create a custom provider named `actual`.** Older setup guides123 (pre first-class support) wrote `providers.actual.*` config blocks. On124 current Loki the built-in provider wins the name; stale custom blocks125 are ignored or conflict. Remove them and use the env vars + model.provider126 flow above.127128## Verification129130```bash131# Relay:132loki chat -Q -q "Reply with exactly: ACTUAL_OK" --provider actual -m MODEL133# Local (small model — reduced toolset):134loki chat -Q -q "Reply with exactly: LOCAL_OK" --provider actual -m MODEL -t file,web135# Provider status (local no-auth shows key_source=local-offline):136loki status137```138139For other OpenAI-compatible clients (e.g. OpenCode), see140`references/opencode.md`.