Skip to content

askalf/agent

@askalf/agent

connect any device to your askalf fleet

npm Node License CI

askalf.org · @ask_alf · Changelog


What this is

@askalf/agent is the device-side half of an askalf workforce — a self-hosted AI workforce platform, now in early access. You run it on a machine you want the fleet to be able to act on — a server, a laptop, a remote box — and it opens a persistent WebSocket to your askalf forge. From then on, agents in the fleet can run shell commands or Claude Code on that machine, see what's installed, and stream results back.

It's not a chat client, an MCP server, or an autonomous coder. It's a connector — the substrate side of "agents can do real things on real computers."


Install

npm install -g @askalf/agent

Requires Node 22+. For Claude Code execution, install @anthropic-ai/claude-code globally as well.

One-command setup

askalf-agent connect <api-key> --url ws://your-forge:3005 --name laptop --install

Writes config, registers with the forge, installs a system service that auto-starts. Close the terminal — the agent keeps running.


Commands

Command What it does
connect <key> Connect to a forge. Add --install to also register as a service.
disconnect Stop the running daemon.
status Show connection + service state.
scan List the device's discoverable capabilities (CPU, RAM, installed tools, Claude Code presence).
doctor Diagnose common setup issues and offer fixes.
daemon Run in foreground. Mostly useful for debugging — --install is the normal path.
install-service Install the service after a connect without --install.
uninstall-service Remove the service.

Options

Flag Description Default
--url <url> Forge WebSocket URL, e.g. wss://your-forge.example.com (or ws://localhost:3005 over a local tunnel) required — askalf is self-hosted, so there is no default
--name <name> Device display name in the dashboard system hostname
--install Install as a service after connecting
--insecure Allow unencrypted ws:// to a non-loopback host (trusted LANs only — loopback ws://localhost needs no flag)
--cf-access-id <id> Cloudflare Access service-token client ID, if the forge sits behind CF Access (or env CF_ACCESS_CLIENT_ID)
--cf-access-secret <secret> Cloudflare Access service-token client secret (or env CF_ACCESS_CLIENT_SECRET)
-v, --version Print version
-h, --help Print help

Connecting through Cloudflare Access

If your forge is published behind Cloudflare Access, the WebSocket upgrade gets intercepted by the SSO redirect. Mint a service token, authorize it on the forge's Access application, and pass it to the agent — it sends the CF-Access-Client-Id / CF-Access-Client-Secret headers on connect (the secret is encrypted at rest in the config):

askalf-agent connect <api-key> --url wss://forge.example.com \
  --cf-access-id <client-id> --cf-access-secret <client-secret> --install
# or via environment:
export CF_ACCESS_CLIENT_ID=<client-id> CF_ACCESS_CLIENT_SECRET=<client-secret>
askalf-agent connect <api-key> --url wss://forge.example.com --install

Service install

OS Backend Auto-start
Linux systemd unit on boot
macOS launchd plist on login
Windows Scheduled Task (or nssm if installed) on login

How it works

your device                          askalf forge
┌──────────────┐                  ┌──────────────────────┐
│ askalf-agent │ ──── wss ──────► │ dispatcher           │
│              │ ◄─── task ────── │ agent fleet          │
│  shell       │ ──── stream ───► │ dashboard / discord  │
│  Claude Code │ ──── result ───► │                      │
│  device tools│                  └──────────────────────┘
└──────────────┘
  • Heartbeat every 30s with memory and uptime.
  • Auto-reconnect with backoff after a disconnect.
  • Capability scan on registration and on demand — reports CPU, RAM, OS, and presence of git, docker, node, npm, python, gh, claude, and more.
  • Subprocess timeout — 5 minutes per shell command, 10 minutes per Claude Code task.
  • Streaming output — the dashboard sees what the task prints, line by line, while it's still running. A final result with token + cost numbers follows.
  • Security policy — every task is screened before it runs and every result is logged. See Security.

Security

The agent runs authorized tasks from your own forge, but it still screens every execution through a local security policy before anything runs. Out of the box, with no configuration:

  • Dangerous-command blocklist — inputs matching destructive patterns (rm -rf /, fork bombs, mkfs, DROP TABLE/TRUNCATE, curl … | sh, reading /etc/shadow or .ssh/id_*, format c:, diskpart, …) are blocked before execution and recorded as blocked.
  • Output sanitization — results are scrubbed for secrets before being streamed back to the forge.
  • Audit log — every task (success, failure, blocked, denied) is appended to ~/.askalf/audit.log (mode 0600) with timestamp, agent name, executor, and cost.

Optional, via a policy file at ~/.askalf/policy.json:

{
  "requireApproval": false,     // prompt on the controlling terminal before each task
                                // (headless daemons auto-deny after 60s when enabled)
  "trustedAgents": [],          // agent names that skip the approval prompt
  "blockedPatterns": [...],     // regex blocklist — REPLACES the built-in list when set, so
                                // copy the defaults in before adding your own
  "allowedPaths": [],           // restrict execution to these directories ([] = unrestricted)
  "sanitizeOutput": true,       // strip secrets from output
  "auditLog": true              // write ~/.askalf/audit.log
}

The agent connects over wss:// by default; plain ws:// is rejected for non-loopback hosts unless you pass --insecure (intended for trusted LANs).


Programmatic usage

import os from 'node:os';
import { AgentBridge, scanCapabilities } from '@askalf/agent';

const bridge = new AgentBridge({
  apiKey: process.env.ASKALF_AGENT_KEY!,
  url: 'wss://your-forge.example.com',
  deviceName: 'edge-laptop',
  hostname: os.hostname(),
  os: `${os.type()} ${os.release()}`,
  capabilities: scanCapabilities(),
});

await bridge.connect();

Most users want the CLI. This is for embedding the connector in something larger.


Known limitations

Building in public — real today:

  • systemd restart can corrupt the stored apiKey (Linux). A systemctl restart askalf-agent re-encrypts the config and, in some cases, leaves the apiKey unrecoverable. Until the upstream fix lands, recover with askalf-agent disconnect && askalf-agent connect <key> --install.
  • Per-user/machine key binding. Keys are bound to the user that ran connect on the machine that ran it. Switching Linux users on the same box means minting a new key, not reusing the old one.
  • Older ws versions reject base64-encoded API keys as subprotocols. If you embed AgentBridge in a project with an older ws, pin to ^8.20.0 or move the key to the Authorization header.

Requirements

  • Node 22+
  • @anthropic-ai/claude-code globally installed, if you want the fleet to run Claude Code tasks here
  • A reachable askalf forge (npx create-askalf)

Related projects

Project What it does
askalf platform The forge + dashboard the agent connects to — self-hosted AI workforce platform, now in early access.
@askalf/dario Local LLM router. Use your Claude Max subscription as an API.
@askalf/hands Computer-use agent. Your LLM on your mouse, keyboard, and screen.
@askalf/deepdive Deep-research SDK with citation tracking.

License

MIT — see LICENSE.



Built by Sprayberry Labs

This is one of the open-source building blocks from Sprayberry Labs — an independent studio (Atlanta, GA) that ships bespoke software and fixed-price code & security audits, delivered with the AI workforce these tools are part of.

Got a codebase that needs an expert read?Scan a repo — free mini-audit, or see the $1,500 fixed-price Audit and build Sprints. · sprayberrylabs.com · hello@sprayberrylabs.com

About

Connect any device to the askalf fleet. WebSocket bridge that dispatches autonomous agent tasks to your machine.

Topics

Resources

License

Code of conduct

Contributing

Security policy

Stars

Watchers

Forks

Packages

 
 
 

Contributors