Linux from zero
For a Linux machine that has never had KernelHub. Every step can be copied, and every step says what success looks like: install Node, install KernelHub with one line, log in a Runtime, pair your phone, send a real task, watch it deliver.
Work from top to bottom, one step at a time. Every step tells you which line to copy, what success looks like, and what to do if you don't see it. Each command block has a Copy button: click it, paste into your terminal (or SSH window), press Enter. With internet access you only need sections 1 and 2. Blocked network: section 5.
1 · Before you start: what this Linux machine is missing
You have a Linux machine that has never had KernelHub on it (x86-64 or arm64; desktop, server or VM), and you want to get to "send work from my phone, have this machine do it". First, what it ships with and what it lacks:
| Thing | On a fresh system? | Notes |
|---|---|---|
| bash / tar / sha256sum | Yes | Commands on this page are written for bash; sha256sum comes with coreutils. |
| curl | Not always | Many minimal systems and container images don't have it. Section 2, step 1 checks first. |
| Node.js / npm | No | The single most important row on this page. The installer does not install Node for you. Without npm it cannot install an AI coding tool (a Runtime), and you end up with "KernelHub is installed, but it cannot run a single task". Distro nodejs packages are often old, so this page uses the official nodejs.org build. |
~/.local/bin on PATH | Not always | KernelHub and the Node from this page both live there. Section 2, step 3 makes sure it's on PATH with one line. |
| A logged-in Runtime | No | KernelHub ships no model. It drives a CLI coding agent that you installed and logged into yourself (Claude Code by default). Installed is not usable: until you log in, tasks still cannot run. |
| A phone | — | With the KernelHub app installed, for scanning the pairing code, sending tasks and approving. |
- Install Node first, then KernelHub. The other way round, you end up unable to work (it is recoverable: once Node is in, run the install command again).
- Log the Runtime in once after installing (type
claudeand follow the prompts). Otherwise every task comes back with "no runtime here can run it". - After pairing, keep
icloser runopen (or install it as a background service). Pairing only introduces your phone to this machine; the thing that actually picks up work isicloser run.
The grey boxes are verbatim from a real run: a freshly started container from the official Ubuntu 24.04 image plus systemd (Ubuntu 24.04.4 LTS, aarch64), with only sudo and a normal user added — no curl, no Node. x86-64 (amd64) was not run.
Apart from installing curl and enabling lingering, no step on this page needs sudo. If you are already root (your prompt ends in #), just drop the sudo in front of those commands.
2 · With internet access: the shortest path (15 steps)
One line per step, copy and run.
Step 1 · Make sure curl is there
Success: curl prints its version — go on to step 2. On a fresh minimal system you may see (no curl):
bash: curl: command not found
Install curl on Ubuntu / Debian:
Install curl on Fedora / RHEL / CentOS Stream:
Step 2 · Check whether Node is there
Node already installed: it prints a version — skip to step 3; steps 4 and 5 can be skipped. On a fresh system you will see (Node is missing; carry on):
bash: node: command not found
Step 3 · Put ~/.local/bin on your PATH
This line does three things: appends one line to ~/.bashrc if it isn't there yet, applies it to the current window straight away, and prints the first PATH entry so you can see it. Running it twice doesn't add it twice. (If you use zsh, change both ~/.bashrc to ~/.zshrc.)
Success: it prints /home/your-name/.local/bin (for root, /root/.local/bin):
/home/kh/.local/bin
Step 4 · Download Node.js and check it against the official checksum
The current LTS is Node v24.21.0. This line downloads the official nodejs.org .tar.gz for your CPU (x86-64 / arm64), then checks it against the official SHASUMS256.txt:
Success: the last line is the file name followed by OK:
node-v24.21.0-linux-arm64.tar.gz: OK
Ends in FAILED: the download is broken — run the line again. Errors like curl: (6) / (7) / (28) / (35): a network problem; retry, and if it keeps failing set a proxy (section 5).
sha256sum: WARNING: 1 computed checksum did NOT match node-v24.21.0-linux-arm64.tar.gz: FAILED
Step 5 · Unpack Node into ~/.local (no sudo)
Success: two version lines, one for node and one for npm:
v24.21.0 11.19.0
Why this way: node, npm, and later icloser and claude all end up in ~/.local/bin, and npm's global installs land in ~/.local too — no sudo, no EACCES errors. The official build is for glibc systems (Ubuntu, Debian, Fedora and the like); on musl systems such as Alpine, use the distro's own nodejs package and see section 4.
Step 6 · Install KernelHub with one line
It does these things in order — you don't have to do anything, just watch:
| What it does | Details |
|---|---|
| Identifies the machine | Detects Linux and the CPU (amd64 / arm64). |
| Reads the release manifest | Fetches stable.json from kernelhub.icloser.xyz; refuses to install unless it says READY, with no override. |
| Downloads and verifies | Downloads icloser, checks SHA-256 and size, discards it and stops on mismatch; if the machine has neither shasum nor sha256sum, it refuses to install. |
| Where it goes | ~/.local/bin/icloser, plus three legacy names icli / kernelhub-cli / devnexus-cli. |
| Local console | Also installs ~/.local/bin/kernelhub-desktop; if that download fails it prints one warning and the CLI install still stands. |
| Self-check | Runs icloser version on the spot and compares it with the manifest's version and build. |
| One Runtime | If npm is there: npm install -g @anthropic-ai/claude-code (only claude, by default). If it's already installed, it's left alone. |
On success you'll see (the installer's messages are in Chinese):
清单:stable 频道 · v1.0.2 · build 202609161352 · commit a4099c062543
下载 icloser_linux_arm64 …
✓ SHA-256 核对通过
✓ 装到 /home/kh/.local/bin/icloser
✓ 装到 /home/kh/.local/bin/kernelhub-desktop(本机管理台)
✓ icloser 1.0.2 (build 202609161352, commit a4099c062543)
装 Runtime:claude(npm install -g @anthropic-ai/claude-code)…
✓ 装好 Runtime:claude(@anthropic-ai/claude-code)
下一步:
① 登录 Runtime(只用一次)。装上但没登录,任务照样跑不了:
claude
按提示登录完,退出它即可。
② cd 到你的项目目录,跑:
icloser pairIf it contains "这台机器上没有 npm,Runtime 没装" (no npm on this machine, no Runtime installed), steps 4–5 were skipped or didn't take. KernelHub itself is installed; go back, install Node, then run this line again:
清单:stable 频道 · v1.0.2 · build 202609161352 · commit a4099c062543
下载 icloser_linux_arm64 …
✓ SHA-256 核对通过
✓ 装到 /home/kh/.local/bin/icloser
⚠️ 管理台没下下来(kernelhub-desktop_linux_arm64)—— 只装了 CLI
✓ icloser 1.0.2 (build 202609161352, commit a4099c062543)
⚠️ 这台机器上没有 npm,Runtime 没装(KernelHub 本体已经装好)
装好 Node.js(自带 npm)之后重跑一次这个安装器即可。If it says "管理台没下下来 —— 只装了 CLI" (console didn't download, CLI only): usually a network hiccup — just run the line again.
Step 7 · Check which version you got
Success: one line containing both 1.0.2 and 202609161352:
icloser 1.0.2 (build 202609161352, commit a4099c062543)
icloser: command not found: step 3 wasn't done; do it and retry.
Step 8 · Log the Runtime in once
First, see what it looks like before logging in. The first output is long (a matrix plus dozens of lines of notes) — only look at the Claude Code row at the top: before login it says 状态不明 (STARTABLE_AUTH_UNKNOWN), after login ✅ 可用 (AUTHENTICATED).
这台机器上的 Runtime(14 家已注册 · 1 家装着 · 0 家可直接用 · 0 家卡在登录/凭据)
Runtime 版本 状态 登录态 / 位置
⚠️ Claude Code 2.1.272 状态不明 声明了探测手段但一条都没命中,状态问不出来(不猜)
Claude Code STARTABLE_AUTH_UNKNOWN 起得来,但登录态问不出来:声明了探测手段但一条都没命中,状态问不出来(不猜)Then log in. The first run walks you through it; follow the prompts on screen (on a server with no browser, finish the login on your own computer the way it tells you). When done, type /exit or press Ctrl + C twice to leave:
The screens the first claude run shows (Linux run, the gist of each screen):
- Welcome to Claude Code v2.1.272 / Choose the text style — press Enter (Dark mode is the default).
- Select login method — press Enter (1. Claude account with subscription).
- Browser didn't open? Use the url below to sign in — open that link in a browser, sign in, paste the code the page gives you back here, press Enter.
- Login successful. Press Enter to continue… — press Enter.
- Security notes … Press Enter to continue… — press Enter.
- Accessing workspace … ❯ No, exit / Yes, I trust this folder — press Enter (No, exit: you only came to log in).
Run icloser runtimes again. Success: the Claude Code row is ready to use:
这台机器上的 Runtime(14 家已注册 · 1 家装着 · 1 家可直接用 · 0 家卡在登录/凭据)
Runtime 版本 状态 登录态 / 位置
✅ Claude Code 2.1.272 可用 /home/kh/.local/bin/claude
Claude Code AUTHENTICATED 起得来、凭据也在(配置文件 /home/kh/.claude.json 里有顶层键 oauthAccount(只看键是否存在,不读值))。 …Still stuck on login (the state reads STARTABLE_NOT_AUTHED or "unknown" (STARTABLE_AUTH_UNKNOWN)): type claude and log in again.
Step 9 · Create a project folder and go into it
If you already have a project, use its path instead:
If the project uses git, make sure git is installed (sudo apt-get install -y git on Ubuntu / Debian, sudo dnf install -y git on Fedora).
Step 10 · Pair your phone
It does three things in turn:
- Creates a workspace in the current folder.
- Asks how far the agent may go on this machine — just press Enter for tier 3, read + write + execute: it can change files and run builds and tests. Most people pick this.
- Draws a QR code in the terminal, with a "paste this if you can't scan" link below it.
The Linux run did not keep this screen separately; in the Mac run the permission question is a 6-tier menu where Enter = 3 — see step 10 of Mac from zero.
Scan the code with the KernelHub app on your phone. If your SSH window is too narrow to draw the whole code, widen it and use the line below to redraw it.
Step 11 · Enter an invitation code in the phone app
The first time a brand-new account runs pair, the window shows this (verbatim from the Mac run; Linux uses the same CLI):
账户 7a9e5014 还没有使用权 —— 在 iPhone 或 Android 上输入一次邀请码即可, 这台机器会自动继承(CLI 上没有激活入口)
It says, in Chinese: this account has no access yet — enter an invitation code once on iPhone or Android and this machine inherits it; the CLI has no activation entry. Open the KernelHub app on your phone and enter your invitation code there. Once it is redeemed, this computer inherits it automatically; nothing to type here.
- One code is 30 days.
- Codes add up: measured, redeeming a second code with 29 days left brought it to 59 days.
- The same code cannot be redeemed twice: the second try is refused (
invite_exhausted).
How to get a code: Access & activation. An account that is already active says access was inherited during pair, and you skip this step.
Step 12 · Start taking work
Leave this window open. It keeps running and checks for new tasks every few seconds — it is what picks up the tasks you send from your phone. Its first lines say which workspace it joined and which Runtime it chose:
icloser · 设备 cli-fresh-ubuntu · 工作区 cc274549-d96e-44d8-a0a1-f89727078c5e Selected Runtime: claude · 适配器 claude-code(支持会话接续、只读可强制) 选择原因: eligible pool 里最佳可用:claude 工作目录 /home/kh/projects/my-app · 轮询 3s 等待命令中(Ctrl-C 退出)…
Step 13 · Send a real task and watch it deliver
With the step 12 window still open, pick up your phone:
- In the KernelHub app, choose the workspace you just paired and type one sentence into the box. Name the file if you know it, for example "Add a line with today's date at the end of README.md. Don't commit."
- The
icloser runwindow on your computer scrolls a few new lines — the task has been picked up. On the phone the task card turns into a live view: which files it read, which commands it ran, which files it changed. - If the task lacks a permission tier, it stops before acting and shows a card; approving applies to this task only.
- When it finishes, tap the card's changes to read the diff line by line, then read the result: what it did, what it changed, what it couldn't do. Not happy? Ask for changes, and the same task carries on.
Success: the task shows as done, the changes show the new line in README.md, and the file on your computer really has that extra line.
KernelHub checks the machine-level base tools (Go, Python) on the way. If one is missing and this machine has not been allowed to access the internet, the task carries on and no card is raised; the
icloser run window just logs one line (verbatim from the CLI source, in Chinese: the base tool is not installed, no card, not blocking, the task carries on; to fill it in run icloser env bootstrap go, or allow exec + web for this device):ⓘ go:KernelHub Base(机器级,与这条任务无关)没装上 —— 不挂卡、不阻塞,这条任务照常往下跑。要补齐:在这台机器上跑 icloser env bootstrap go,或在设备权限里批 exec + web 后它会自动补上。A card appears only when the task really needs it — the request names it (say, it mentions
go build) or the work actually runs it — and the install is refused; approving applies to this one task only. On a machine that already allows exec and internet access it installs the tool and carries on without any card (seen on a real Windows machine).This is what a delivered task looks like in the step 12 window (Linux transcript):
▶ 102f0802 新建 hello.txt,内容只写一行:hello from kernelhub。不要提交。
✓ 落盘核对通过(看了 2 个路径,没有越权改动)
ⓘ 改动 1 个文件(+0 −0)
ⓘ 已上传 1 份产物,手机上可以直接打开
✓ 完成(16s)
我在项目根目录新建了 `hello.txt`,写入前确认过这个文件不存在。里面只有一行:
```
hello from kernelhub
```The result of that task (seen from the CLI; the phone shows the same record):
新建 hello.txt,内容只写一行:hello from kernelhub。不要提交。 状态 done 机器 fresh-ubuntu 完成于 09-15 16:58 小结 我在项目根目录新建了 `hello.txt`,写入前确认过这个文件不存在。里面只有一行: ``` hello from kernelhub ``` 我没有提交,这个目录也不是 git 仓库。 改动 改了你的文件。看改了什么:icloser task diff 102f0802
Nobody picks it up: check that the step 12 window is still open; if it's still stuck, do the health check in the next step.
Step 14 · Health check (in a second terminal / SSH window)
✓ 工作目录 /home/kh/projects/my-app
? 常驻服务 Unknown(查不到服务状态)
✓ 网关连得上、令牌有效
✓ 读得到任务队列
任务 2 条,其中 0 条还没人接
执行体 fresh-ubuntu · 在轮询(0 秒前)
✓ 读得到本机权限
已生效:exec read write
✓ 读得到 AI 团队
本机 Runtime
✓ claude /home/kh/.local/bin/claude
都正常。This transcript is from the version before the fix: the background-service line used to be Unknown on Linux every time; from v1.0.2 it says whether it is installed and running.
It checks the service, gateway, queue, permissions and Runtimes in one go. Whatever is wrong, it tells you what to type next.
Step 15 · Keep working after you close the window or disconnect SSH: run it in the background
Once the step 12 window closes (or SSH drops), nobody picks up tasks from your phone. On a system with systemd, run this (it uses the project folder recorded at pairing, so it doesn't matter which folder you type it in):
✓ 已常驻 kernelhub-cli.service
执行体 /home/kh/.local/bin/icloser run
项目目录 /home/kh/projects/my-app
unit /home/kh/.config/systemd/user/kernelhub-cli.service
日志 /home/kh/.kernelhub/daemon.log
除非开启常驻会话:sudo loginctl enable-linger kh
想要开机即起、与登录无关:用 root 再跑一次 icloser daemon install
看状态:icloser daemon status(Excerpt: between the log line and the lingering line, the real output has one more ⚠️ line saying this is a user-level service because you are not root, and it will be stopped when you log out.)
- You're a normal user: it installs a user-level service, and systemd stops it as soon as you log out. To keep it running after logout, enable lingering (needs sudo, once per machine):
- You're root: it installs a system-level service that starts at boot, whether or not anyone logs in.
- It says there is no systemctl on this machine (common in containers and minimal systems): use the line below to keep it running in the background, logging to
~/icloser-run.log(type it again after a reboot):
Check on the background service any time:
✓ 正在跑 · pid 12860 日志 /home/kh/.kernelhub/daemon.log
See what it has been doing lately:
With the background service installed, you can close the manual icloser run from step 12 — running both is redundant.
3 · Local console (including servers with no desktop)
The console is a separate program; icloser run doesn't start it. Start it (this window stays busy too):
Open http://127.0.0.1:18092 in a browser on this machine. It listens only on the loopback address, so other machines can't reach it directly — on purpose.
No browser on the server? On your own computer, open an SSH tunnel (replace the user name and server address; leave that window open), then open http://127.0.0.1:18092 in your own computer's browser:
To see whether the console is running and at what address:
4 · Another way to get Node: your distro's package
You can also install nodejs and npm with your distro's package manager. Two things to know: the version is often old, and it installs into system folders, so afterwards npm install -g often fails with EACCES (permission denied) — including the step where the KernelHub installer installs claude for you.
Don't force it with sudo. Point npm's global folder at ~/.local instead (do section 2, step 3 first):
Success: it prints /home/your-name/.local. Then run step 6's install command again.
5 · Adding Runtimes, blocked networks
Add another Runtime (no need to rerun the whole install)
Only claude is installed by default. These can be installed with npm: claude, codex, qwen, codebuddy, opencode, kimi, mimo, pi. This line installs codex; swap in any of them:
Or pick it through the installer (again, swap codex for the one you want):
Each one needs its own login (type its name, for example codex). Google's entry is agy (Antigravity); it does not come from npm — install it from Google's official channel.
Set a proxy (for this window only)
Replace PORT with your own proxy's address and port; the last part checks it:
Success: it prints install -> HTTP 200. If not, the proxy is wrong — don't go further yet. Once it works, run section 2's commands in this same window.
Use an npm mirror
It echoes the mirror address. registry.npmmirror.com is a common public mirror; to use another one, swap the address.
Point KernelHub's downloads at a mirror / skip the Runtime
For company networks with an internal mirror (it must mirror the official folder exactly; SHA-256 is still checked; the installer script itself still comes from icloser.xyz):
Install no Runtime at all (CLI only):
6 · Verify the files yourself
Compare the output with the table below, using the rows for your CPU:
| File | Bytes | SHA-256 |
|---|---|---|
| icloser_linux_amd64 (x86-64) | 12,853,432 | d3475109eb22f704a2690a2295c289f6b5cd76ed164e19c90d6f4113cc754a68 |
| kernelhub-desktop_linux_amd64 | 8,220,856 | 6a6ebce22da317af3efd70d08d417ac41588ff0523ca1a935aae1b08ab4332ee |
| icloser_linux_arm64 (arm64) | 12,058,808 | f182497a8f536a9bda060d0cb7f46f227eace2ccf2506caf58bd963dd03c4bac |
| kernelhub-desktop_linux_arm64 | 7,798,968 | 78aacc8bdd4e0be4b8815dc5c93715a0cde0edf986829de21ae8dab2199bd258 |
| node-v24.21.0-linux-x64.tar.gz | — | 6e1db87ef58b8819e5d5402eff1536491b18edd8eb7bee5ef7897876e88dc5ff |
| node-v24.21.0-linux-arm64.tar.gz | — | 724282c3b43aec998aa9527380465b45d229e021b58035f5f4f63095eabfe5d5 |
The KernelHub rows match the release manifest stable.json exactly; the two Node rows come from nodejs.org's SHASUMS256.txt. The installer has already checked these for you — this is for anyone who wants to see it with their own eyes.
7 · Common errors: symptom → cause → the one line to run
| What you see | Cause | What to do |
|---|---|---|
curl: command not found | Minimal system without curl | Section 2, step 1: install curl |
node: command not found | Node not installed, or step 3 skipped | Section 2, steps 3–5 |
icloser: command not found | ~/.local/bin isn't on PATH | Section 2, step 3 |
| Installer says "这台机器上没有 npm,Runtime 没装" | KernelHub was installed before Node | Install Node, then run curl -fsSL https://icloser.xyz/install | sh again |
| Installer says "这台机器上没有 shasum 也没有 sha256sum" | coreutils missing | Install coreutils, then rerun the installer |
npm install -g fails with EACCES | Node is installed in system folders | Section 4: npm config set prefix ~/.local |
Node check says FAILED | Broken download | Rerun the step 4 line |
| Tasks come back with "no runtime here can run it" | Runtime not installed or not logged in | Type claude to log in, then check with icloser runtimes |
| Phone paired, but tasks just sit there | icloser run isn't open and no background service is installed | Run icloser run in the project folder, or icloser daemon install from step 15 |
| Once SSH drops or you log out, tasks stop being picked up | systemd stopped the user-level service | Enable lingering in step 15 (loginctl enable-linger) |
daemon install says there is no systemctl | Container or minimal system without systemd | Use the nohup line from step 15 |
| The QR code scrolled away | The window scrolled | Type icloser qr — don't pair again |
curl: (18) / (35) / (56), or "清单和服务器上的产物对不上了" (manifest and server disagree), or just a single curl: (35) … line and nothing else | The network dropped mid-download (seen several times in our runs; the artifacts were fine) | Run the same command again |
daemon install says Failed to connect to bus | This is not a normal login session (switched in with su, exec'd into a container), so user-level systemd is unreachable | Log in normally (desktop or SSH) and run it again; as a normal user, run sudo loginctl enable-linger "$USER" first |
8 · Uninstall / clean up completely
① If you installed the background service, remove it first:
② See exactly what would be deleted (list only):
③ Delete the data folders. The three hold configuration and the task ledger, identity credentials, and the protected root; it's only clean once all three are gone. You'll have to pair again afterwards:
④ Delete the programs:
The PATH line in ~/.bashrc can stay (Node lives in that folder too). Node and the Runtimes are yours: the Node from this page lives under ~/.local — if you don't want it, delete ~/.local/bin/node, ~/.local/bin/npm, ~/.local/bin/npx and ~/.local/lib/node_modules.