An AI-native software engineering cockpit that turns a phone into a complete development workstation. Instead of wrapping an LLM, Atlan integrates code editing, terminal access, local and cloud models, deterministic verification, build automation, and agent orchestration into a single execution environment β one page at http://127.0.0.1:4589
. The reference platform is Ubuntu proot under Termux on a phone; it also runs on any Linux/macOS host (see docs/SETUP.md
). The cockpit binds to loopback only β nothing reaches it from the network unless you deliberately build a tunnel. What your chosen engines send to their providers is a separate question, answered in full in docs/SECURITY.md
.
Built by John Viruet / Mid-Atlantic AI. Licensed Apache-2.0 β free to use and fork; keep the attribution. Its resident AI, Atlan, is the cockpit's living mascot β a calm presence that reacts to what's actually happening as you build.
Status (2026-08-08):M1βM6 plus streaming chat on awarm, fast session(the CLI is spawned once and kept alive β no ~3.7s cold-start per turn; measured ~1.3s to first token warm vs ~7s cold),live self-awareness(Atlan perceives the current time, your active tab, running agents, today's token burn, and the open project),visible reasoning(summarized thinking streams to a panel), password auth, worker hierarchy, attachments, a code editor, voice I/O (12 AI-model + 10 voice providersβ browser voice free by default, the rest BYO-key, OpenAI-Realtime honestly marked roadmap), and adurable auto-respawning server(bin/atlan-serve.sh
) with optional Termux:Boot reboot-autostart.838 automated tests green across 25 suites(seedocs/RECEIPTS.md
). Runs loopback-only by design; the Preflight security gate goes green once you've set a password (it's part of first-run).
New in this pass:conversationspersist across a refreshwith a searchable history and archiving that never deletes Β·chat-to-chat and chat-to-project messages, bounded by rate, duplicate, backlog and relay-depth limits Β· apreview full-screentoggle Β· aDoctor grouped by the question each check answers, with a one-tap copy-report and a real agent-CLI connection check Β· aPersona+ drafterthat fills the form from a plain sentence Β· and the removal of the last places a vendor name stood in for "the engine you picked" β the wire protocol, the runtime decisions, and the copy.
Confinement, measured on a real Galaxy S24 Ultra (Android 16, kernel 6.1.145-android14, arm64):14/16 rungs,establishes T2, short of T3 only by Landlock and sibling-memory β because the GKI kernel branch freezes when a device ships, so no OS update will add it.declaredTier()
still defaults toT0on every host: those numbers come from anadb shell
, and Atlan runs asuntrusted_app
under Android's own zygote seccomp filter, which can only take capabilities away. Seedocs/SECURITY.md
.
Building on a phone normally means a cramped terminal and no feedback loop. Atlan makes the phone a real dev surface: you talk to an agent that edits your code, you see the app it's changing, its errors flow back to the agent automatically, you can hand any conversation to the command line and back, you can send agents off to work on budgets while you sleep, and you can build an installable APK from the same screen. It's opinionated toward honesty β every capability is labeled for what it actually is, and every dangerous thing has a wall you can see.
Atlan is a Node server you drive from a browser. Where the server can run decides how you use it:
| Platform | On-device (local) server | How you actually run it |
|---|---|---|
| PC β Linux / macOS / Windows | ||
| β easiest | Just Node. git clone && npm install && node server . The most portable target. |
|
| Android (capable phone) | ||
| β | Termux (from F-Droid) β proot-distro install ubuntu β Node β clone β run. Inside the proot, not native Termux β bionic libc can't run the engine CLIs and can't build node-pty , so skipping the proot step is a dead end (the launcher and Doctor now say so instead of crash-looping). A power-user setup, not a tap-to-install app. Aggressive-OEM phones (Samsung/Xiaomi battery/phantom killers) and low-RAM devices may fight it. |
|
| iPhone / iPad | ||
| β impossible | iOS forbids a shell or background server outright. Cloud-client mode only (below). | |
| Any phone, incl. iPhone | ||
| β as a client | ||
| Cloud-client mode: run the server once on a PC / home node / cloud VM, connect the phone as a plain PWA browser client. No Termux on the phone. |
The APK does not remove the Termux requirement on Android β the one-button APK is a wrapper/client; the server still runs in Termux/proot, because the Node server needs a Linux userland and Termux/proot is that userland. The broadly-shareable path is cloud-client mode (host the server once, connect any phone); the phone-local Termux route is the privacy / power-user mode. See docs/SETUP.md
for both.
You also need an engine. Atlan is a cockpit that drives models β it needs at least one: a Claude subscription/API key (full agent, "has hands"), or a free cloud key like Gemini/Groq (chat brains, no hands), or a local llama-server
model (free, if the hardware can run it). With none configured, the app runs but the agent has no brain.
Project pickerβ every folder in your projects directory (configurable, defaults to/root
) with a.git
orpackage.json
. Everything else (fleet, build, terminal, editor) acts inside the picked project.Streaming + thinking + self-awareβ replies stream token-by-token on a** warm session**(the agent CLI is spawned once and kept alive, so there's no cold-start wait per turn); a collapsible panel shows the model'ssummarized reasoning live; a "workingβ¦" indicator fires the instant you send. Atlan isself-aware of live stateβ each turn quietly carries the current time, your active tab, running fleet agents, today's token burn, and the open project, so it genuinely knows what's happening as you work.Attachmentsβ π images/audio/video/files/folders (drag, paste, or reference a path). Images go to vision, files/folders become path references the agent reads, audio/video are routed to a multimodal model (Gemini/OpenAI) and folded into the turn as text.Engine switcher, four honest groups:** Claude Code (agent)**βfable-5
,opus-4.8
,sonnet-5
,haiku-4.5
. Real hands: reads/edits files, runs tools, builds. Permission-carded.Agent CLIsβ Codex and Gemini CLI, running headless full-auto in your repo (all-or-nothing approvals; Claude stays the careful, card-gated primary).On-phone (free)β local models viallama-server
(chat only).Cloud brainsβ a wide, BYO-key spread through one OpenAI-compatible adapter (chat only; they'll tell you they have no hands):** Gemini, OpenAI, DeepSeek, Kimi (Moonshot), xAI Grok, Mistral, Groq, Together, OpenRouter, Fireworks, Cohere**. Adding another provider is a single base-URL row. EachdefaultModel
is just a starting point β type any model the provider offers.- Unavailable options are disabled and say exactly what they need; Settings β Engine keys has a "how to get β" link for every one.
Permission cardsβ when Claude wants a risky action you get Allow/Deny. Deny is always safe; the agent is told why and adapts.** Conversations persist.**A pull-to-refresh used to destroy the thread β chat lived only in the DOM and in a per-socket map the server clears on close. Transcripts are durable now (FLEET_DIR/chats/*.jsonl
, appended a line at a time so a long chat isn't O(nΒ²) writes on phone flash), so a reload replays where you were.π History lists past conversations β searchable, titled by your first message rather than the assistant's tool preamble.Archiving, never pruning. Nothing is deleted to make room. Usage is measured β size, free disk, available RAM β and when it matters the Doctor says so andasks. Archived conversations stay in the same list, marked, and open on tap; the gzip they came out of is an implementation detail you never see.Chat-to-chat and chat-to-project messages. Send a note to another conversation, or to aprojectβ "tell whoever is working on auth" β from the History list. A live conversation gets it on screen; a dormant one keeps it in its transcript until you open it. Every peer message is rendered with its own style and a "from" byline: agents run full-auto here, so an unattributed channel between them would be an injection path, and the attributionisthe control. Rate, duplicate, backlog and relay-depth limits bound it.Session handoffβ after each turn a line shows cost + session id; tap to copyclaude --resume <id>
and continue thesameconversation in any terminal.Auto-attached preview contextβ console errors and πΈ snapshots from the Preview tab ride along on your next message automatically.** Voice β talk to Atlan, hear him back.π€ push-to-talk uses the browser's Web Speech API (free, on-device) and drops the transcript in the box to review before sending. π/π toggles spoken replies. Speech-out is a wide, honest, BYO-key spread β pick one inSettings β Voice**:** Browser**(free, instant, offline; quality varies) Β·** Piper**(free, local, private, real SSML βpip install piper-tts
- a
.onnx
voice)ElevenLabs, Cartesia Sonic, Deepgram Aura-2, OpenAI TTS(low-latency premium) Β·** Google Cloud TTS, Azure Speech, Amazon Polly**(broad languages, real SSML, budget)- Each provider shows its cost, latency, and whether it honors SSML, and greys out until its key is set β the picker never claims a voice you can't use. Mood (calm/proud/alarmed/building) drives light prosody so Atlan sounds like the orb looks.OpenAI Realtime (full-duplex voice-to-voice) is on the roadmap and labeled as such β not pretended to work.
- Point at any local dev server (loopback only β
127.0.0.1
/localhost
/::1
, hostname exact-matched against a loopback allowlist; a deliberate SSRF boundary), rendered through a proxy that injects a watcher. Console strip mirrors the app's logs.Errors queue and auto-attach to the agent's next turn with file:line β you never copy-paste a stack trace again.πΈ Snapshot saves a real PNG a vision-capable agent reads ("the button overlaps the header" becomes verifiable).β€’ Full screen fills the display and Escape brings it back. It's a CSS class first and the Fullscreen API second, because that API is refused on iOS Safari and inside some webviews β a control that silently does nothing on the primary platform would be worse than none.- HMR / live-reload passes straight through.
- A full code editor (CodeMirror, 122 languages, self-hosted β no CDN). Open a file by path or browse the project tree, edit with syntax highlighting, save to disk.
Send to agent for review hands the open file to a chat turn with a review prompt. Scoped to the project; credential paths (
.ssh
, keys) are refused.
xterm.js
bound to tmux sessionatlan-main
in proot. Run anything.Two-way with Termux:tmux attach -t atlan-main
mirrors this exact screen both directions. Stored API keys are injected into its environment so CLIs authenticate like the cockpit. The GUI never traps you.
Runs. Describe a job; an agent runs it alone and reports back.
Profiles gate tools; only Scout is a hard wall.* Scout*=SDK-read-only(write/exec tools stripped at the SDK level, provably β not merely denied).Builder/Verifierget Bash, which isfull host execution as the Termux userβ itsSDK file-edittools are fenced to the project, but Bash side-effects arenot OS-sandboxed on proot (bubblewrap/Landlock don't run there). So don't read "Builder writes stay in the project" as a security boundary β it isn't one for Bash. Seedocs/SECURITY.md
for the honest threat model; run untrusted work on a native sandboxed host.Budgets HALT β with an honest edge. The budget is checked between the agent's steps, so at the cap the run halts, but a single in-flight step can overshoot before the halt lands (a tiny-budget run may spend a few thousand tokens past the cap). There is nounboundedspend, and the ledger always reports the true number. First turn β 35k tokens (Claude Code's preset system prompt, cached after), so ~50k is the practical floor.Top-up. A budget-halted run resumes itsexactsession with fresh budget β nothing lost.Inbox. Report cards carry live burn bar, tokens/cost, denials, final report; they survive restarts (.fleet/history.jsonl
). Chat gets a ping line; the Fleet tab shows an unseen-count badge.Pushβ enable once (π
) for real notifications with the app closed, via a push-only service worker (no fetch handler β can never serve a stale app; Doctor asserts this).KILL ALLβ immediate, always present.
Routines. Scheduled fleet runs: every-N-minutes or daily-at-HH:MM. Each fire is a normal budgeted run labeled routine:<name>
in the inbox. Missed-run rule: if the server was off past a slot, the routine is flagged missed and does nothing until you tap "run late" β a rebooting phone never spends by surprise. Global ; per-routine enable/disable.
Builder β Persona+ compiled to real agent parts.
- A
persona(NAME / FOCUS / BIO / SKILLS / NO_NOS / TEMPLATE / INSTRUCTIONS) compiles into the agent's system prompt, plus a fleet profile. Or describe it and let an engine fill the form in. Seven fields ask you to decompose your intent into the framework's shape before you're allowed to express it, and people don't think in schemas β they think*"a reviewer that's brutal about error handling and never touches tests"*.
POST /api/personas/draft
takes that sentence and returns a filled form.The form stays: a draft is cheap to tweak and free to change, where re-prompting to nudge one line is expensive and nondeterministic. Nothing is saved until you press save.- A
structured command compiles into a typed tool: VARIABLES β JSON-schema parameters; TEMPLATE fields β a constrained JSON answer (models with constrained decoding literally can't return the wrong shape). Checkers are deterministic assertions graded bycode, never by a model:enum β
,range
,regex
,β input-variable
(no invented values),max-length
, andarith
formulas (total = qty*price
) evaluated by a safe parser with noeval
reachable.Test harness runs any command against a chosen engine (free local first), shows every checker's pass/fail with evidence, and on failureescalates the identical command to a Claude fleet run in one tap β the small-model-does-the-reps, frontier-catches-the-hard-5% ladder.
Hierarchy β the worker ladder. A job is a chain of links; each link runs a Persona+ command on the cheapest capable tier (local Qwen β cheap cloud β frontier Claude), deterministic checkers gate each output, a checker failure escalates up the model ladder, and a human gate s where semantic (tier-3) risk concentrates. Hard job budget, blackboard wiring between links, full audit trail of which tier did what. This is the orchestrator-workers pattern: frontier plans/supervises, free local does the bulk.
Runs the proven pipeline in order: env.sh
β web build (CAP_BUILD=1
) β Capacitor sync β Gradle using the qemu shim that lets the x86-only aapt2
run on ARM. Log streams live. Every APK gets a unique filename + visible build stamp (defeats Android's stale-cache), served from the cockpit at /apk/
(auth-gated). Wants ~2.5 GB free RAM β stop llama-server
if tight.
Engine keysβ AES-256-GCM at rest (.keys.enc
- 0600 secret), shown as last-4 only, never echoed; env vars win over stored keys.Doctor checks, grouped by the question they answer rather than listed flat:** Containment**(how much an agent can reach on this device),** Engines**(what can answer you right now),** Build toolchain**,** Health**. Each group carries a verdict; green ones collapse and anything with a problem opens itself. Seventeen rows sorted by nothing is how someone hunting for the containment answer scrolled straight past it.Agent CLI connections asks the two questions that both have to be true, byrunningthe binary: is it installed, and is it authenticated. Installed-but-logged-out and never-installed used to look identical from chat β silence.β§ Copy report puts the whole thing on the clipboard as text, so "what does your Doctor say?" has an answer on a phone that isn't a screenshot. Built only from what's already on screen, so it can't leak anything the tab doesn't show.- Underneath: JDK 21, Android SDK, aapt2 shim,
claude
binary + auth, tmux, disk, chat-transcript usage,llama-server
, Piper voice, the push service worker's no-fetch promise, and the confinement ladder measured on this boot. Green = go; red names exactly what a Termux update broke. Preflightβ the*"safe to expose?"*gate (distinct from "does it work?"): loopback bind, password set, encrypted keys, no plaintext key files, gitignore coverage, no live tunnels. It goes green once you've set a password (first-run) and stored any keys encrypted; the app stays loopback-only until you deliberately expose it.
Mood is real state: calm (idle β idle is free) Β· building (agents/builds active; orbiting lights = running agents) Β· alarmed (Doctor red or a run needs you) Β· proud (something surfaced). Time-aware greetings, event commentary, and a night dimming pass 22:00β06:30. Canvas-rendered, battery-safe (animation s when the tab is hidden). A steady light while you build.
Browser PWA (127.0.0.1:4589, password + httpOnly session cookie)
Chat Β· Preview Β· Editor Β· Term Β· Fleet Β· Build Β· Doctor Β· Atlan canvas Β· xterm.js Β· CodeMirror
β WebSocket (events, PTY) β HTTP (REST, static, /apk)
atlan-server (Node 22)
config.js env > atlan.config.json > defaults (paths, ports, branding)
auth.js password (scrypt) + httpOnly session cookie on /api, /apk, WS; bearer header for automation
claudeEngine Claude Agent SDK, WARM persistent session (CLI spawned once, kept alive across turns): streaming text + summarized thinking, Atlan identity + live self-awareness (cockpitContext), permsβcards, warm setModel() switch, resume-id handoff
agents.js Codex + Gemini CLI headless (JSONL β chat events)
brains.js one OpenAI-compat adapter, 12 providers (local / Gemini / OpenAI / DeepSeek / Kimi / Grok / Mistral / Groq / Together / OpenRouter / Fireworks / Cohere)
voice.js TTS registry: browser / Piper / ElevenLabs / Cartesia / Deepgram / OpenAI / Google / Azure / Polly (SigV4), honest readiness + caps
fleet.js profiled, hard-budgeted runs; burn ledger; inbox; top-up resume
hierarchy.js job = chain of checker-gated links across the model tier ladder
routines.js in-server scheduler; missed-run flags (never auto-fire late)
personas.js Persona+ compiler + deterministic checker engine + harness
attachments.js upload/reference + audio/video β multimodal model
files.js code-editor read/write/tree, scoped + secrets-guarded
preview.js proxy local dev server, inject console/error/snapshot hook
build.js APK pipeline (env.sh β cap sync β gradle/qemu-aapt2)
keys.js AES-256-GCM key store doctor.js/preflight.js health+gate
push.js Web Push (VAPID) pty.js tmux-backed PTYs
Front-end is deliberately no-build vanilla (no vite/bundler process). There is one service worker β but it's push-only with no fetch handler, so it can never serve stale content (the stale-SW landmine stays dead; Doctor asserts it). Fewer moving parts to break in proot.
npm install
bin/atlan-serve.sh start # durable: detached, auto-respawns, survives a dropped session
bin/atlan-serve.sh {start|stop|restart|status|log}
runs the server under a detached supervisor that respawns it if it ever exits and is reparented off your shell, so a dropped terminal/session no longer takes the server down. On a phone it also holds a Termux wake-lock and wires the local Piper voice. For survival across a reboot, the Termux:Boot script (bin/termux-boot.sh
, installed to ~/.termux/boot/
) restarts it on device boot β one-time setup in docs/SETUP.md
.
Then open http://127.0.0.1:4589
. On first load you set a password (8+ chars); a long-lived httpOnly session cookie keeps you logged in across restarts. Take the guided tour (the ?
button reopens it and the searchable handbook any time). See docs/SETUP.md
for the full clone-and-run guide.
Everything below has a working default β Atlan runs with none of these set. They are listed because an undocumented environment variable is a setting nobody can find, and an audit on 2026-08-08 found fourteen of them, including the one that raises the confinement tier.
| variable | default | what it does |
|---|---|---|
ATLAN_CONFINE_TIER |
||
T0 |
||
The confinement tier a run declares. T0 Β· TS Β· T1 Β· T2 Β· T3 . A run whose declaration outruns what the device can prove does not start, and the Doctor names the rung that said no. See docs/SECURITY.md before raising it. |
||
ATLAN_DEFAULT_ENGINE |
||
claude |
||
| Engine used when a request names none. | ||
ATLAN_SANDBOX |
||
| off | 1 passes the Agent SDK's OS-sandbox option to autonomous fleet Bash. Needs kernel user namespaces β unavailable under proot. |
|
ATLAN_ASSUME_NO_SANDBOX |
||
| off | 1 forces the no-kernel-sandbox path. For testing the phone's behaviour from a PC, and for demanding Atlan-side containment where the kernel would have helped. |
|
ATLAN_ORIGIN |
||
| β | An extra origin the guard accepts (a tunnel hostname). | |
ATLAN_SECURE_COOKIE |
||
| off | 1 sets the Secure cookie flag. Set it behind TLS. |
|
ATLAN_FLEET_DIR |
||
<repo>/.fleet |
||
| Where durable state lives: runs, routines, sessions, keys, chat transcripts. | ||
ATLAN_CHAT_ARCHIVE_BYTES |
||
15 GB |
||
| Transcript size at which the Doctor suggests archiving. Nothing is ever deleted automatically. | ||
ATLAN_PROJECTS |
||
/root |
||
| The projects directory the picker lists and every guard scopes to. | ||
ATLAN_MODELS_DIR Β· ATLAN_LLAMA_SERVICE Β· ATLAN_LLAMA_DEFAULTS |
||
| β | Local llama-server : where models live, the service name, and its launch flags. |
|
ATLAN_TIER_LOCAL_BASE Β· ATLAN_TIER_CLOUDSM_BASE Β· ATLAN_TIER_FRONTIER_MODEL |
||
| β | Override a worker-hierarchy rung's endpoint or model. | |
ATLAN_SECRET |
||
| β | Key for the credential-blinding layer. | |
ATLAN_TOKEN |
||
| β | Automation bearer, sent as a header. Never put it in a URL. | |
ANTHROPIC_API_KEY Β· ANTIGRAVITY_API_KEY Β· XAI_API_KEY Β· GITHUB_TOKEN / GH_COPILOT_TOKEN Β· CODEX_API_KEY |
||
| β | Per-engine credentials. Each is granted only to the engine that needs it β the env is not copied wholesale, which is what once handed codex the xAI key. | |
PREFIX |
||
| β | Set by Termux; used to find the toolchain when building a grant list. |
npm test # boots a throwaway instance, runs every suite, writes docs/RECEIPTS.md
838 assertions across 25 suites. They run on a separate throwaway instance (own port + temp state), so they never touch your live cockpit. e2e
makes real Claude runs and is opt-in via RUN_PAID=1
.
CI runs the same gate on every push. A green badge does not mean the sandbox was verified β a GitHub runner has no proot and cannot write unprivileged uid_map
, so ~87 assertions skip there and the workflow says so in its own log. The confinement work is only ever proven on a real host or a real device.
Loopback-only. Human access is a password (scrypt-hashed) plus an httpOnly, SameSite=Strict
session cookie; automation uses a bearer header (never a URL). Failed logins are throttled. Preflight is the gate to ever exposing this; exposure remains a deliberate act and should go through Cloudflare Tunnel + Access, never a bare port (docs/SECURITY.md
).
Accepted, documented limits (nothing hidden):
Bash isn't OS-sandboxed on proot. Claude Code's OS-level Bash sandbox needs kernel namespaces (bubblewrap) or Landlock, which proot doesn't provide. So a builder/verifier agent's Bash is gated by itstool profile, not OS-confined within the machine β though proot itself confines everything to the Termux app sandbox (an agent can't escape to the phone). Run untrusted/autonomous work on a native Linux host to get the real OS sandbox. The Doctor shows which you have.- The preview proxy (:4590) is unauthenticated loopback.
- Cloud "brains" and multimodal delegation send your prompt/media to that provider under its own ToS.
docs/SETUP.md
β clone-and-run guide for a fresh instancedocs/SPEC.md
β full spec + milestone historydocs/HANDOFF.md
β onboarding + recovery playbook (for John or a future maintainer)docs/RECEIPTS.md
β verbatim output of every testdocs/SECURITY.md
β exposure model, why Workers can't host it, iOS realitydocs/VOICE-AND-MODELS.md
β the full voice (TTS/STT) + AI-model provider matrix, keys, and how to add moredocs/FLEET-TESTERS.md
β ready-to-launch adversarial edge-case testers (brittleness/injection/boundary-honesty)vault/
β Atlan's knowledge pages (pre-L3): small grep-queried micro-facts; seevault/README.md
docs/engines/
β per-engine research briefs (Claude, Codex, Gemini, local)
Apache-2.0 (LICENSE
, NOTICE
). Free to use, modify, and distribute β the one requirement is preserving the attribution to John Viruet / Mid-Atlantic AI. π§