Headlamp plugin: agent-sandbox dashboard with per-agent tmux terminals and file drop.
  • TypeScript 85.1%
  • JavaScript 14.3%
  • Dockerfile 0.6%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
JJ Macalinao e0fa08f205
All checks were successful
release / image (push) Successful in 7m30s
fix: keep the keyboard closed when a selection ends with it down
Android opened the keyboard as the finger lifted after a long-press
selection made with the keyboard down. The textarea's
virtualkeyboardpolicy is set to manual for the selection, which stops
the browser opening it by itself, and goes back to auto a second after
the release.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-07 03:46:39 +08:00
.forgejo/workflows chore(ci): drop cleanup steps the ephemeral runner makes redundant 2026-10-03 02:06:11 +08:00
demo feat: add a standalone demo of the terminal and a screenshot script 2026-09-24 03:51:27 +08:00
docs docs: add the fullscreen terminal screenshot and demo instructions 2026-09-24 03:51:28 +08:00
src fix: keep the keyboard closed when a selection ends with it down 2026-10-07 03:46:39 +08:00
test feat: start a tmux selection with a long press on touch screens 2026-10-06 20:03:28 +08:00
.dockerignore fix(ci): stop rebuilding the plugin inside dind 2026-09-20 18:17:01 +00:00
.gitignore feat: add a standalone demo of the terminal and a screenshot script 2026-09-24 03:51:27 +08:00
Dockerfile feat: render the terminal in JetBrainsMono Nerd Font Mono 2026-09-21 14:02:29 +08:00
LICENSE chore: add license, readme, container build and release workflow 2026-09-20 17:36:25 +00:00
mise.toml chore: scaffold headlamp plugin 2026-09-20 17:31:10 +00:00
package-lock.json fix: upgrade xterm to 6.0 for the Android IME duplicate-input fix 2026-10-01 00:11:43 +08:00
package.json fix: upgrade xterm to 6.0 for the Android IME duplicate-input fix 2026-10-01 00:11:43 +08:00
README.md docs: add the fullscreen terminal screenshot and demo instructions 2026-09-24 03:51:28 +08:00
renovate.json5 fix(ci): run npm ci without lifecycle scripts and delay automerges 2026-09-20 18:04:35 +00:00
tsconfig.json chore: scaffold headlamp plugin 2026-09-20 17:31:10 +00:00

headlamp-agent-sandbox

A Headlamp plugin for kubernetes-sigs/agent-sandbox.

Fullscreen terminal with tabs and the touch key row

Features

  • A list of Sandbox resources (agents.x-k8s.io/v1beta1) with readiness and expiry, plus create, suspend, resume and delete.
  • Terminal tabs per sandbox. Each tab attaches to its own named tmux session, so you get independent shells instead of one shared screen.
  • Drop a file or paste a screenshot to upload it to /workspace/.attachments/. Its path is typed into the prompt without submitting.
  • Ctrl+click (Cmd on a Mac) opens a link and Ctrl+right-click copies it. Selecting text copies it. Hold Shift to select while tmux mouse mode is on.
  • A key row for touch keyboards: Esc, Tab, Ctrl-C, arrows, Home/End, the tmux prefix, sticky Ctrl and Shift, upload, and fullscreen. Dragging scrolls tmux history, and the row stays above the on-screen keyboard.
  • Shift+Enter sends ESC CR, which Claude Code reads as a newline.
  • Launching an agent types its name into the shell, so shell functions apply and you land back at a prompt when it exits.
  • JetBrainsMono Nerd Font is bundled, so every device draws the same glyphs. This is why main.js is a few megabytes.

Uploads use a separate pods/exec call that pipes base64 into the pod. The sandbox needs no web server or credential of its own, and everything runs under your own Headlamp session and RBAC.

Requirements

  • Headlamp v0.45 or newer.
  • The agent-sandbox controller and its Sandbox CRD.
  • RBAC in the sandbox namespace: sandboxes (list, get, create, update, delete), and pods and pods/exec (get, list, create).
  • tmux, base64, head and mv in the sandbox image.

Settings

Setting Default Meaning
namespace agents Namespace the sandboxes live in.
templateName agent-session SandboxTemplate that new sandboxes copy spec.podTemplate and spec.volumeClaimTemplates from.

The create dialog has no pod spec editor. The template stays owned by whatever manages it, such as a GitOps repository.

Installing

Each release is published to the Forgejo registry as git.macalinao.org/jj/headlamp-agent-sandbox:<YYYY.MDD.P>. It can be pulled without credentials. A same-day rebuild reuses the tag, so pin the digest.

The image only holds the built plugin at /plugin/headlamp-agent-sandbox/. Copy it into Headlamp's plugin directory with an init container:

spec:
  initContainers:
    - name: headlamp-agent-sandbox
      image: git.macalinao.org/jj/headlamp-agent-sandbox:<tag>@sha256:<digest>
      command: ['cp', '-a', '/plugin/.', '/headlamp/plugins/']
      volumeMounts:
        - name: headlamp-plugins
          mountPath: /headlamp/plugins
  containers:
    - name: headlamp
      args:
        - -plugins-dir=/headlamp/plugins
      volumeMounts:
        - name: headlamp-plugins
          mountPath: /headlamp/plugins
  volumes:
    - name: headlamp-plugins
      emptyDir: {}

Development

npm install
npm start           # rebuild on change against a local Headlamp
npm run build       # production build
npm run test:unit
npm run lint

The Dockerfile only copies dist/, so run npm run build before docker build.

demo/ renders the real terminal against a fake pod, with no cluster or Headlamp. It produced the screenshot above:

npm run demo:build
(cd demo/dist && python3 -m http.server 8000) &
node demo/screenshot.mjs 'http://127.0.0.1:8000/index.html?fullscreen' docs/fullscreen-terminal.png

The screenshot script needs chromium on the PATH.

License

Apache-2.0, see LICENSE. The bundled font is under the SIL Open Font License, and its icon sets are listed in src/fonts/README.md. The .woff2 files are the Regular and Bold JetBrainsMonoNerdFontMono faces from Nerd Fonts v3.5.1 (JetBrainsMono.tar.xz, sha256 04d5e8f903693f9dd13e16f867e994834e681eb3c72c0d337a770dcda09010cf), converted with fonttools ttLib.woff2 compress.