internkim

Running the host

Install the company host, check its services, and find local data and logs.

The company host runs on Debian 13, Ubuntu 22.04 or 24.04, Fedora, RHEL-compatible 10 (Rocky, AlmaLinux) or Arch Linux, on arm64 or amd64, or on a Mac with Apple silicon through Homebrew. The Linux packages need glibc 2.35 or newer. The host needs an outbound internet connection and must stay awake. The installer registers native services with systemd on Linux or launchd on macOS. It needs no public address, inbound port, or Docker installation.

Install

Download the connection file from the company setup page, then run:

curl -fsSL https://intern.kim/install.sh | sh -s -- host
sudo internkim install ~/Downloads/internkim-host.json

The first command installs the package through apt, dnf, pacman or Homebrew. On Linux it fetches the package for this machine from our GitHub Releases and checks it against the release's SHA256SUMS before the package manager installs it. On a Mac it adds our Homebrew tap, yeomyeonggeori/tap, and installs the internkim formula, whose bottle comes from the same GitHub Release and is checked against the checksum the formula carries. The second command configures the company, asks for the OpenRouter API key, and registers the host services. Without a terminal it reads the key from standard input, or from a private file named with --model-key-file. They start with the computer and recover after a service exits. Installation finishes once every service answers and the agent holds the company's roster, so a member can write to it right away. Then open the printed company setup address and choose Check connection.

On Linux the connection file is optional. After the first command alone, the computer waits for a company and shows an eight-character code at http://<computer>.local:18088/ on its own network; sudo internkim box code prints the same code. An administrator on that network enters it on the company setup page, checks the last four characters of the computer's key, and confirms. The setup page then asks for the OpenRouter key. Kim mini describes how the claim works and how Disconnect undoes it.

Updating

A host is updated by running the installer again, by asking the agent, or from Settings.

With the installer

Run the first command again. On Linux it installs the release the channel now points at over the version you have. On macOS Homebrew upgrades the formula and restarts the services on it, asking for your password to do so. The company and its data stay in place. The default channel is the latest stable release. On Linux, --channel testing follows the newest release, prereleases included, and --version installs one release by its tag, an older one included. A release is named MAJOR.MINOR.PATCH, such as v0.0.1. Releases made before it carry a date, such as v2026.10.01.203142, and still install by that tag:

curl -fsSL https://intern.kim/install.sh | sh -s -- host --channel testing
curl -fsSL https://intern.kim/install.sh | sh -s -- host --version v0.0.1

The installer records the channel it followed in /var/lib/internkim/release-channel. The tap carries only the latest release, so a Mac stays on the default channel and cannot be pinned to a version.

By asking the agent

Any member can ask which version the host runs and whether a newer stable release is out. An administrator can ask the agent to update the host, or to take it back to an earlier stable release. The agent does this only on a Linux host installed on the stable channel, and only after the administrator confirms a question that carries the release notes, what the restart costs, and when to run it: now, at 03:00 company time, or at a time the administrator named. Nothing updates on its own.

Once confirmed, the admin gateway, which runs as root, records who asked and in which conversation, then runs the installer with --version in a systemd unit of its own, internkim-host-update, which outlives the restart it causes. A second update is refused while one runs. When the agent is back it answers in that conversation with the version the host reached, or with what failed and the version the host is on.

From Settings

Settings shows every member the installed version, the channel, and the latest stable release with its notes. On the administrator tab, an administrator updates to that release or goes back to the previous one with a button. The click is the confirmation, so no question follows; a dialog says what the restart costs first. The call goes through the public API to the same admin gateway, which checks that the caller is an administrator and refuses a Mac or a host off the stable channel as above. The page then reads the host until it answers on the new version, and the gateway keeps the result for it, so nothing is posted to a conversation. The API starts the update at once, and only the agent schedules one for later.

What the restart costs

On a connected Linux host the update rewrites the settings the first install wrote, prepares the database again, restarts the services and returns once every one of them answers and the agent holds the roster again. The agent, the relay and the messenger are away for about a minute. A message sent in that window fails and has to be sent again. A task running at the restart is interrupted and resumed once when the agent is back; one that cannot be resumed is marked failed and its requester is told. A scheduled job due during the update runs once, late.

