Headless and Docker
Kitlig can run on a server with no screen, as an MCP server that agents drive from anywhere on your network. The same server also serves Kitlig Web, a page made for phones, so a team can send work to Kitlig from an agent and pick up the results without ever seeing the desktop app. Nothing here is needed for normal use on your own computer.
A Kitlig licence is required
The container is the same app as the desktop build and needs activating against your Kitlig account, like any other install. Generate a device pairing code on your account page at kitlig.com and set it as KITLIG_ACTIVATION_CODE before the first start. Unactivated, agents can still connect, but title cards don't render and tracking, mocap and shader jobs never finish. Each container counts as one device on the licence.
What you get
- An MCP endpoint at
http://<server>:8420/mcp. Open WebUI, Claude Code, Cursor, Claude Desktop (through itsmcp-remotebridge) and any other MCP client connect to it with the token you set. The agent then does everything the Settings page lists: projects, imports, generations, Describe & Tag, Create Video, timeline edits, exports. - Kitlig Web at
http://<server>:8420/. Open it on a phone, sign in with the password, and you see the projects, what an agent just made, and a button to send it files. Make something starts work from the phone with a few plain choices: make or change an image, make it sharper, remove a background, bring a photo to life or make a clip, cut a narrated documentary, commercial, UGC spot or story reel from your clips, read text aloud, describe and tag, or read the text in a picture. Each shows its price before you run it; Jobs shows progress and lets you stop or try again, and Do something on any picture or video opens the same list for that file. See Kitlig Web on your phone below.
Setting it up
- On a machine with Docker, get the
docker/folder from the Kitlig repository (Dockerfile,docker-compose.yml,.env.example). - Copy
.env.exampleto.envand fill it in:KITLIG_MCP_TOKEN: a long random string, for example fromopenssl rand -hex 32. Clients send it on every request.KITLIG_ACTIVATION_CODE: the device pairing code from your kitlig.com account (required, see above). It's redeemed on the first start and kept in the data folder, so it's only needed once; codes are single-use.KITLIG_WEB_PASSWORD: what people type into Kitlig Web. Leave it empty and the MCP token is the password; the token always works as well, so you can never lock yourself out.- The provider keys you use:
KITLIG_FAL_KEY,KITLIG_OPENROUTER_KEY,KITLIG_ELEVENLABS_KEY,KITLIG_GOOGLE_KEY,KITLIG_OPENAI_KEY,KITLIG_ANTHROPIC_KEY.
- Run
docker compose up -din that folder. The first start pulls the image (uaisoftwareinc/kitligon Docker Hub) and activates. - Point a client at
http://<server>:8420/mcpwith the headerAuthorization: Bearer <your token>. In Open WebUI that's Admin Panel › Settings › External Tools, type MCP (Streamable HTTP), auth Bearer. - Send
http://<server>:8420/and the web password to whoever needs to see the results.
Settings, activation and logs live under ./data next to the compose file. Projects live wherever KITLIG_PROJECTS_HOST_DIR points (default ./data/projects): set it to a big disk or a NAS share. Downloaded local models (Whisper, Florence-2, segmentation) go to KITLIG_MODELS_HOST_DIR (default ./data/models), which several deployments can share so each model downloads once.
Kitlig Web on your phone
Kitlig Web is a small web page served by Kitlig itself, made for someone who has never seen the desktop app. One thing per screen, big buttons, no settings.
- Point the phone's camera at the QR code the server shows (see Logging in with a QR code), or open
http://<server>:8420/in the phone's browser, type the address if asked, and sign in with the password. The phone stays signed in as long as it keeps being used (a login unused for 30 days expires). Add the page to the home screen (Share then Add to Home Screen on iPhone, the browser menu on Android) and it opens full screen like an app. - Projects lists every project Kitlig knows, with a cover and how many videos and images it holds. With a single project you land straight on it. Kitlig has one project open at a time, so tapping another one switches the whole server to it, the same as an agent calling
open_project. - Project home has big tiles: Recent (the newest files across the whole project, so the thing you just asked for is at the top), Videos, Images, Audio, Notes & text and Exports (finished cuts and packages). A Jobs pill shows how many jobs are running.
- Gallery is a grid of thumbnails. Chips filter All, Generated (made by Kitlig) and Source (added by a person); the last chip flips between Newest and By name. Videos show a play badge.
- Viewer shows one image or video full screen. Swipe left and right to move through the section, pinch to zoom an image, double-tap to zoom in and out. Save opens the phone's share sheet when it has one, so a video or photo can go straight to Photos; on other browsers it downloads. Describe shows the description and tags an agent wrote for the file, if any.
- Notes & text opens a note readable on the phone (Markdown is rendered). Notes written here, and other
.mdand.txtfiles, have Edit and Save. - Jobs lists what is running and what finished, live, with the result's thumbnail when it's done. A failed job shows its message in plain words.
- Add (the button at the bottom of a project or gallery) offers Photos & videos (the phone's picker or camera, several at once), Files (any image, video, audio or
.txt,.md,.srt,.jsonfile) and Write a note (a title and a text box). Files go into the project'simages/source,video/source,audio/sourceortext/sourcefolder as registered assets, exactly like an import on the desktop, so an agent can use them right away withlist_project_assetsandread_text_asset.
Note
Phones play H.264 and HEVC MP4s and most web formats. A ProRes master, an EXR sequence or a 3D model doesn't play in a browser: use Save and open it in another app. Meshes, splats and image sequences don't appear in the phone's sections at all.
Set KITLIG_WEB_READ_ONLY=1 in .env for a deployment where people should only collect files: Add disappears and uploads and notes are refused.
On a desktop install the same pages are a Settings switch: Settings › MCP Server › Phone companion turns them on, on the MCP port, with the access token as the password. Turn on Listen on network so phones on the Wi-Fi can reach it.
The phone app isn't tied to one server. Servers (the stacked icon on the Projects screen) lists every Kitlig the phone knows, with how many devices are connected to each; tap one to switch, Add server for another, Edit address to move between a server's local, Tailscale and public addresses (the login stays), Forget to drop it.
Logging in with a QR code
Nobody has to type an address or a password. The server shows a QR code, the phone's camera opens it, and the phone is signed in.
- Docker and other headless installs: the start-up log prints a QR code (
KITLIG_WEB_PRINT_PAIR_QR=1, the compose default). After that, openhttp://<server>:8420/pair?token=<your MCP token>in any browser for a fresh one. The page lets you pick how the phone will reach the server: Local network, Tailscale or your public hostname. - Desktop: Settings › MCP Server › Phone companion shows the QR code, the same choice of address, and Refresh. Give the server a name there; that's what the phone shows.
- From a phone that's already in: Servers › Add another phone shows a QR for the next person.
Each code works once and expires after five minutes. If the camera opens a page that says the code has expired or was already used, ask for a new one. The QR carries the other addresses the server answers on, so a phone that scanned a Wi-Fi code while on Tailscale still gets in.
Devices
Every phone or browser that signs in holds a device login, at most 10 per server. The count ("3 of 10 connected": seen in the last five minutes) shows on the desktop Settings page, on the phone's Servers screen, in the start-up log and on the /pair page, and an agent can read it from get_app_state. When the 11th tries, it's told to have someone remove a device first.
Servers › Devices on the phone, or the device list in the desktop Settings, shows each device with its name, how it signed in (QR or password) and when it was last seen, with Revoke to cut a lost phone off at once. Logins unused for 30 days expire on their own.
Reaching Kitlig from outside
Three ways, all offered where the QR code is shown:
- Local network. The default: the phone and the server on the same Wi-Fi.
- Tailscale. Install Tailscale on the server and on the phones; the server's Tailscale address (or its MagicDNS name) then works from anywhere, encrypted, with nothing opened on the router. The recommended way out of the building.
- Quick share. The no-setup way:
KITLIG_REMOTE_ACCESS=quick-share(desktop: Settings › MCP Server › Phone companion › Remote access › Quick share). Kitlig downloadscloudflaredonce and opens a Cloudflare quick tunnel with a randomtrycloudflare.comaddress, no account needed. The address changes each time it starts, so phones scan a fresh QR after a restart; good for light use, with no guarantees from Cloudflare. - Custom domain. A fixed public hostname in front of Kitlig, either your own Cloudflare tunnel (desktop: if
cloudflaredalready runs on the computer, add a route for Kitlig's port to that tunnel and enter the hostname; otherwise the tunnel token or a CLI-made tunnel's name; Docker: thetunnelcompose profile withCLOUDFLARE_TUNNEL_TOKEN,KITLIG_REMOTE_ACCESS=cloudflare-tunnelandKITLIG_WEB_PUBLIC_URL) or your own TLS reverse proxy (KITLIG_REMOTE_ACCESS=custom-domainand the URL).
Warning
A domain or a tunnel puts this Kitlig on the internet. Set a strong KITLIG_WEB_PASSWORD, keep an eye on the device list, and revoke what you don't recognise. The device cap and the one-time QR codes are what stand between a guessed address and your projects.
Things to know
Warning
The port speaks plain HTTP, and the MCP token travels in a header on every request. Keep the server on a private network or VPN (Tailscale works well), or put a TLS reverse proxy such as Caddy in front and don't publish the port directly. Anyone with the token can run paid generations on your keys, and anyone with the web password can see and download every file.
- Check the activation. The container log says
activated from KITLIG_ACTIVATION_CODEwhen it worked, and warns at every start while the install is unactivated. Kitlig Web shows a banner on the project home while the install is unactivated. - Projects live under
/data/projectsinside the container. The server tells agents so; ask for a project by name and it's created there, and it then shows up in Kitlig Web. - Local models run on the CPU. Describe with local captions, segmentation and detection all work, slower than on a desktop GPU. Generations on fal and the other providers are unaffected.
- Keys from the environment win. A key set by a
KITLIG_*_KEYvariable overrides one saved through Settings, and Settings shows it as From environment. - Video thumbnails need FFmpeg. The image ships it; outside Docker, a headless install needs FFmpeg set up or video tiles in Kitlig Web show a play icon instead of a frame.
- The same variables work outside Docker:
KITLIG_HEADLESS=1with the Linux AppImage or any desktop build turns that install into a server too, as long as a display exists (xvfb-runon Linux).