Starting a Node
A "node" is a machine running zqagent: it has a local working directory, model configuration, and session data on that machine. It can be used locally only, or connected to the User Center for remote management and viewing.
This page explains how to start, keep running, and connect a node.
Three Run Forms
| Form | Startup method | Best for |
|---|---|---|
| Interactive CLI | zqagent | Chatting and working on the local machine; most commonly used |
| Long-running service node | zqagent serve | Running on a server/always-on machine for remote management |
| Desktop app | Install the desktop app | When you want a GUI; shares the same boot-start node with the long-running service |
The desktop app and the long-running service node are the same node service (same data directory and port), only the UI differs: installing the desktop app and then running install.sh will not create a second node. The interactive CLI uses independent data in the current directory, and the three can be combined as needed.
Interactive CLI
zqagentOnce in the interactive interface, enter natural-language tasks; configure the model with /connect (see Quick Start). For all commands, see CLI Usage.
The interactive CLI is a node that is "usable locally" but does not listen on a port and cannot be managed remotely. For remote management, see
zqagent servebelow.
Start a Long-running Node
zqagent serve starts the service headlessly, listens on an HTTP port, and runs in the background.
zqagent serveAfter startup, the logs print the listening address, data directory, node ID, and demo tenant information (on first startup, a demo tenant demo is created automatically; its apiKey is randomly generated and printed in the startup logs, and can be used directly for local debugging).
Options
| Option | Description | Default |
|---|---|---|
--port <n> | Listening port; if occupied, automatically switches to the next available port (the actual port is in the data directory server-port, and the logs also state it) | 8787 (or environment variable PORT) |
--host <addr> | Listening address; set to 0.0.0.0 to allow external access | 127.0.0.1 (or HOST) |
--data-dir <dir> | Data directory (projects, sessions, ledger, credentials) | ./.zqagent_data (or DATA_DIR) |
--hub <url> | User Center URL; use with --enroll-code to connect on startup | — |
--enroll-code <code> | One-time enrollment code | — |
--label <name> | Node display name | Hostname |
By default it listens only on
127.0.0.1, i.e. accessible only from the local machine, which is the safest. If LAN/public access is really needed, set--host 0.0.0.0and pay attention to firewall and access control.
Persistent Background Operation
Running in the foreground exits when the terminal closes; for long-term operation, install it as a system service (start on boot + automatic restart on crash).
Windows: There is no systemd / launchd. Use Task Scheduler to create a "Run at logon" task; set the program to the absolute path of zqagent.exe and the arguments to serve --port 8787 --data-dir "%APPDATA%\zqagent"; alternatively, put a shortcut to zqagent.exe serve ... in the Startup folder (Win+R → shell:startup). Stop/restart via Task Scheduler or Task Manager.
Recommended: one command (automatically downloads the latest single file, installs the service, and enables automatic updates; see Single-file Installation):
curl -fsSL https://agent.cd-zq.com/install.sh | sudo shAfter installation:
sudo sh -s -- status # 运行状态
sudo sh -s -- logs # 跟踪日志
sudo sh -s -- restart # 重启
sudo sh -s -- rollback # 回滚到上次自动更新前
sudo sh -s -- uninstall # 停止并移除(sudo sh -s -- <子命令> is equivalent to curl ... | sudo sh -s -- <子命令>; if the script has already been downloaded, you can also run sudo sh install.sh status directly.)
Install from repository source (on a development machine / when already installed with npm). macOS uses launchd; Linux uses systemd:
# 在仓库 deploy/service 目录下执行
bash install.sh install # 安装并启动(开机自启)
bash install.sh status # 运行状态
bash install.sh logs # 跟踪日志
bash install.sh restart # 重启
bash install.sh uninstall # 停止并移除Default data directories: macOS ~/Library/Application Support/zqagent, Linux ~/.zqagent_data; logs: macOS ~/Library/Logs/zqagent/node.log, Linux ~/.zqagent_data/node.log. (Early Linux versions used /var/lib/zqagent; for existing installations, the script follows the path in the original unit and does not migrate.) You can override with PORT / HOST / DATA_DIR / LOG / SERVICE_NAME, for example:
sudo PORT=9000 DATA_DIR=/data/zqagent bash install.sh installThe service starts with an "absolute-path node + CLI entry point" and does not depend on the PATH from nvm/volta; extra environment variables on Linux (LLM key, HUB_URL, SECRET_KEY, etc.) can be written to /etc/zqagent.env. Shutdown uses SIGTERM, and serve persists the ledger before exiting (default grace period 3s, adjustable with ZQAGENT_SHUTDOWN_GRACE_MS).
The script checks whether the current CLI supports
serve: older versions (such as 0.1.33) do not have this subcommand. Runnpm i -g @zqagent/core@latestfirst; otherwise the process silently enters an interactive session.
Hand-written systemd unit (when not using the script)
# /etc/systemd/system/zqagent.service
[Unit]
Description=zqagent node
After=network-online.target
[Service]
# 把 <用户名> 换成实际运行节点的用户;数据放在该用户家目录,权限天然归它所有
User=<用户名>
ExecStart=/usr/local/bin/zqagent serve --port 8787 --data-dir %h/.zqagent_data
Restart=always
RestartSec=3
KillSignal=SIGTERM
TimeoutStopSec=15
[Install]
WantedBy=multi-user.targetsudo systemctl daemon-reload
sudo systemctl enable --now zqagent
journalctl -u zqagent -f # 查看日志pm2 (alternative)
Note that you cannot put the entire command into a single string (it will be treated as a bash -c script, arguments will be lost, and it will fall back to an interactive session):
pm2 start "$(command -v zqagent)" --name zqagent -- serve --port 8787 --data-dir "$HOME/.zqagent_data"
pm2 save && pm2 startup # 开机自启nohup (temporary debugging)
nohup zqagent serve --port 8787 --data-dir "$HOME/.zqagent_data" \
> "$HOME/.zqagent_data/node.log" 2>&1 &Automatic Updates
After installing as a single file (SEA) and handing it over to a system service, the node keeps itself up to date. On a brand-new machine, it is recommended to use the one-line command from Single-file Installation, which installs both the binary and the service:
- Checks once 5 minutes after startup, then once every 6 hours (±15% jitter)
- If a new version exists, silently downloads it and verifies SHA-256, then runs a
--versionself-check - Waits until continuously idle for 60 seconds (no sessions executing and no sessions waiting for approval/answer) before replacing itself and exiting
- systemd / launchd brings up the new version, and the version is automatically updated in the console
Failures do not affect node operation: download/verification failures are only logged, and after 3 consecutive failures for the same version, it is skipped.
Prerequisites
Automatic updates take effect only when all three conditions are met at the same time (all are required):
- Single-file form (started from the SEA artifact, not
node dist/cli/index.js) - Managed by systemd / launchd (installed by
install.sh) - Signature verification public key
ZQAGENT_UPDATE_PUBKEYis configured
Nodes installed with npm are not automatically replaced; upgrade with
npm i -g @zqagent/core@latest.
macOS: Managed detection is the same as on Linux. It takes effect directly inside the service process; when manually running
zqagent update --status/--check/--nowin a terminal, it also automatically detects the managed state, public key, and channel through the launchd job (pid / program) andEnvironmentVariablesin the plist, without needing tosourceany environment variables first. To uninstall, usesudo sh -s -- uninstall.
Windows: There is no systemd / launchd, and single-file nodes are not automatically updated (
zqagent update --statuswill show "Service managed: unmanaged (foreground/nohup)"). To upgrade, stop theserveprocess, overwrite the old file with the newly downloaded exe, and restart; in an unmanaged environment,zqagent update --nowrefuses to execute directly.
The installation script fetches the public key by default, so one command completes installation + enables automatic updates:
curl -fsSL https://agent.cd-zq.com/install.sh | sudo shTo override the automatically fetched key with an out-of-band saved public key, add --pubkey "..." (an explicit public key takes precedence and will not be overwritten by online fetching).
Switches and Configuration
| Environment variable | Default | Description |
|---|---|---|
ZQAGENT_AUTO_UPDATE | 1 | Set to 0 to completely disable automatic updates |
ZQAGENT_UPDATE_PUBKEY | Automatically written during installation | Signature verification public key (PEM or base64 SPKI DER); if missing, no automatic installation is performed |
ZQAGENT_UPDATE_CHANNEL | stable | Manifest channel (stable / beta) |
ZQAGENT_UPDATE_URL | https://agent.cd-zq.com/downloads/zqagent/<channel>.json | Manifest URL; can be overridden on an intranet |
ZQAGENT_UPDATE_INTERVAL_MS | 21600000 (6h) | Check interval |
ZQAGENT_UPDATE_MIN_UPTIME_MS | 600000 (10min) | How long after startup before updates are allowed |
ZQAGENT_UPDATE_IDLE_MS | 60000 | How long it must be continuously idle before installation |
ZQAGENT_UPDATE_INSECURE | — | Set to 1 to allow an http manifest (intranet self-testing only) |
Check for Updates
zqagent update --check # 只查有没有新版(不下载,秒回)
zqagent update --status # 当前版本、通道、上次检查时间、暂存/失败原因Example output:
当前版本 v0.2.1
运行形态 单文件(SEA)
服务托管 systemd
更新通道 stable
清单地址 https://agent.cd-zq.com/downloads/zqagent/stable.json
自动更新 已启用--check prints "Already the latest version (vX)" or "New version vY found (current vX)".
Manual Intervention
zqagent update --now # 立即下载安装(跳过空闲等待,需重启服务)
zqagent update --rollback # 回到上次更新前的版本Service-side rollback (automatic restart):
sudo sh -s -- rollback # 单文件安装(从下载目录取脚本时用 sudo sh install.sh rollback)
sudo bash install.sh rollback # 仓库内安装After rollback, that version is skipped: automatic updates will not immediately install it again until a newer version is released; if you really need to force installation, use zqagent update --now.
Release Side
One command does it all: build the SEA single file → generate and sign the manifest → sync to the download directory. npm is not involved at all, and the node side does not need Node either (the binary bundles the runtime).
# 首次:生成签名密钥对(私钥只放发布机或 CI secret,公钥分发给节点)
node packages/core/scripts/gen_update_keys.mjs --out .update-keys
# 每次发版(参数全有默认值:版本取 packages/core/package.json,私钥取 .update-keys/update-private.pem)
bash scripts/release_node.shCommon options:
| Option | Default | Description |
|---|---|---|
--version X | Version in packages/core/package.json | Bare version number; the script verifies both match |
--key FILE | .update-keys/update-private.pem | Ed25519 private key used for manifest signing |
--pubkey-file FILE | update-public.b64 in the same directory as the private key | Node signature verification public key; verifies before release that it pairs with the private key, and syncs it to the download directory |
--host USER@HOST | Empty = local release | Omit when the release machine is the site server |
--dest DIR | /var/www/zqagent-downloads/zqagent | Directory that nginx /downloads/ actually points to |
--notes TEXT | 本次更新内容: 例行更新 | Written into the manifest and visible in client logs |
--skip-build | — | Reuse existing artifacts from packages/core/release/cli |
--dry-run | — | Only prints the commands to be executed |
Three typical usages:
# 1) 发布机就是站点服务器:直接写本机下载目录
bash scripts/release_node.sh --skip-build
# 2) 从别的机器发布:ssh + rsync 推到站点服务器
bash scripts/release_node.sh --host deploy@your-server --skip-build
# 3) 先看清楚会做什么
bash scripts/release_node.sh --dry-runCross-platform artifacts can only be built on the corresponding OS/architecture. For an all-platform release, build once in each CI matrix entry, then aggregate and publish with --skip-build --host ....
Directory structure after publishing:
/downloads/zqagent/
├── install.sh # 一键安装脚本
├── install-node.sh # 旧地址兼容副本(内容同 install.sh)
├── update-public.b64 # 验签公钥(安装时用 --pubkey 传入)
├── stable.json # 更新清单(节点读取)
├── stable.json.sig # 清单签名
├── stable.txt # 纯文本清单(安装脚本用)
└── v0.2.2/
└── zqagent-<platform>-<arch>The node downloads the binary only after signature verification passes, and then performs another check using the SHA-256 in the manifest. Self-check after publishing:
curl -s https://agent.cd-zq.com/downloads/zqagent/stable.txt
curl -s https://agent.cd-zq.com/downloads/zqagent/stable.json | head -20For the complete release and rollback process, see docs/release-runbook.md in the repository.
Connect to the User Center (Optional)
After connecting, you can view node online status, projects, and events in the User Center. There are two methods; choose either one:
- Hub account (recommended): directly use the email/phone number and password registered in the User Center;
- One-time enrollment code: log in to the User Center → create Node Management → generate an enrollment code (valid for 15 minutes).
Already Running Node: Hot Connect (No Restart)
# 账号方式:邮箱或手机号 + 密码
zqagent link --hub https://hub.cd-zq.com --username you@example.com --password '<密码>'
zqagent link --hub https://hub.cd-zq.com --username 13800000000 --password '<密码>'
# 手机号 + 短信验证码
zqagent link --hub https://hub.cd-zq.com --username 13800000000 --sms-code <验证码>
# 或一次性接入码
zqagent link --hub https://hub.cd-zq.com --code <接入码>Windows single file:
zqagent.exe link --hub https://hub.cd-zq.com --username you@example.com --password <密码>
zqagent.exe link --hub https://hub.cd-zq.com --code <接入码>When no credential arguments are provided, zqagent link enters an interactive wizard that asks in turn for the Hub URL, login method, and account/password (password input is hidden). The password can also be provided via the environment variable ZQAGENT_HUB_PASSWORD to avoid leaving it in command history.
The default data directory on Windows is %APPDATA%\zqagent; link automatically discovers it from runtime\service.json registered by the desktop app. You only need to add --data-dir when you manually configure a scheduled task and the data directory is not in the default location.
link first attempts to hot-connect to the local running serve. It traces back the process command line via /proc on Linux, ps on macOS, and PowerShell's Win32_Process on Windows, so it can be discovered even if serve uses a custom --data-dir / --port; if PowerShell is unavailable, it falls back to "write fleet.json, effective on next startup".
When multiple instances are found, link prefers the service managed by systemd / launchd (starts on boot and remains after restart), followed by a temporarily launched serve from the command line; .zqagent_data in the current directory is only used as a last resort, to prevent credentials from being intercepted by a temporary instance, causing the command to report success while the managed service remains offline.
Node Name
For nodes connected without --label, the hostname is used as the display name by default; what you see in the Hub is the machine name, not the nodeId. You can change it later in two places, and both modify the same record:
- Hub User Center → Node Management → Node "Rename";
- Execute on the node machine (takes effect live when a local service is running, no restart needed):
zqagent rename ten004-devIf the node has connected to the Hub, this command uses the node's own credentials to sync the Hub record, and it takes effect after refreshing the console; if not connected, it only writes the local configuration, which takes effect the next time serve starts.
When the service is not currently running, link also parses the plist / systemd unit to find its registered data directory and writes the credentials there (the service automatically connects on next startup). Therefore, whether the node was installed by the desktop app or by install.sh, users do not need to manually pass --data-dir.
Generally, you do not need to manually write --data-dir: the command above automatically discovers the local node. You only need to add it when prompted "No local node service found", and you must use a directory writable by the current user (the default for each platform's installation script):
| Platform | Default data directory |
|---|---|
| macOS | $HOME/Library/Application Support/zqagent |
| Linux | ~/.zqagent_data (owned by the current user; early versions used /var/lib/zqagent) |
| Windows | %APPDATA%\zqagent |
Do not copy
--data-dir /var/lib/zqagentfrom old tutorials: new installations default to~/.zqagent_data, and manually specifying a system directory will instead hitEACCES: permission denied. Just omit this option.
Connect on Startup
Include the Hub URL and account (or enrollment code) when running serve:
# 账号方式(适合 systemd / 容器等非交互环境)
zqagent serve --hub https://hub.cd-zq.com --username you@example.com --password '<密码>'
# 接入码方式
zqagent serve --hub https://hub.cd-zq.com --enroll-code <接入码>You can also use environment variables (suitable for containers / scripts):
HUB_URL=https://hub.cd-zq.com ZQAGENT_HUB_USERNAME=you@example.com \
ZQAGENT_HUB_PASSWORD='<密码>' zqagent serve
HUB_URL=https://hub.cd-zq.com HUB_ENROLL_CODE=<接入码> zqagent serveConnect from the Interactive CLI
Directly in the zqagent interface:
/link # 进入账号接入向导
/link <接入码> [Hub地址]Docker
docker run -d -p 8787:8787 -v zqagent-data:/data \
-e HUB_URL=https://hub.cd-zq.com -e HUB_ENROLL_CODE=<接入码> \
ghcr.io/<owner>/zqagent-serverCredentials and Network
- After a successful connection, credentials are written to
{DATA_DIR}/fleet.json; subsequent restarts do not require the account or enrollment code again; - The node only needs an outbound connection to the gateway (
wss://, usually over 443); no public inbound access and no open ports are required; - To rebind or unbind: operate from the node details page in the User Center, or delete
fleet.jsonand reconnect.
Data Directory
All long-term node data is in {DATA_DIR} (default ./.zqagent_data, following the project):
| Path | Content |
|---|---|
{DATA_DIR}/admin.json | Administrator key |
{DATA_DIR}/fleet.json | Connection credentials (0600) |
{DATA_DIR}/usage/ | Usage ledger, summaries, and price table |
| Sessions and projects | Saved by each project according to the working directory |
Model API keys are encrypted and stored separately in the user configuration directory (macOS / Linux
~/.config/zqagent/, Windows%APPDATA%\zqagent\), separate from the data directory.
Verify That the Node Is Online
- Open the User Center in a browser and go to the corresponding Node Management;
- The node appears in the node list with the status Online;
- Click the node to enter the Node Console, where you can view projects, sessions, usage, and events.
If the node is offline: confirm that the serve process is alive and that the machine can access the gateway address outbound (FLEET_GATEWAY_URL).
Next Steps
- Node Console: manage nodes, sessions, and usage through a GUI
- Remote Control Overview: assign tasks remotely from mobile and QQ
- Server Configuration: environment variables, cloud connection, and public network options
