Skip to content
nikcli
Docs
Documentation

Mobile App

A complete guide to running and managing nikcli from the Expo app in packages/mobile against a host server.

Overview

The nikcli mobile app is an Expo / React Native client that drives a running nikcli mobile host over its /mobile/* HTTP + SSE API. You start a host on your machine (or a cloud platform), pair the app with a token, and then work from your phone: run agent sessions, approve tool actions, review diffs, import GitHub repos, manage routines and loops, and open interactive terminals.

The app is organized into six tabs plus Settings and Profile:

Core

Sessions

Create and resume agent sessions with live SSE streaming, plan/code modes, approvals, and diffs.

Workspaces

Repos

Server worktrees and GitHub repos — import, sandbox, and launch GitHub-backed sessions.

Shell

Terminal

Fully interactive PTYs running on the host, with multiple tabs and copy/paste.

Automation

Routines

Create, run, pause, and resume scheduled or API-triggered routines.

Orchestration

Loops

Create, run, pause, and resume multi-stage Loops that fire on a schedule or on demand.

Management

Settings & Profile

Providers, connectors, MCP, skills, agents, commands, memories, tokens, plugins, and account.

App preview

The Expo app is built for one-handed control of a running nikcli host. Pair it over a QR code, then drive sessions, terminals, repos, routines, loops, and settings from the same surface you already use to check your messages.

iOS · Android · Expo

Run nikcli from anywhere.

One app, six tabs, every surface of your host in your pocket. Pair once over nikcli://, then stream sessions, approve tool calls, browse your worktrees, and ship a pull request without opening a laptop.

  • Live SSE streaming
  • Plan / Code modes
  • Multi-tab PTY
  • Offline queue
Sessions list — landing screen
Chat & composer inside a session
Chat & composer

Stream agent output, on the go.

A scrollable transcript above a fixed composer with attach, command palette, Git review, and tool drawer shortcuts. Toggle Plan to think before acting, or Code to send as-is. Slash commands surface inline with skill / MCP / arg badges.

Replies stream over SSE with reasoning, text, tool cards, and — when present — a per-message cost and token count.

Workspaces tab with sandboxes and repos
Workspaces & repos

One portfolio for every worktree.

The Workspaces tab merges server worktrees and GitHub repos in one view, with a summary card showing live counts, the active worktree, the execution target, and your GitHub login.

Provision a fresh isolated sandbox, import a repo with one tap, or walk through a guided 3-step launch (repo → branch → session) without leaving the app.

Repository tree file explorer
Files & diffs

Browse, search, and open files.

The Repository tree shows every folder under the active worktree with git status markers (A / M / D), a fuzzy filename filter, ripgrep-backed workspace search, and stat chips for files, dirs, open, and changed.

Tapping a file opens the in-app editor with syntax highlighting, find-in-file, copy, and a View/Edit toggle — large files over ~5,000 lines open read-only.

In-app code editor with syntax highlighting
Editor

A real editor, in your pocket.

Syntax-tinted code, line numbers, breadcrumbs, and a TYPESCRIPT chip with live line and character counts. Edits stay local until you tap Save, which writes the file back to the host; leaving with unsaved changes prompts Save, Discard, or Cancel.

Appearance and theme picker
Themes & preferences

Make it yours.

100+ named color themes (Nikcli default, Nord, Dracula, Tokyo Night, Catppuccin, Gruvbox, Solarized, GitHub, One Dark, Kanagawa, Rose Pine…). System / Light / Dark mode and the theme apply instantly and persist on the device.

Toggle which Settings sections stay visible — Profile, Interaction, Commands, Memories, Models, GitHub, MCP, Connectors, Skills, Agents, Tokens, Plugins, Advanced — and switch them per device.

Settings control plane
Settings

One control plane for everything.

Providers, connectors, MCP servers, skills, agents, slash commands, memories, mobile tokens, plugins, connection, execution target, Git identity, and teleport defaults — all under one scrolling control plane.

Provider and model defaults flow through the host catalog; the app caches the catalog so the composer preselects the right model even before the network round-trip completes.

Routines tab empty state
Routines

Schedule the boring work.

Saved prompts that run as sessions — on a cron schedule, via an HTTP webhook, or on demand. Each routine has a status chip, a trigger summary, the last-run time, and Run now / Edit buttons right from the list.

The API trigger endpoint is assigned by the host at create time, so external systems can fire a routine with no bearer token.

Loops tab empty state
Loops

Compose multi-stage workflows.

A loop is a named, persisted workflow that runs an ordered list of stages, each driven by a single goal command. Loops keep running when the app is closed; the engine lives in the host process.

The list view mirrors status, schedule, stage chain, and last run; the detail editor handles per-stage agent / model / token budget and an interval or manual schedule.

Host setup

The app connects to a host process exposing the mobile API. Two commands cover the common cases. The server binds to 0.0.0.0 by default. For a full cloud / Docker deployment guide see Deploy as a server.

Pairing from inside the TUI

You can pair the phone without touching a terminal. Inside the interactive TUI run /mobile (alias /link) to open the Connect Nikcli Mobile dialog — it handles local LAN pairing, cloud-server pairing, and session teleport from one menu. See Pair from the TUI for the full walkthrough.

Start and pair in one step

Use this to start the host and immediately print a pairing token + QR code.

Terminal
bash
# Local network / Tailscale — no --public-url needed
nikcli mobile serve --pair --pair-name iphone

# Public endpoint (Railway, Fly, etc.)
nikcli mobile serve \
  --hostname 0.0.0.0 \
  --port $PORT \
  --public-url https://your-host.example.com \
  --pair --pair-name iphone --pair-expiry-days 90

Pair an already-running server

Use this to mint a new token for a server that is already up — e.g. to add a second device. --public-url is required so the QR encodes the right address.

Terminal
bash
nikcli mobile pair \
  --public-url https://your-host.example.com \
  --name iphone --expiry-days 90 \
  --directory /home/user/projects/myrepo
FlagApplies toPurpose
--hostname / --portserveBind address and port. Defaults to 0.0.0.0.
--public-urlserve, pairHTTPS URL the app uses from outside your LAN/tailnet. Required for pair.
--pairserveCreate a pairing token at startup and print token + QR.
--pair-name / --nameserve / pairLabel for the generated token.
--pair-expiry-days / --expiry-daysserve / pairOptional token lifetime in days. Omit for a non-expiring token.
--directorypairDefault working directory encoded into the QR; pre-fills the app's directory field.

Combined terminal + mobile host

nikcli remote start --mobile starts the mobile host alongside a terminal remote session (or --mobile-only for just the mobile host) and prints a pairing QR. It shares the same --public-url, --pair, and pairing flags.

Token management

Terminal
bash
nikcli mobile token list           # list issued pairing tokens
nikcli mobile token revoke <id>     # revoke a token by ID
Public hosts must be secured

Public or LAN-facing hosting requires NIKCLI_SERVER_PASSWORD to be set. The server refuses to start with a non-loopback address or --public-url unless this variable is present (or Tailscale auth is active).

Deploy as a server

For phone access outside your LAN you need a publicly reachable HTTPS endpoint running nikcli mobile serve. The repository ships two Dockerfiles that build a production-ready image; you can run it on any container host — a VPS, Fly.io, Render, Google Cloud Run, Kubernetes, or Railway.

Docker images

FileUse when
Dockerfile.serve Recommended. Multi-stage build with arm64/x64 support, a startup healthcheck, Linuxbrew for agent workflows, and the shared railway-entrypoint.sh entrypoint.
Dockerfile Simpler single-stage image with the same mobile-host default command. Useful for quick local experiments; production deploys should prefer Dockerfile.serve.

Both images compile the nikcli binary inside the container, expose port 4096 for the mobile API and 2222 for optional SSH, and default to:

Terminal
bash
nikcli mobile serve --hostname 0.0.0.0 --port 4096

Persistent state (sessions, config, cache) is written under /data via XDG_DATA_HOME, XDG_CONFIG_HOME, XDG_CACHE_HOME, and XDG_STATE_HOME. Mount a volume at /data so restarts and redeploys keep your data.

Build and run locally

Terminal
bash
# From the repository root
docker build -f Dockerfile.serve -t nikcli-mobile .

docker run -d \
  --name nikcli-mobile \
  -p 4096:4096 \
  -v nikcli-data:/data \
  -e NIKCLI_SERVER_PASSWORD='choose-a-strong-password' \
  -e PORT=4096 \
  nikcli-mobile \
  nikcli mobile serve \
    --hostname 0.0.0.0 \
    --port 4096 \
    --public-url https://your-host.example.com \
    --pair --pair-name iphone --pair-expiry-days 90

Replace https://your-host.example.com with the HTTPS URL your phone can reach. --public-url is required for QR pairing from outside the container network. The --pair flags print a bearer token and QR code in the container logs on first start — copy them before the process restarts without --pair.

Pair after deploy

If the container is already running, mint a new token with nikcli mobile pair --public-url https://your-host.example.com on the host (or docker exec into the container) instead of restarting with --pair.

Required environment variables

VariableRequiredPurpose
NIKCLI_SERVER_PASSWORD Yes (public) HTTP basic-auth password for every API request. The server refuses to bind publicly without it (unless Tailscale auth is active).
NIKCLI_SERVER_USERNAME No Basic-auth username. Defaults to nikcli.
PORT No HTTP listen port inside the container. Defaults to 4096.
NIKCLI_SERVER_CORS_ORIGINS No Comma-separated extra origins allowed for browser clients (e.g. your web app domain).

Optional: restore auth and connectors

The entrypoint (packages/nikcli/scripts/railway-entrypoint.sh) can hydrate provider keys and connector credentials from base64-encoded JSON before the server starts:

VariableWrites to
NIKCLI_AUTH_JSON/data/nikcli/auth.json (provider API keys)
NIKCLI_CONNECTORS_AUTH_JSON/data/nikcli/connectors-auth.json (Slack, GitHub, etc.)

Encode with base64 -w0 auth.json (Linux) or base64 -i auth.json (macOS) and set the result as the environment variable. With a /data volume these files persist across redeploys even without the env vars.

Optional: SSH into the container

Both Dockerfiles enable an OpenSSH server on port 2222 when you provide an authorized key:

Terminal
bash
# Plain text (one or more keys, newline-separated)
NIKCLI_SSH_AUTHORIZED_KEYS="ssh-ed25519 AAAA... you@laptop"

# Or base64-encoded authorized_keys file
NIKCLI_SSH_AUTHORIZED_KEYS_B64="c3NoLWVkMjU1MTkgQUFBQS4uLg=="

Map port 2222 if your platform exposes TCP services (Railway TCP proxy, Fly [[services.ports]], etc.). SSH is key-only — password login is disabled.

Deploy on any container platform

The same image works everywhere. The checklist is always:

  1. Build from Dockerfile.serve (or push to a registry your platform pulls from).
  2. Expose port 4096 (or set PORT to match your platform's injected port).
  3. Mount persistent storage at /data.
  4. Set NIKCLI_SERVER_PASSWORD (and provider keys via env or volume).
  5. Terminate TLS at the platform edge so the public URL is https://….
  6. Start with --public-url https://your-domain and pair the phone.

Examples for common hosts:

PlatformNotes
VPS / bare metal docker run as above, or run the binary directly with systemd. Put Caddy or nginx in front for HTTPS.
Fly.io fly launch with dockerfile = "Dockerfile.serve", attach a volume at /data, set secrets for NIKCLI_SERVER_PASSWORD.
Render / Railway / similar Point the service at Dockerfile.serve, add a disk/volume on /data, configure env vars in the dashboard.
Kubernetes Deployment + Service on port 4096, PVC mounted at /data, Ingress for HTTPS. Override CMD to pass --public-url.

Example: Railway

The repo includes a convenience script and config for Railway, but the same Dockerfile.serve image is not Railway-specific — it is just one way to publish it.

  • railway.toml — sets dockerfilePath = "Dockerfile.serve" and mounts /data.
  • script/railway-deploy.sh — builds a minimal upload context (~10 MB), syncs only the packages needed to compile nikcli, and runs railway up.
Terminal
bash
# One-time: link the project (railway link)
export NIKCLI_SERVER_PASSWORD='choose-a-strong-password'
export RAILWAY_SERVICE=nikcli-mobile   # override if your service name differs

./script/railway-deploy.sh          # deploy and stream logs
./script/railway-deploy.sh --detach # trigger deploy in background

Railway injects RAILWAY_PUBLIC_DOMAIN; the default container command uses it for --public-url and auto-pairs on boot. Set NIKCLI_SERVER_PASSWORD in the Railway dashboard before the first deploy. For SSH, add a TCP proxy targeting port 2222 and set NIKCLI_SSH_AUTHORIZED_KEYS.

HTTPS is mandatory for mobile

The Expo app expects a stable https:// base URL. Self-signed certificates and plain HTTP work only on local development builds — production pairing should always go through a trusted TLS terminator.

Connect the app

With no saved server, the app opens the Connect screen (root route /) — a "Secure pairing" card with three fields and a Validate and continue button.

FieldRequiredMeaning
Server URLYesBase address of the running host, e.g. https://your-host.example.com.
Bearer tokenNoPairing token; sent as Authorization: Bearer … on every request.
Default server directoryNoServer path that scopes file/git/session operations; sent as the x-nikcli-directory header.

Tapping Validate and continue calls GET /mobile/bootstrap with the entered credentials. On success the config is saved to the device secure store and the app routes to /sessions if a user token already exists, otherwise to /login. On failure an inline error banner shows the server's message. On later launches the app re-pings the saved host and skips Connect automatically when it responds.

Login & accounts

After connecting, the app shows the Login screen. This is a second auth layer: the pairing token authenticates the device to the host, while the user account token authenticates the person and scopes their sessions and data.

The screen calls GET /user/status first. If no accounts exist yet it shows only a Create account form; otherwise it offers Sign in and Create account. Sign-in needs email + password; registration needs username, email, and a password of at least 8 characters (display name optional). A Remember me toggle (on by default) stores only your email — never the password or token — and surfaces it as a tappable chip next time.

LayerCreated bySent asControls
Pairing tokennikcli mobile pair / serve --pairAuthorization: Bearer + x-nikcli-directoryDevice access to the host API
User session token/user/login or /user/registerManaged by the app for user-scoped endpointsIdentity, roles, per-user data
Stored securely

Both tokens are kept in expo-secure-store (iOS Keychain / Android Keystore), never in plain preferences.

Brand wordmark

The mobile app renders the same nikcli pixel wordmark as the docs site and the dashboard connect screen. components/layout/BrandMark.tsx consumes wordmark-dark.png and wordmark-light.png from assets/ and picks the right variant through useAppTheme().

components/layout/ScreenBrandHeader.tsx wraps the wordmark in a screen-aware header used by the Sessions, Repos, and More tabs. Width is derived from the requested height so the image never stretches or squashes.

See also

Read the full asset and theme guide in the brand assets reference — it documents where the source files live, why we keep three PNGs, and how the theme switch is implemented across surfaces.

Sessions list

The Sessions tab is the landing screen. A hero "Operations board" card doubles as the create entry point and a live status summary, with chips for total sessions, busy, retry, GitHub-linked, container-backed, the active provider/model, and the current project.

  • Search — a debounced field filters sessions, repos, or branches via the host.
  • New session — calls the host to create a session (using your configured execution target: local worktree or container sandbox) and opens it. Title, agent, and model are adjusted from inside the session.
  • List items — show title, location (GitHub repo→branch or local path), an IDLE/BUSY/RETRY badge, file and additions/deletions chips, and an Open button.
  • Actions — long-press or the overflow button opens a sheet: Open, Abort (when busy), or Delete (optimistic, re-fetches on error).
  • Pull-to-refresh reloads the list.

Workspace switcher

components/session/WorkspaceSwitcherSheet.tsx is the bottom sheet opened from the session header. It lists every workspace the host knows about, lets you pick one, and forwards the selection as x-nikcli-directory so subsequent calls land in the right project.

  • Active highlight — the current workspace is marked with the accent color and a checkmark.
  • Status pill — connected, error, or connecting state mirrored from the host bus event.
  • Switch action — sends the new directory + workspace through the SDK, then refreshes the session list and active workspace id in the store.
  • Refresh — pull-to-refresh re-queries the host workspace list, useful after a fresh nikcli workspace create.
Fallback directory

When the host returns a session without a workspace id, the app falls back to the saved directory through sessionWorkspaceFallback() in lib/client.ts, so legacy sessions still load cleanly.

Chat & composer

Inside a session the screen is a scrollable transcript above a fixed composer. The transcript auto-follows new output while you are near the bottom; scrolling up pauses auto-follow.

Composer

The composer capsule grows from 2 to 6 lines and exposes a toolbar:

  • Paperclip — attach files (staged and sent as data-URL file parts).
  • Terminal icon — open the command palette (grouped: View, Session, Compose, GitHub, Memories, Presets, Skills, MCP, Subtasks, Commands).
  • Git branch icon — open the Git review panel.
  • Plus — open the tool drawer (models, skills, tools, MCP servers).
  • Plan / Code toggle — a sliding segmented control.
  • Model label pill, optional MCP N badge, character count, and Send / Stop button.

Plan vs code mode

In Plan mode the host is asked to analyze and propose an approach without making changes until you confirm; in Code mode the message is sent as-is. The mode can be switched mid-session and its default is set in Settings.

Slash commands & sending

Typing / shows up to five matching commands with SKILL / MCP / TASK / arg badges; tapping inserts the command. Plain messages stream the assistant reply over SSE (/mobile/session/:id/stream) with reasoning, text, tool cards, and — when present — a per-message cost and token count. The chosen model is only sent on the first message so the host keeps its running model afterward. If a send fails offline, the input is restored and the operation is queued for the next foreground.

Tool calls

Each tool call renders as a collapsible card whose status dot cycles pending → running → completed/error as stream events arrive. The collapsed header shows a status dot, a tool-specific icon (terminal, file, folder, search, globe, or wrench), the tool name and title, a status pill, and an elapsed-time badge.

Expanding the card reveals the Input key/value pairs and the Output (or Error) — truncated to 400 characters with a "Show all" toggle and a Copy button for the full text.

Approvals & permissions

The app surfaces two approval flows that map to the host permission system: tool-execution permission requests and structured question requests.

Permission cards

Pending permissions render above the transcript with the requested permission, an optional description, command/path scope chips, the matching glob patterns, and three actions — Reject, Allow once, Always allow. A compact approval bar above the composer mirrors these actions and lets you page through queued requests.

Always allow is persistent

"Always allow" is scoped to the current project on the host and is written to permission/:projectID in the JSON storage layer (see Permissions → Always approvals). Rules survive host restarts, but are not shared across different project directories on the same host.

Questions

Question requests show the prompt and option pills. Single-select submits on tap; multi-select uses checkboxes and a submit arrow. A reject button dismisses the question. New permission and question events also fire a local notification (deduplicated) and a haptic.

Files & diffs

Patch diffs

When an assistant message includes a patch, a "Load diff" button fetches the file diffs and renders one collapsible card per file with an added/deleted/modified badge and +N / -N counts. Expanding shows a syntax-tinted line diff (additions green, removals red, context muted).

File explorer

The folder icon in the session header opens the Repository tree for the session's workspace: a filterable file tree with git status markers (A / M / D), workspace text search (ripgrep-backed), fuzzy filename filtering, expand/collapse, and stat chips for files, dirs, open, and changed.

Editor

Tapping a file opens an in-app editor with syntax highlighting, find-in-file (with case toggle and match navigation), word-wrap, copy, and a View/Edit toggle (large files over ~5,000 lines open read-only). Edits are tracked locally; Save writes the file back to the host, and leaving with unsaved changes prompts to Save, Discard, or Cancel.

Session artifacts

lib/session-artifacts.ts extracts inline previews from assistant messages so the chat surface can render URLs, HTML, SVG, and Mermaid diagrams without leaving the app. The top queue banner (SessionQueueBanner) summarizes queued offline messages, and every artifact link is queued the same way when the device is offline.

KindSourceRendered as
urlFirst https?:// link in a message (filtered against well-known hosts).Inline link card with title, host, and an Open button.
htmlhtml / iframe fenced code block.Inline preview through a sandboxed WebView.
svgsvg fenced code block.Inline SVG, with a Copy SVG action.
mermaidmermaid fenced code block.Inline Mermaid render with a Copy source action.
Hosted preview safe list

Hosts like github.com, npmjs.com, and developer.mozilla.org are excluded from URL previews — they appear as text links, never as the "your running app" card.

Repos & GitHub

The Repos tab is a unified workspace portfolio: the server worktrees the host knows about, and the GitHub repos from your connected account. A summary card shows live counts, the active worktree, the execution target, and your GitHub login.

Connect GitHub first

GitHub browsing, import, and launch require GitHub to be connected (OAuth device flow or a personal access token in Settings → GitHub). Until then the GitHub section shows a "Connect GitHub first" empty state.

  • Server worktrees — tap a worktree to make it the active directory (forwarded as the x-nikcli-directory header). The active one is highlighted.
  • New sandbox — provision a fresh isolated server worktree before starting a task.
  • Import a repo — "Import only" clones the repo to the host and sets it active without creating a session; "Use repo" switches to an already-imported clone.
  • Guided launch — "Configure session" loads branches and opens a 3-step wizard (repo → branch → launch) to create a worktree and session in one go via the host GitHub API.

Git review

Git operations are exposed through the Git review panel launched from a session: view status and diff, browse commits and branches, stage/unstage/discard files, commit and push, and — for GitHub-backed sessions — publish a pull request or clean up the worktree. A status bar widget shows branch, staged/unstaged/untracked counts, and ahead/behind. Discard affects only tracked files.

Routines

The Routines tab is a full create/read/update/delete interface for saved prompts that run as sessions — on a cron schedule, via an HTTP webhook, or on demand. The list shows active/paused counts; each row shows the name, a prompt preview, a status chip, a trigger summary (cron and/or API, or "manual only"), the last-run time, and Run now / Edit buttons.

The detail screen edits everything:

  • Name and Prompt (both required).
  • Schedule — preset chips (@hourly, Every 6h, @daily, @weekly) or a custom cron expression, with an enable/disable toggle.
  • API trigger — shows the endpoint POST /mobile/routines/trigger/<token> (no bearer token needed) with an enable/disable toggle.
  • Run now / Pause / Resume / Delete, plus a link to the last run's session.
Also on the CLI

The API trigger token is assigned by the host when the routine is created with --api / --api-token. Everything here is also available via nikcli routine — see Routines.

Loops

The Loops tab exposes the headless Loop engine from the phone. A loop is a named, persisted workflow that runs an ordered list of stages, each driven by a single goal command. Loops keep running when the app is closed; the engine lives in the host process.

The list view shows every loop with:

  • Status chip — idle, running, paused, error, or cancelling, mirrored from the host bus event.
  • Schedule summary — Every 30m, Every 1h, … for interval loops; Manual for trigger-only loops.
  • Stage chain — triage → draft-fix → review preview of the ordered stages.
  • Last run — relative time of the previous run, or Never run.
  • Quick actions — Run now, Pause/Resume, Edit, Delete.

Detail screen

Tap a loop to open the detail screen. It edits everything in the definition:

  • Name and per-stage objective, agent, model, and token budget.
  • Schedule — interval string (30s, 10m, 1h, 1h30m, 1d) or manual, with an enable/disable toggle.
  • Per-stage editor — add, remove, and reorder stages with an inline form.
  • Run history — the last 50 runs with status, duration, and a deep link to the active stage's session.
  • Run now / Pause / Resume / Delete, with confirmation sheets for destructive actions.
Schedule parsing

The duration parser accepts bare numbers (treated as minutes) and Nd/Nh/Nm/Ns tokens, including combinations such as 1h30m. The same parser is used by the loop detail editor and the nikcli loop create --every flag.

Terminal

The Terminal tab opens fully interactive PTYs running on the host — you can type commands, use arrow keys, run editors, and see color output. Each tab is a terminal emulator in a WebView connected to the host over a WebSocket; the auth token and active directory are passed as query parameters (WebSockets can't send custom headers), and resizes are synced back to the server PTY.

  • Multiple tabs stay connected in the background; only the active one is visible.
  • Toolbar shows the working directory and offers Copy (selection or visible text), Paste (sends clipboard into the PTY), New tab, and Close all.
  • Reconnect — up to five automatic retries before a "Connection Failed" overlay with a Retry button.
  • Key bar (components/terminal/TerminalKeyBar.tsx) provides one-tap shortcuts for Tab, Ctrl-C, arrow keys, and a configurable "extra" key (often Escape) on small screens.
  • Key strip (TerminalKeyStrip.tsx) is a compact alt-row used when the soft keyboard is hidden, derived from lib/terminal-keys.ts.
Server-local & non-persistent

The PTY runs on the host (no local shell on the device), and tab state is not persisted across app restarts — though host PTYs may keep running until they time out or are cleaned up.

Teleport

nikcli teleport ships a session (and optionally the working tree) to a remote nikcli host so you can pick it up from your phone. The CLI archives the session messages, uploads them through POST /mobile/teleport, and the remote host re-hydrates the session in its own storage.

Terminal
bash
# Pick the most recent session and ship it to a remote host
nikcli teleport --url https://my-host.example.com --token <mobile-token>

# Ship a specific session, including the source files (no binaries)
nikcli teleport ses_abc123 \
  --url https://my-host.example.com \
  --token <mobile-token> \
  --content --git=false --save

Teleport sheet

From the session header overflow menu on mobile, Teleport to… opens components/session/SessionTeleportSheet.tsx. The sheet prefills the last successful URL + token from lib/storage.getTeleportTarget(), so repeat teleports are one tap.

FlagDefaultMeaning
--urlsaved / envRemote host base URL. Saved to nikcli.json with --save.
--tokensaved / envMobile bearer token for the remote host.
--contenttrueClone the working tree (source files only) into the archive.
--gitfalseInclude the full .git history. Large; off by default.
--savetrueRemember the URL + token for next time.
URL normalization

The CLI strips trailing slashes and any /mobile or /mobile/teleport suffix before posting, so the QR-encoded https://host/mobile form and the bare https://host form both work.

Settings

Settings is a single scrollable control plane; each section can be shown or hidden per device from Appearance. Some areas open dedicated sub-screens. This is where you manage everything the host exposes.

AreaWhat you manage
Models / ProvidersBrowse the host provider catalog, pick a default model for new mobile sessions, and save or remove provider API keys on the host.
GitHubConnect via OAuth device flow (or save the OAuth client ID), view the connected login, disconnect, or save a manual ghp_… token.
MCPAdd remote (URL) or local (command) MCP servers; enable/disable, connect, authenticate (browser), or clear auth, with live status chips.
ConnectorsSave/remove credentials for Figma, Slack, Discord, Microsoft Teams, Linear, Lovable, and Google Chat. Stored on the host.
SkillsBrowse the host skill registry (sources: .nikcli, .claude, .agents) with name, category, version, and tags.
AgentsBrowse built-in and custom agents with their tools and IDs; the default agent is marked.
CommandsAdd/edit/remove host slash commands (template, optional agent/model override, subtask flag); manage local prompt presets and composer defaults.
MemoriesAdd/remove reusable host-backed snippets and browse recent prompt history.
TokensCreate long-lived mobile bearer tokens (name + expiry), copy them once, view last-used/expiry, and revoke instantly.
PluginsSave API keys for Codex (openai), Cursor, and GitHub Copilot on the host.
ConnectionServer URL, bearer token, default directory; Save connection, Forget server, Sign out.
ExecutionExecution target: local worktree (default) or container sandbox (when Docker/Podman is available).
Git identityPer-host Git user name and email used by Git operations from the mobile app (commit, push, publish PR). Backed by the host git_identity config.
Teleport defaultsDefault remote URL + token for the session teleport sheet.

Provider and model defaults flow through lib/model-catalog.ts and lib/model-preferences.ts. The catalog is fetched once per host connection and cached, while preferences are stored locally so the composer can preselect the right model even before the network round-trip completes.

Profile & account

The Profile screen shows your identity (avatar, display name, @username, email, role, member-since), account stats, and an edit form for display name and password. Admins additionally get a User management list to promote/revoke admins and delete accounts. A Sign out action (with confirmation) ends the session.

Deletions are permanent

Deleting a user from the admin panel removes the account permanently on the host and cannot be undone.

Notifications & Live Activities

Notifications are off by default. Enable them in Settings → Interaction → Notifications; the app requests OS permission on enable. Three kinds gate on individual toggles:

KindToggleFires when
sessionReadySession readyA session goes idle / ready for the next command.
permissionsPermission requestsA session is waiting for an approval.
failuresFailuresA session enters an error state.

Notifications are suppressed while the app is foregrounded and deduplicated within an 8-second window. Android uses a dedicated nikcli-mobile channel. On iOS 16.2+ the app drives Live Activities that show session state on the Lock Screen / Dynamic Island, with a color tone derived from state (attention for approvals, countdown for retries, editorial for GitHub publish/cleanup, work for running). Activities deep-link back into the session and are reconciled on app foreground. Live Activities are iOS-only.

Offline behavior

When a send can't reach the host, the message is queued locally (in secure storage) and replayed automatically the next time the app returns to the foreground. The queue is capped at 50 entries (oldest evicted) and drained with per-operation retry — successful sends are removed, failures stay for the next attempt.

Session queue

lib/session-queue.ts plus components/SessionQueueBanner.tsx give the user visible feedback about pending offline work: a banner shows how many messages are queued and whether the next send was deferred. The banner appears on every screen that consumes the same session id and disappears automatically once the queue drains.

Network awareness

lib/offline.ts watches the device's network status. When the connection drops, new sends are queued without surfacing an error; reconnecting drains the queue without user action.

Themes & preferences

Settings → Appearance offers a color mode (System, Light, Dark) and a color theme picker with 100+ named themes (Nikcli default, plus Nord, Dracula, Tokyo Night, Catppuccin, Gruvbox, Solarized, GitHub, One Dark, Kanagawa, Rose Pine, and many more). Mode and theme apply instantly and persist on the device.

Other persisted preferences you can manage in Settings include:

PreferenceDefaultWhere
Notifications (master + per-kind)Off / on per kindInteraction → Notifications
Haptics (master + send/commands/permissions/errors)OnInteraction → Haptics
Message gestures (swipe / long-press)OnInteraction → Message gestures
Composer default modeCodeCommands → Composer defaults
Auto-follow transcriptOnCommands → Composer defaults
Slash suggestionsOnCommands → Composer defaults
Visible settings sectionsAll visibleAppearance