Releases: askalf/agent
v3.4.3
Documentation
--helpnow lists everyconnectflag. The built-in help and the README options table were missing--install,--insecure, and the Cloudflare Access service-token flags (--cf-access-id/--cf-access-secret) added in 3.4.0–3.4.1 — they worked but were undiscoverable. Added them, plus an example for connecting through Cloudflare Access.- README documents the security layer. Added a Security section covering the default dangerous-command blocklist, output sanitization, the
~/.askalf/audit.logaudit trail, and the optional~/.askalf/policy.json(requireApproval,trustedAgents,blockedPatterns,allowedPaths) — shipped in 3.4.0 but never documented in the README. Corrected the "5-minute subprocess timeout" line (shell tasks are capped at 5 min, Claude Code tasks at 10).
v3.4.2
Fixed
--urlis now required instead of defaulting towss://askalf.org. askalf is self-hosted — every deployment runs its own forge — so there is no valid universal default. The old default pointed at the marketing site (not a forge), so aconnect <key>without--urlsilently dialed the wrong host and failed with an opaque WebSocket error.connectnow exits with a clear "Missing --url" message (and an example) when no URL is given. The--from-configpath used by the installed service is unaffected (it reads the saved URL). Help text, usage strings, and README updated to match.
v3.4.1
Added
- Cloudflare Access service-token support. When the bridge URL sits behind a Cloudflare Access application (e.g. a self-hosted forge exposed via
cloudflared), the WebSocket upgrade is 302-redirected to the SSO login at the edge unless the request carries a valid service token — so a remote agent could never connect, only same-host agents reaching the bridge over loopback. The agent now sendsCF-Access-Client-Id/CF-Access-Client-Secretheaders (alongside the bridge bearer auth) when configured via--cf-access-id/--cf-access-secretflags or theCF_ACCESS_CLIENT_ID/CF_ACCESS_CLIENT_SECRETenvironment variables. The secret is persisted toagent.jsonencrypted at rest like the API key (the id is not sensitive);connect --from-config(used by the installed service) restores both, so the autostart service needs no environment wiring. Keeps the Access application fully gated — no per-path bypass required.
v3.4.0
Security
- Approval gate and audit logging are now wired into the execution path.
requestApproval()andlogAudit()existed in the security module but were never called byhandleTask, sorequireApproval/trustedAgentspolicy had no effect and no audit log was ever written despite the documented promise. Every dispatched task is now screened, optionally gated on approval, and recorded to~/.askalf/audit.log(input field encrypted, chmod 600) with ablocked/denied/success/failedresult. - Refuse to send the API key over unencrypted
ws://to a non-loopback host. The bearer token (and every task payload) previously travelled in cleartext over plaintext WebSocket connections. The agent now rejects such connections unless you explicitly pass--insecure(persisted to config for service installs) for a trusted private network. Loopback is exempt.wss://remains the default. - Fix command injection in Claude-mode execution on Windows.
runClaudespawned withshell:trueand a raw args array, so Node concatenated arguments without quoting and a task prompt containing shell metacharacters (& | < > ^ …) could break out into a second command. It now routes throughcmd.exewith full two-layer (cmd.exe+CommandLineToArgvW) argument escaping andwindowsVerbatimArguments. - Validate server-pushed OAuth credentials before writing.
task.credentialsis now required to be a well-formed JSON object before it overwrites~/.claude/.credentials.json, so a malformed payload can no longer brick the device's localclaudelogin. - Hardened the
allowedPathsboundary check. The previousstartsWithtest let/srv/data-evilpass for an allowed/srv/data(no separator boundary) and let../-traversal escape entirely (paths were never normalized). Candidate paths are now normalized (collapsing./..) and matched on a real path boundary before being permitted. - Removed a stale, insecure duplicate
bridge.tsat the repository root — a pre-security-layer copy lacking input validation and the model allowlist.src/bridge.tsis the only bridge. SECURITY.mdcorrected to describe the actual execution model (tasks run with the agent user's full privileges; there is no OS sandbox) instead of overstating isolation, and to document the approval gate, audit log, and transport guard.
v3.3.1
Changed
- README rewritten — honest, building-in-public voice; drops the legacy "thinks/heals/remembers/evolves" + "nervous system / immune system" marketing copy. Fixes two factual errors (subprocess timeout is 5 min not 10; reconnect uses backoff). Ships to npm with this release.
package.jsondescription refreshed to match — plain description of what the connector does, no version-coupled marketing.
No runtime behavior change.
v3.3.0 — fix #15 (stable encryption keyfile)
Closes #15. After upgrade, every askalf-agent device becomes restart-safe — systemctl restart, host reboots, Docker churn, VPN reconnects, Wi-Fi MAC randomization all stop corrupting the on-disk apiKey.
Fixed
- agent.json apiKey unreadable after restart on hosts with churning network interfaces (#15). The pre-3.3 config-encryption key was derived from a hash that included every currently-up non-loopback interface's MAC address, so any Docker container start/stop, VPN connect/disconnect, or Wi-Fi MAC-randomization event silently changed the key. The agent then wrote a blob it could never decrypt again, and
loadConfigreturned the still-encrypted ciphertext as the Bearer token, producing AUTH_FAILED with no useful diagnostic.
Changed
- Config-at-rest encryption now uses a stable random 32-byte keyfile at
~/.askalf/keyfile(chmod 600), generated once on first need. Survives every restart, container churn, and network reconfiguration. loadConfigdistinguishes "valid encrypted blob, wrong key" from "legacy plaintext format". Pre-3.3 a single catch-all swallowed both cases as "return as plaintext" — that was the silent-corruption mode. Wrong-key failures now surface a clear re-pair error pointing at #15.- On first run after upgrade, the legacy machine-derived key is tried as a one-shot migration. If it decrypts successfully (your network state happens to still match what it was at write time), the config is transparently re-saved under the stable keyfile and you never see this again. If both keys fail, you get the re-pair message instead of silent failure.
Upgrade path
npm i -g @askalf/agent@3.3.0If the legacy key still works on your host, the upgrade is transparent — you'll see a one-line [agent] migrated agent.json from legacy machine-key encryption to stable keyfile notice and nothing else. If it doesn't, you'll see a clear re-pair error pointing at the recipe in #15 — one INSERT + one file write, ~30 seconds per device.
Either way, future restarts won't need this dance again.
v3.2.1 — fix WS subprotocol crash
Patch release
Single substantive fix on top of v3.2.0:
- #14 — drop apiKey from WS subprotocol per RFC 6455 / ws@8.20.0 strict validation. Fixes the reconnect crash that hit fleet devices on agent restart against forge >=3.1.
Tracking
Issue #15 documents a separate bug — per-process apiKey re-encryption corrupting agent.json on shutdown. Recovery recipe in the issue. Larger fix coming in a future release.
Install
```
npm install -g @askalf/agent@3.2.1
```
v3.2.0 — model-in-dispatch
What's new
The dispatcher can now control which Claude model runs on each device by including a model field in the task payload. When present, the agent invokes claude with --model <value>; otherwise it falls back to the device's local default (existing behavior, fully backward compatible).
This closes a real cost cliff: previously claude defaulted to whatever the device's local CC was configured to. One device defaulting to Opus caused 7-10x cost concentration on routine healthchecks compared to identical work on Haiku-default devices. With this version, the platform controls the model regardless of local defaults.
Compatibility
- Old platform releases that don't send
model→ behavior unchanged - Malformed model strings rejected before reaching the CLI (no arg injection)
v3.1.6 — fix Claude prompt invocation (API-key auth path)
Fixes PR #11: agent now passes the Claude prompt as a positional arg instead of stdin, so installs that route Anthropic calls through an upstream gateway via ANTHROPIC_API_KEY work end-to-end (previously "Not logged in · Please run /login").