A company on several boxes takes a release one box at a time, standby boxes first. The service box names the release in the hosted service, each standby box takes it at its next check, and the service box installs it only once every standby seen in the last ten minutes runs it. A standby box could not take over from a snapshot made by a newer release, which is why they go first. If a standby has not taken it within twenty minutes, the update stops there, names the box, and the service box stays on its release.

A failed download or checksum installs nothing, and the host stays on its version. A release that installs but whose services do not come back is left installed and unconfigured, and the update names the silent service and how to read why. sudo internkim refresh runs the same steps again once that is fixed, and --version with the earlier tag goes back.

Remove

sudo apt remove internkim     # Debian, Ubuntu
sudo dnf remove internkim     # Fedora, RHEL-compatible
sudo pacman -R internkim      # Arch Linux

Removing the package stops and disables the host services and deletes the program files, the host's Python runtime and what it prepared for the skills. The install added no package source or signing key. The company stays on the computer: /var/lib/internkim holds its key on the hosted service and the seed that signs messages as each person, and /var/lib/internkim-postgres and /var/lib/internkim-cache hold the host's database and cache. Installing the package again brings the same company back. On Debian and Ubuntu, sudo apt purge internkim also deletes the settings in /etc/internkim.

Neither key can be issued again, so deleting the company is left to you. The last directory holds its backups:

sudo rm -rf /var/lib/internkim /var/lib/internkim-postgres /var/lib/internkim-cache /var/lib/internkim-backups

Check services

On Linux, systemd shows the host service state and logs:

systemctl list-units 'internkim*' 'blueclaw*' 'buzz*'
systemctl status internkim-relay
journalctl -u internkim-relay -n 50 --no-pager

The package creates an internkim-admin group whose members can start, stop and restart these services without sudo. The group opens nothing else on the computer. sudo usermod -aG internkim-admin <account> adds an account to it.

On macOS, run launchctl print system/kim.intern.<service> to inspect a service. Its logs are under /var/log/internkim/.

Settings

The installer writes company connection details and generated credentials to the protected host data directory. Most companies do not need to edit these files. Optional operator settings go in /etc/internkim/company-host.env. The generated host settings reference lists the supported variables and their defaults. Keep API keys and connection files out of the settings file.

Local data

The computer holds the agent's conversation history, task history, memory, workspace files, and messages waiting for delivery. These are separate from company records in the hosted service, which What lives where describes. A backup of the host holds everything on this computer that the hosted service does not.

Back up and restore

On Linux, one command writes the whole host to one archive and another brings it back:

sudo internkim backup
sudo internkim restore /var/lib/internkim-backups/internkim-backup-20261001T031500Z.tar

The services keep running while a backup is taken. Each database is dumped with pg_dump, which reads it as of one moment, and every SQLite database among the files is copied through SQLite's own snapshot. The archive holds:

The agent's databaseconversations, task history and the ledger
The messenger's databaseevery channel and message
/var/lib/internkimthe company's keys, the seed that signs messages as each person, the messenger's attachments
/workspaceevery person's and circle's files and memory, with their owners and modes
/var/lib/internkim-relaymessages and approval questions still waiting for the agent
/root/.internkimthe admin gateway's own databases and settings
/etc/internkimthe operator's settings

It leaves out what the host rebuilds: the cache, which lives in memory, the dependency caches under /workspace/shared/cache, each person's tmp, the Python runtime, the browser's profiles and the logs.

The daily backup

The package runs internkim backup --keep 7 once a day through internkim-backup.timer. A day the computer was off is caught up when it next starts. To keep another number of backups, set BACKUPS_KEPT in /etc/internkim/company-host.env. To turn the daily backup off:

sudo systemctl mask --now internkim-backup.timer

An upgrade leaves a masked timer off. sudo systemctl unmask internkim-backup.timer and then sudo systemctl enable --now internkim-backup.timer turn it back on. A backup made by hand prunes nothing unless it is given --keep, and pruning only ever removes archives named internkim-backup-<time>.tar.

Keep a copy elsewhere

On a box, a snapshot sealed to the company key is also kept in the hosted service every fifteen minutes, which the company's other boxes take over from. More than one box says how. On any other computer, an archive on the computer it protects does not survive that computer. It is also unencrypted: it holds the company's keys and its people's files, and the directory and every archive in it are readable by root alone. Encrypt it as it leaves the computer, to a key that does not live there. With age and a recipient whose private key the company keeps elsewhere:

