Skip to content
addiberraPublic
forked from tjakobsson/uatu

About

UatuCode is a watch UI for following what an AI coding agent is doing in a codebase.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

 
 

Latest commit

 

History

350 Commits

Folders and files

NameName
Last commit message
Last commit date
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 

Repository files navigation

uatu

UatuCode

Codebase Watcher
I observe. I follow. I render.

CI OpenSSF Scorecard License: MIT Built with Bun Tested with Playwright

uatu previewing a project README — Change Overview, file tree, and plan usage in the sidebar, the rendered Markdown in the preview pane, a Claude Code conversation on the right, and two shells in the embedded terminal


uatu is a watch UI for following what an AI coding agent is doing in a codebase. Run the hub, add a folder from its dashboard, and uatu keeps a preview in sync with the files as they change. Flip the Follow switch on to jump to whichever file just changed; flip it off and click a file to stay there — the file you're viewing still reloads in place when it changes on disk. Today it's a live preview and file browser; over time it grows toward a companion for onboarding, peer review, and self-assessment of cognitive debt.

Features

  • Markdown / AsciiDoc rendering with unified metadata cards for frontmatter and AsciiDoc header attributes
  • Mermaid diagrams (fenced and [source,mermaid]) with a fullscreen pan/zoom viewer
  • Syntax highlighting for source files, plus per-file copy-to-clipboard on every code block
  • Cross-document .md/.adoc link navigation; live reload over one server-sent-events stream per tab, however many panes are open
  • Rendered / Source / Diff view chooser per document; Diff renders only the active file's changes against the resolved compare base via @pierre/diffs
  • Follow switch for the agent-collab workflow — on = auto-jump to the latest changed file, off = stay on the file you're reading (it still reloads in place when it changes on disk)
  • Side-by-side / stacked split layouts for Source + Rendered
  • Whole-repo browsing with .uatu.json ignore.exclude and .gitignore filtering on top of built-in defaults
  • Sidebar with Change Overview, Files, and Git Log — toggle individual panes from the per-pane menu
  • Git-aware workspaces: adding a folder outside a repository offers git init
  • Git worktree workspaces: create and switch branch checkouts from the workspace picker, with independent terminals and conversations, parent credential policy and guarded cleanup
  • Embedded terminal panel (real PTY via Bun) toggled with `Ctrl+`` — dark theme, Nerd Font detection, dock to bottom or right, split for two concurrent PTYs
  • Workspace-scoped Chat with your own OpenCode and Claude Code — resumable history, streamed Markdown and tool activity, permissions, questions, plan approvals, task progress, cancellation, and safe file navigation
  • Installable as a PWA so TUI editor shortcuts (Cmd+W, Cmd+T, Cmd+L, Cmd+R) reach the embedded terminal

Claude Code and OpenCode are first-class agents in uatu: the aim is to use what each SDK offers, not the subset they share. The Agent SDK coverage dashboard lists everything each SDK declares and what uatu does with it; the gap count is the work still to do.

Install

Homebrew (macOS and Linux)

brew install tjakobsson/tap/uatu
brew upgrade uatu        # stay current

UatuCode Desktop (macOS)

A native macOS app that connects to hubs: add a hub (a remote box, or http://localhost:4700 for one on your own machine), sign in once, and every window is a native view onto that hub's dashboard and sessions. Requires macOS 26 or later.

brew install tjakobsson/tap/uatu-desktop

The app is a client, not a server — it runs no sessions of its own, so quitting it never stops anything. Desktop source lives in desktop/macos/.

Edge channel (nightly)

Want the bleeding edge instead? Builds of main — the CLI for every platform, plus a signed desktop app — are published nightly (when main has changed) to the rolling edge prerelease:

brew install tjakobsson/tap/uatu-edge                 # CLI (macOS and Linux)
brew install --cask tjakobsson/tap/uatu-desktop@edge  # desktop app
brew upgrade              # follows the nightly channel

Edge is exactly what's merged — expect occasional rough edges. Each channel conflicts with its stable sibling, so switch back with brew uninstall uatu-edge && brew install tjakobsson/tap/uatu (and likewise brew uninstall --cask uatu-desktop@edge && brew install --cask tjakobsson/tap/uatu-desktop).

Manual download

Grab the archive for your platform from the latest release — uatu-darwin-arm64.zip, uatu-darwin-x64.zip, uatu-linux-x64.tar.gz, or uatu-linux-arm64.tar.gz — extract the single uatu binary, and put it on your PATH.

macOS note: binaries downloaded through a browser are quarantined and Gatekeeper will refuse to run them (the binaries are not notarized). Either approve the binary under System Settings → Privacy & Security, or clear the quarantine flag:

xattr -d com.apple.quarantine ./uatu

Downloads via curl or Homebrew never set the quarantine flag and run as-is.

Every release ships a SHA256SUMS file, and all archives carry GitHub build-provenance attestations:

gh attestation verify uatu-darwin-arm64.zip --repo tjakobsson/uatu

From source

Requires Bun ≥ 1.3.5 (for the built-in PTY API; older Bun degrades the terminal feature gracefully).

bun install
bun run dev                        # dev hub on testdata/watch-docs (see dev/README.md)
bun run build && ./dist/uatu hub   # standalone binary
bun link                           # expose `uatu` on PATH

Windows is pending Bun's upstream PTY work — the terminal stays hidden there; everything else works. Release binaries are darwin/linux only for now.

Usage

uatu runs as a hub. uatu hub starts a daemon that serves a login-gated dashboard on one port, runs one session per workspace folder, and serves each session under <host>/s/<workspace-id>/. Run it on your own machine or on one you own elsewhere. Every session has the full app (live preview, change overview, detachable terminals, chat), in any browser, in an iPad that installs the hub as a PWA, or in UatuCode Desktop.

To start a hub on your own machine, hash a password first. The command reads it from stdin, never from its arguments; run it bare to type the password at a prompt instead:

printf '%s' 'a-password' | uatu hub hash-password   # prints an $argon2id$… hash

Save the hash as a user in ~/.config/uatu/hub.json:

{ "users": [{ "name": "you", "passwordHash": "$argon2id$…" }] }

Then run the hub and open the URL it prints (http://127.0.0.1:4700/ by default):

uatu hub

Sign in and choose Add Folder to pick any folder on the machine, or clone a repository into one. Each folder becomes a workspace with a stable URL.

uatu hub [--config <PATH>] [--port <PORT>] [--exit-on-stdin-close]
uatu hub hash-password

Login is required on every interface, localhost included. A hub started without a configured user prints these steps and exits. Sessions are server-side records, so signing out, or revoking a device from the dashboard's Devices pane, ends that session at once for every client holding it. Terminal sessions detach and reattach across connectivity blips: a shell, or an agent running in it, keeps working while your train is in a tunnel.

docs/SELF-HOSTING.md is the full guide. It covers the trust model (hub users share the daemon's OS user, with no isolation between them), the config reference, certificates (mkcert, tailscale cert, tailscale serve), and systemd and launchd service definitions.

uatu serve is gone. It was deprecated in v0.5.0 and is now removed, along with the watch alias and the bare uatu <path> form. Each of them prints the steps above and exits with an error. Add the folder to a hub instead.

Web notifications

The hub can send Web Push notifications when an agent asks a question, requests permission, or successfully finishes a turn. Open Notifications in the hub navigation or workspace sidebar to choose workspaces and event categories for that browser or installed app. Tick All workspaces to cover every workspace on the hub, including ones registered later, or pick workspaces one by one; turning All workspaces off brings back the workspaces you had picked. Permission is requested only when you enable it.

Configure the hub's hub.json with a contact for its Web Push sender, then restart the hub:

"notifications": { "contact": "mailto:you@example.com" }

On iPhone and iPad, use HTTPS, add Uatu to the Home Screen, and enable notifications from the installed app. Supported desktop browsers can enroll without installation. Plain HTTP to a remote LAN address does not support push. The hub needs outbound access to the browser's push service; no Apple developer account or Uatu-hosted relay is needed.

Notifications are for when you are not looking at Uatu. While a workspace page is visible on any of your devices, the hub holds your pushes. A finished turn is not pushed; the workspace switcher shows it. A question waits, and if it is still unanswered 30 seconds after you hide or close your last Uatu page, it is pushed then. While you work in one workspace, a question in another shows a notice in the page with an Open button that takes you to it. With no Uatu page visible, alerts go out immediately. The hub dashboard does not count as looking, and neither does a page left open in a background tab.

The hub and agent must stay running, but the page can be closed or the phone locked. Tapping an alert opens its conversation. Notifications contain generic event text and the workspace name, not question text or tool output. Delivery timing follows browser and OS settings, including Focus. Sends expire after five minutes, and failures, cancellations, and background-work transitions do not produce a successful-turn alert.

Preferences are per device. Signing out, login expiration, or session revocation stops future sends under that login. Return to Notifications and enable it again after signing in. Disable on this device stops future sends without affecting other devices. Already submitted platform notifications cannot be recalled.

See self-hosting for state backups, troubleshooting, and rollback.

Configuration: .uatu.json

Optional repo-root file carrying content-scoping facts about the repository — a single ignore block. Validation errors are surfaced in Change Overview rather than aborting the watch session.

{
  "ignore": {
    "exclude": ["bun.lock", "*.log", "!debug.log"],
    "respectGitignore": true
  }
}

Every monospace surface in the app — rendered Markdown code blocks, AsciiDoc code blocks, the source view, the diff view, the terminal — uses the bundled Hack Nerd Font Mono so prompt icons (powerline, devicons, git status, FontAwesome, Material Design, etc.) render correctly out of the box in every browser, including Safari and the installed PWA, which hide locally-installed fonts from web pages.

The compare base is resolved automatically in order: origin/HEAD → origin/main → origin/master → main → master, then falls back to staged + unstaged worktree changes against HEAD.

Files at or above 1 MB render without syntax highlighting to keep the browser responsive. Binary files appear with VS Code-style icons and route to a "preview unavailable" view. Git status (added / modified / deleted / renamed / untracked) is surfaced as ambient row annotations on the tree.

Security posture of the terminal

The terminal endpoint accepts shell input, so it gets a stricter envelope than the rest of uatu:

  • Loopback-only children. Each workspace's session child binds 127.0.0.1, never 0.0.0.0, and nothing on the network can reach it. Remote access always ends at the hub's authenticated HTTPS listener.
  • Per-session token. Each child mints a 32-byte token at startup, and the terminal's WebSocket upgrade requires it. The hub reads the token from the child's startup output and attaches it to proxied requests itself, so it never reaches a browser. Restarting the workspace rotates it.
  • Origin checks at both hops. The hub compares the browser's Origin with the Host it receives and refuses a mismatch, so a reverse proxy in front of it must pass Host through unchanged (see SELF-HOSTING). It then forwards loopback-shaped Host and Origin headers, and the child's own allowlist (127.0.0.1 or localhost on the port the request arrived at) holds unchanged.
  • Write-only OSC 52 clipboard bridge. TUIs that own the mouse (Claude Code, opencode) copy selections by emitting OSC 52 up the PTY. uatu bridges the sequence to the browser's clipboard, which is the clipboard of the machine running the browser, not the hub. Read queries (ESC ] 52 ; c ; ?) are never answered, so nothing in the terminal can read your clipboard, and decoded payloads are capped at 100 KB. Every accepted write shows a "Copied N characters" toast, so a hostile escape sequence can't poison your clipboard silently. On browsers that require a user gesture for clipboard writes (Firefox, Safari), a blocked write turns into a Copy-button toast instead of being lost.

Safari 17+ blocks page-accessible Nerd Fonts (anti-fingerprinting), so terminal prompts using Powerline glyphs show TOFU squares there. Chrome / Edge / Brave or "Add to Dock" works around it.

Watchdog and freeze recovery

Every session child runs a sibling watchdog subprocess. If the child's 1Hz heartbeat stops advancing for 30 seconds' worth of consecutive watchdog checks, for example because the JS event loop is wedged on a native fsevents deadlock, the watchdog captures a forensic dump and force-kills the child (see issue #40). Staleness is counted in watchdog checks rather than wall-clock time, so a laptop sleeping past the timeout does not trigger a false kill on wake.

The hub builds its children's command lines itself, so these settings reach sessions through the hub's environment:

UATU_DEBUG=1 uatu hub                      # also write 1Hz NDJSON metrics for every session
UATU_HEARTBEAT_TIMEOUT_MS=60000 uatu hub   # staleness threshold (default 30000)

Diagnostic files live under $XDG_CACHE_HOME/uatu/ (or ~/.cache/uatu/): heartbeat, snapshot, optional debug ring-buffer, and forensic dumps on freeze. With UATU_DEBUG set, GET /s/<workspace-id>/debug/metrics returns a session's live counters.

Chat startup

Chat history and inventory reads have a 30-second client deadline. Cold agent history and catalog reads allow the configured startup timeout plus 35 seconds for transport (65 seconds with the default startup setting). A failed read offers Retry read, which preserves the draft and issues only read requests. Conversation selection cancels obsolete reads. History can load while optional model, mode, and command catalogs are still pending.

History reuse stays in memory, with an estimated 32 MiB and eight-conversation limit per provider. Claude verifies native file identity, timestamps, size, and normalization inputs before reusing parsed history. OpenCode's current API has no revision covering both history stores, so it shares concurrent reads and reconciles later reads against both stores. Changed older-page cursors require a fresh snapshot. No cache files are written to the workspace.

Chat starts OpenCode lazily, waits for it to answer at all, then waits a shorter slice for it to report healthy. A cold OpenCode start on a slow filesystem can exceed the 30-second default. Widen it on the hub, which passes its environment to every session:

UATU_OPENCODE_STARTUP_TIMEOUT_MS=60000 uatu hub

An empty, non-numeric, or non-positive value is ignored and the default stands — a typo here must not stop documents from being served. When startup does fail, the Chat surface reports which phase failed and offers a Diagnostics block (resolved executable, shadowed candidates on PATH, version, probed endpoint, elapsed time, probe count, last probe outcome, and OpenCode's own stdout/stderr) plus a Retry that recovers a fixed environment without restarting the workspace. The ephemeral OpenCode server password never appears in that block.

Privacy note: forensic dumps include absolute repo paths from lsof (macOS) or /proc/<pid>/fd/ (Linux). Review before sharing.

For contributors

Development setup, validation, pull-request conventions, and the OpenSpec workflow are documented in CONTRIBUTING.md. A folder-by-folder tour of the runtime and its extension points lives in ARCHITECTURE.md.

About

UatuCode is a watch UI for following what an AI coding agent is doing in a codebase.

Resources

Contributing

Security policy

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages