MILAGPT
Start with “For business”: three steps to launch.
Book a reviewTelegram will open
RU·EN
Docs · Your own server

Your own server: isolation and install in a day

Putting Mila on your server or a client’s? One script prepares a clean Ubuntu or Debian box: a separate user with password login disabled, token and journal at 600, a service that receives messages. What it does not do — log in to Claude, write the bot token, open a port — is in its first lines. Every line below links to the code.

For anyone installing Mila for themselves or a client who wants to know what lives where.

What the script does

One run — the server is ready for Mila

deploy/bootstrap.sh runs as root on a clean server and leaves a separate user, the runtimes, the kit, a receiver service and closed files. The repository puts installing at a day: by evening messages arrive and nothing is lost on restart. REFERENCE.md:495-499

01 · USER

A separate one, no password

An account without root rights. Password login is disabled: it is reached by key or by root only. A key can be passed with --ssh-key.

bootstrap.sh:17-19 bootstrap.sh:73-83 bootstrap.sh:85-93
02 · SERVICE

Survives logout

User services keep running after the SSH session ends. The message receiver is a systemd unit with Restart=always.

bootstrap.sh:95-102 bootstrap.sh:195-204 deploy/README.md:47-48
03 · KIT

Runtimes and Mila’s kit

Bun, Node and Claude Code for this user, then the kit and its installer: skills, launcher, hooks.

bootstrap.sh:104-133 bootstrap.sh:135-160 deploy/README.md:45
04 · FOLDERS

Message folders at 0700

~/.claude/channels/telegram/ and its subfolders: only this user can enter them.

bootstrap.sh:162-167
Isolation

Token and journal — for her user only

The script sets the bot token, the journal of incoming messages and the access list to 600: only the file’s owner reads and writes them. bootstrap.sh:217-224 deploy/README.md:49

mila doctor checks this later too. It does not compare modes as numbers: 0444 is smaller than 0600, yet it lets everyone read the token. It looks for bits that should not be there and says which chmod to run. doctor.py:248-271

The installer puts the tool policy into the same folder, also at 600. install/install.sh:239-251

Closed to other users
Dry run

Every step is visible before it is taken

With --dry-run the script changes nothing and prints every step it would take. The README asks you to run it first and read it out loud to yourself. deploy/README.md:29-35 bootstrap.sh:40-43

A second run is safe: it skips what is already in place and says so. deploy/README.md:51 bootstrap.sh:4-6

It checks the system first: run as root, on Ubuntu or Debian. Anything else stops with the reason. bootstrap.sh:45-52

$ scp deploy/bootstrap.sh root@server:/tmp/
$ ssh root@server \
    'bash /tmp/bootstrap.sh --user mila --dry-run'
# read it, then the real run:
$ ssh root@server \
    'bash /tmp/bootstrap.sh --user mila'
Tool policy

rm -rf and DROP TABLE are refused without a card

The policy decides which of Mila’s commands run on their own, which are refused, and which wait for a human. Rules are read top to bottom, the first match wins; anything not listed is “ask”. permissions.example.json:2-4 permission_policy.ts:8-15

01 · DENY

Refused at once

Recursive delete, dropping a database or a table, mkfs, writing to a disk with dd, chmod -R 777 /. Nobody is woken: it is already decided.

permissions.example.json:9-26 permission_policy.ts:12-13
02 · ALLOW

Look and count

git status, ls, cat, grep and the like; reading, searching and editing files. Runs without a card and goes into the log.

permissions.example.json:27-32 permissions.example.json:44-68 permission_policy.ts:11
03 · ASK

A card with a deadline

Her own scripts, the rest of the shell, and writing to her own harness: hooks, settings, access.json, .env. The card waits 15 minutes; no answer means no.

permissions.example.json:33-43 permissions.example.json:69-74 permissions.example.json:5 permission_policy.ts:14-15 permission_policy.ts:50
04 · FAILURE

A broken file closes, not opens

A broken policy file turns everything into “ask”, never “allow”. More than 25 cards in a minute and the rest are refused automatically, so a loop cannot flood you.

permissions.example.json:2 permission_policy.ts:19-25 permissions.example.json:6-7
Three steps by hand

The account and the subscription stay yours

The script never logs anyone in to Claude Code, never writes a bot token and never opens a port to the world. It is on purpose: the account and the subscription are the client’s own, with their hands on the keyboard. Sharing a subscription breaks the provider’s terms and puts both accounts at risk. bootstrap.sh:11-15 deploy/README.md:11-23

At the end the script prints the three steps. mila doctor is the acceptance test: a server that has not passed it is not handed over. bootstrap.sh:226-247 deploy/README.md:77-79

Then pairing from the phone and policy allowlist: until then anyone who guesses the bot’s name gets a pairing code. deploy/README.md:81-89

1 su - mila; claude
  # log in with the client’s own account
2 /plugin install mila-telegram@mila
  /mila-telegram:configure <token>
3 systemctl --user enable --now \
    mila-telegram-receiver
  mila doctor
Honestly

What the script does not do for you

In the repository

Read every line yourself

Files behind the server setup in the mila repository
FileWhat it does
deploy/bootstrap.shthe server script: user, runtimes, kit, folders, service, permissions
deploy/README.mdthe whole path: dry run, three steps by hand, handing over
install/install.shthe kit installer: skills, hooks, tool policy
permissions.example.jsonexample policy: ask by default, deny and allow by name (notes in Russian)
permission_policy.tshow the policy is read: three outcomes, a broken file, the card cap
install/doctor.pymila doctor: the channel check and extra permission bits
docs/REFERENCE.mdinstalling is a day; what comes after
Open source · Apache-2.0

Fork it, teach it, send a PR

The kit is open: skills, hooks, tools and templates. Run bootstrap.sh --dry-run on your server: it changes nothing and shows every step.

Facts on this page: github.com/shakhruz/mila (main, 8a6b97d, v1.5.2), checked 25 Oct 2026. The lines in the phone are part of the script’s own output on a dry run. “Mila”, “MILAGPT” and the logo are trademarks of MILAGPT.