sudo cat /var/lib/internkim-backups/internkim-backup-20261001T031500Z.tar \
  | age -r age1… > internkim-backup-20261001T031500Z.tar.age

The encrypted file can then go to any S3-compatible store with rclone copy or aws s3 cp. A key kept on the host would make the backup readable by anyone who had the host, and lost with it.

Restore onto another computer

Install the package on the new computer with the first command under Install, skip internkim install, and run internkim restore with the archive. The new computer takes over the old one's place on the hosted service, so turn the old one off first.

The restore checks every part of the archive against its recorded checksum before it changes anything. It refuses an archive made by a newer internkim, and one holding a database dump in an archive format newer than this computer's pg_restore reads. A dump from a newer PostgreSQL major in a format it reads is restored in one transaction, and fails whole if the schema uses something the older server lacks. It then stops the services, puts the files back, recreates each person's account from the roster in the archive, gives every file back to its owner by account name, restores both databases and starts the services, which bring their schemas up to the installed version. Like the install, it returns once the agent holds the roster. A file whose owner has no account on the new computer stays owned by root, and the restore lists it.

To restore onto the computer the backup came from, add --replace. The restore first backs up what the computer holds now, so --replace with that archive undoes it.

On a Mac the database is Homebrew's PostgreSQL, which internkim backup and internkim restore do not manage. They refuse there.

The archive format

This is a stable format. A tool that writes it is restored like a backup.

The archive is an uncompressed tar of five members, in any order:

MemberContents
databases/blueclaw.dumppg_dump --format custom of the agent's database. A restore gives objects owned by any other role to internkim
databases/buzz.dumpthe same, of the messenger's database. When it holds one community, that community is moved to the host's relay address, 127.0.0.1:3000
roster.jsonthe policy document the agent was running, whose people and circles become accounts
files.tarthe files, each entry named <root>/<path> with its owner and group recorded by name
manifest.jsonwhat the archive is and what it holds

The manifest:

Field
formatinternkim-host-backup
formatVersion1. A restore refuses a version newer than it reads
createdAtwhen the backup was taken, RFC 3339
packageVersionthe internkim package that wrote it, empty for a build without one
companyIDthe company whose host this is
postgresqlMajorthe PostgreSQL major the dumps were taken from
fileRootsthe roots files.tar holds
membersevery other member, each with name, size in bytes and sha256 in hex

A member the manifest does not list, or one whose size or checksum differs, makes the whole archive refused. A database dump may be absent, and that database then starts empty. roster.json may be absent, and a file whose owner has no account then stays owned by root. files.tar must hold the state root, with companies/<companyID>/connection.json and its secrets directory. Its entries are directories, regular files, symbolic links and hard links, and a restore resolves owners by name and never by number. The roots:

RootOn this computer
state/var/lib/internkim
relay/var/lib/internkim-relay
configuration/etc/internkim
administration/root/.internkim
workspace/workspace

The dumps are compressed by pg_dump and nothing else is. Most of what files.tar holds, pictures and documents, is compressed already.

Answer size

The relay replies with 413 and the byte count when an answer exceeds its transport limit. The default ceiling is 3,000,000 bytes; set ANSWER_BYTE_CEILING to change it. A non-positive value prevents startup. Profile-picture limits are derived from this ceiling because base64 encoding increases their size.

Network access

The host opens outbound connections and listens only on local interfaces. The exception is a Linux host that belongs to no company yet, which serves its pairing code on port 18088 until it is claimed. To administer the computer, use a shell on the same network or a remote access method your company controls.

On Linux, installing or upgrading the package also downloads the host's one Python runtime from github.com into /opt/internkim/python, the pinned libraries that read attached documents, and what each bundled skill's setup keeps beside the skill's files: Python libraries from pypi.org and files.pythonhosted.org, and the office skill's page renderer from registry.npmjs.org. If any of them is unreachable, the install stops and names what it could not fetch. The host needs no Python from the distribution. The skills run on the same runtime, as python3 in each person's commands, and install nothing the first time someone uses them.

On this page