Skip to content

Releases: 1broseidon/hotline-computer

Hotline Computer 0.10.3

Choose a tag to compare

@1broseidon 1broseidon released this 29 Sep 04:24

Hotline Computer 0.10.3 uploads without ever replacing a competing file.

  • Create-only uploads. POST /files?create_only=true stages the body in its own temporary file and publishes it only if nothing is at the destination, in one step. An existing file, or another upload that wins the race, answers 409 and is left untouched. A failed or cancelled upload removes its temporary file and never touches the destination.
  • Said up front. Authenticated /files listings carry x-hotline-upload-create-only: 1, so a desk knows it can send files in without risking someone else's.
  • Nothing else changes. Without the query, uploads replace as before, for the viewer page and cookie import.

The next Hotline desk release pins this computer. Its desk half (hotline#102, BRO-145) lets a desktop app paired with a desk on a server send files into a teammate's computer through the desk's files relay, and refuses to on computers without create-only uploads.

Native ARM64/x86_64 desktop acceptance and checks passed on main; the image build published both architectures and passed its cold pulls. The combined image digest is sha256:a891bcf85b91500d8d1bf969551905d528add1ca59b47e7d614534af1f8f0ad1.

Existing computers keep their running version until they are updated from the teammate's pane. state info and state guide identify the attached computer.

Use ghcr.io/1broseidon/hotline-computer:0.10.3.

Hotline Computer 0.10.2

Choose a tag to compare

@1broseidon 1broseidon released this 25 Sep 03:04

Hotline Computer 0.10.2 fills a field with text or a stored secret, and an empty unused one never makes a valid fill fail.

  • An empty unused argument is not a choice. browser fill takes text or secret. A model on a strict tool route has to send every argument, so it sent the one it was not using as "", and a fill of a saved login with text:"" beside it failed as "not both". Now an empty secret never counts. An empty text counts only when it is alone, where it still clears the field. Only a real text beside a real secret is refused, and the refusal says to omit the unused one.
  • The guide says the same. state guide tells the agent to send text or secret, never both, and to leave out the one it is not using instead of sending it empty.

The next Hotline desk release (0.21.0) pins this computer. Its desk half (hotline#48) lets a Copilot model on a strict route leave an unused argument null, and strips the null before the tool sees it.

Native ARM64/x86_64 release gates passed all 24 scenarios per architecture, then image-identity checks and cold pulls.

Cold registry pulls: 21.33 s ARM64 / 21.60 s x86_64. Downloaded-image start-to-health: 0.865 s / 0.400 s. Compressed layers: 745,561,333 / 749,143,289 bytes. The combined image digest is sha256:f71fb32f1d709d198def053d2a11ec66f0c199d7076c1f02dfb96454d4f997a0.

Existing computers keep their running version until they are updated from the teammate's pane. state info and state guide identify the attached computer.

Use ghcr.io/1broseidon/hotline-computer:0.10.2.

Hotline Computer 0.10.1

Choose a tag to compare

@1broseidon 1broseidon released this 24 Sep 14:25

Hotline Computer 0.10.1 answers a long command with its end, and says where the rest is.

  • shell exec answers with the end of each stream. It used to answer with the first 64 KiB of stdout and of stderr. A build or test run reports its result at the end, so on a long log the answer left out the error the agent ran the command for. The answer is now the last 8 KiB of each stream. It starts on a whole line when one begins near the cut, and never inside a character. max_output still sets the size. stdout_bytes and stderr_bytes give each stream's full size, and truncated still means something was left out.
  • Where the rest is. When a stream is cut, more names its log, for example ~/.hotline/jobs/<id>/stdout.log. grep can search it, and shell read with the job ID pages through both streams in the order they were written. When the job's 4 MiB limit dropped output, more says so: the kept output then ends before the command did.
  • shell read pages 32 KiB by default, down from 64 KiB, so one page fits well inside what a client keeps of a tool's answer.
  • Plain text. Answers and pages come back without colour or cursor codes. A progress bar redrawn with carriage returns keeps only its last draw. Window titles, character-set switches and codes ending in ~ are removed too. The job's logs on disk keep every byte.

The next Hotline desk release (0.19.0) pins this computer. Its desk half (hotline#40) keeps 64 KiB of an external tool's answer and shows the model a short tail of a long command.

Native ARM64/x86_64 release gates passed all 24 scenarios per architecture, then image-identity checks and cold pulls.

Cold registry pulls: 20.45 s ARM64 / 22.77 s x86_64. Downloaded-image start-to-health: 0.302 s / 0.456 s. Compressed layers: 745,563,932 / 749,121,633 bytes. The combined image digest is sha256:19a89ce437757c982abf02fe159b3dc98efcce2f6ccf98d710148911305f87d6.

Existing computers keep their running version until they are updated from the teammate's pane. state info and state guide identify the attached computer.

Use ghcr.io/1broseidon/hotline-computer:0.10.1.

Hotline Computer 0.10.0

Choose a tag to compare

@1broseidon 1broseidon released this 23 Sep 21:17

Hotline Computer 0.10.0: a repository describes itself in a manifest, and its desktop app builds, launches and answers to an agent.

  • Workspace manifests. .hotline/manifest.json names a project's packages, platform, libraries, env, services, hooks and runs, and composes over the image's base. state manifest drafts one from the repository's own lockfiles and build files, with a reason for each line; state prepare takes it, and shell run NAME starts a run in the prepared environment. A workspace keeps the base it was composed against until prepare is given upgrade: true. Services and start hooks come back after a restart.
  • Runs that answer when ready. A desktop run answers when its window is up and settled, with the window and a screenshot of it; a web run gets $PORT and answers when it listens, over IPv4 or IPv6. A first prepare locks Nixpkgs from the image and fetches nothing from GitHub.
  • GUI platforms. gl, gtk, gtk4, webkit, qt, native (X11, XKB and Vulkan for winit, wgpu, egui, iced, GLFW, SDL, Fyne, Gio), prebuilt (the manylinux library policy of PEP 600, for pip and uv wheels and downloaded binaries) and qt-wheel (what PySide6 and PyQt wheels load beyond it). Electron runs from node_modules unsandboxed, as Chromium does. The image carries Noto CJK.
  • Driving apps.
    • type and paste return once the focused field has taken every character, so a click that follows cannot overtake a slow webview.
    • scroll takes direction.
    • capture takes window or region, has an image mode, and says how image pixels map to the screen.
    • The accessibility tree leaves out hidden nodes and unnamed wrappers: the whole desktop with Chromium open went from over 25k tokens to 3.3 KB.
    • Reading a Qt 6.8 app's tree no longer crashes it, and Qt trees now read.
  • Calls and shell. No call waits longer than 50 s, so every answer beats a client's one-minute timeout; exec waits up to 45 s. shell exec takes a whole command line in command.
  • Links and the browser. xdg-open, $BROWSER and the desktop's http and https handlers open addresses as tabs of the managed browser, where the person's sign-ins are. Navigating to a page that answers with an HTTP error status shows the page with a note instead of failing.
  • The bars. The desktop's bar and the viewer's control bar count a failure only while it is under an hour old and nothing has run the same command since; cancelled and restart-interrupted jobs never count. The image sets SHELL=/bin/bash.

Known gaps:

  • Drafts can miss what an app needs to launch. A Python project importing tkinter isn't given Tk, and a Cargo workspace with no default binary is drafted cargo run. Correct the manifest's packages and runs.
  • egui, Dear ImGui, Tk and Fyne expose no accessibility tree; drive them from screenshots.
  • flake cannot yet be combined with platform or services.

Validation: the local release gate passed all 24 acceptance scenarios, including a native Hotline (Tauri) build and screens, Qt wheel, WebKitGTK typing and scrolling, and package workspaces. Unit, contract and image-identity checks passed. By hand, from their own repositories: Hotline, Dear ImGui (C++), CustomTkinter (Python), egui (Rust), Fyne, Electron, PySide6 6.8 and 6.11, pygame, and numpy with pandas. Evidence for each release candidate is in qa/0.10.0-rc.1 through qa/0.10.0-rc.5.

Native ARM64/x86_64 release gates passed all 24 scenarios per architecture, then image-identity checks and cold pulls.

Cold registry pulls: 22.65 s ARM64 / 25.53 s x86_64. Downloaded-image start-to-health: 0.286 s / 0.320 s. Compressed layers: 745,560,653 / 749,121,079 bytes, up from about 425 MB in 0.9.0, mostly the image's Nix substituter cache and Noto CJK. The combined image digest is sha256:7d8c5634a3c4f5ede8ccffc188e8f343fbb6e644e42886b6bdb60afd9549c5b3.

Existing computers keep their running version until updated from the teammate's pane; state info and state guide identify the attached computer.

Use ghcr.io/1broseidon/hotline-computer:0.10.0.

Hotline Computer 0.9.1

Choose a tag to compare

@1broseidon 1broseidon released this 21 Sep 21:10

Hotline Computer 0.9.1 says how long a tool listing may be cached, so a Claude Code teammate has its computer tools.

  • The MCP tools/list result now carries ttlMs: 0 and cacheScope: "private". MCP 2026-07-28 requires both, and a client that negotiates that version and validates the reply, as Claude Code does, refused the listing three times and gave up: the teammate connected, authenticated, and saw none of capture, input, browser, shell, files, windows, wait or state, while nothing on the computer or the desk reported a failure. Older clients ignore the two fields. The eight tools themselves are unchanged.

The next Hotline desk release (0.17.1, PR #28) pins this computer and carries the same fix on its own loopback server; a 0.17.0 desk on this computer gets the computer tools but still hides its own from a Claude Code teammate. Existing computers retain their running version until updated from the teammate's pane; state info and state guide identify the attached computer.

Validation: native ARM64/x86_64 release gates passed all 22 scenarios per architecture, the image contract, restart plus recreate recovery on the same home and store volumes, image-identity checks, and cold pulls.

Cold registry pulls: 15.37 s ARM64 / 21.80 s x86_64. Downloaded-image start-to-health: 0.288 s / 0.460 s. Compressed layers: 425,191,640 / 425,052,783 bytes. The combined image digest is sha256:f09ad43528e8e0be7bd18d5ff089416ca92fa7ad040e1686fdbbe6e77060702f.

Use ghcr.io/1broseidon/hotline-computer:0.9.1.

v0.9.0

Choose a tag to compare

@1broseidon 1broseidon released this 21 Sep 20:10

Hotline Computer 0.9.0 asks the person before a passkey is made.

  • While the desk has armed the computer for a site, a call to navigator.credentials.create() in the managed browser is no longer answered by the browser on its own. A guard in every document of every tab that carries passkeys parks the call and keeps what the site asked for: the site, the origin, the account's name and display name. GET /passkeys/registration then answers asked with that ask (id, rpId, origin, rpName, userName, userDisplayName, askedAt) for the desk to put before the person.
  • POST /passkeys/registration/answer {"id": …, "approved": true|false} carries the person's answer back. Approved, the page is told to go ahead, the tab's virtual authenticator mints, and GET answers approved and then registered with the minted credential as before. Denied, the site gets a NotAllowedError, as it would from a person cancelling the browser's own prompt, and the arming ends with the denial, so neither a site nor a teammate can keep asking. An answer to a request that is not waiting is a 409.
  • The guard holds one request before the person at a time, and rejects create() for any other site, or with none armed, with a NotAllowedError that says so. An approved request that the page never carries through to a credential makes way for the next after 30 s.
  • An arming on a fresh browser is kept when the armed site does not open. The courtesy visit to https://<rpId>/ is logged when it fails instead of refusing the arming with a 503, which it did for a site that only exists inside the container.

Hotline desk 0.17.0 is the first that shows the request as a card on the teammate's tape, with Approve and Deny, and carries the answer back; a desk on 0.16.x arms this computer and finds the registration waiting in asked, which it does not answer, so pair it with 0.17.0 to make passkeys. A 0.17.0 desk on a 0.8.x computer still mints without asking. Existing computers retain their running version until updated from the teammate's pane; state info and state guide identify the attached computer.

Validation: native ARM64/x86_64 release gates passed all 22 scenarios per architecture, the image contract (now including the ask, approve and deny passes), restart plus recreate recovery on the same home and store volumes, image-identity checks, and cold pulls.

Cold registry pulls: 16.22 s ARM64 / 21.53 s x86_64. Downloaded-image start-to-health: 0.290 s / 0.486 s. Compressed layers: 425,188,702 / 425,047,451 bytes. The combined image digest is sha256:1618f34e20c78a27b8a0208a3ad471a2cb23b5b97ed63332202f9568e5ca0b3e.

Use ghcr.io/1broseidon/hotline-computer:0.9.0.

Hotline Computer 0.8.1

Choose a tag to compare

@1broseidon 1broseidon released this 21 Sep 16:42

Hotline Computer 0.8.1 takes brought-over cookies back.

  • DELETE /logins/{name} with {"domains": [...]} drops every cookie the browser holds for each named site, or a host within it, from the running browser context, prunes the saved login of those cookies, and removes the login when nothing is left; with no body, every domain the saved login names. The desk's cookie import lands as a saved login loaded with state login_load, and this is its way back out: the desk names the exact domains from its own record, so a site is taken back whatever the saved login holds by then. The name follows the same rule as state login_save; 404 when there is neither a saved login nor a domain to name. Bearer-only, like /secrets.
  • Restoring a login with nothing in storage leaves the page alone, and saving one on a page without an origin (about:blank, a data: URL) saves its cookies alone. Such a page refuses localStorage, which made the desk's import fragile on a blank tab.

Hotline desk 0.16.1 is the first that lists what it brought over and takes it back; a desk on 0.16.0 drives this computer as before. Existing computers retain their running version until updated from the teammate's pane; state info and state guide identify the attached computer.

Validation: native ARM64/x86_64 release gates passed all 22 scenarios per architecture, the image contract (now including the cookies-back pass), restart plus recreate recovery on the same home and store volumes, image-identity checks, and cold pulls.

Cold registry pulls: 18.84 s ARM64 / 19.09 s x86_64. Downloaded-image start-to-health: 0.436 s / 0.445 s. Compressed layers: 425,171,755 / 425,015,662 bytes. The combined image digest is sha256:1a6d949207255f410d21765773b604ba1661955d67c8033704123512d8a58e20.

Use ghcr.io/1broseidon/hotline-computer:0.8.1.

Hotline Computer 0.8.0

Choose a tag to compare

@1broseidon 1broseidon released this 21 Sep 02:36

Hotline Computer 0.8.0 types a login by name on the login's own sites and makes a passkey that is the teammate's own.

  • PUT /secrets takes three kinds of secret. A bare string is a variable, as in 0.7.0, so a desk on 0.15.x keeps working unchanged. An object tagged "kind": "login" carries sites, username, password and, when the site asks for six digits, a TOTP seed. An object tagged "kind": "passkey" carries rpId, credentialId, the private key and the user handle and names. The set is replaced whole each time and lives in the service's memory and nowhere else; one entry the computer cannot keep refuses the whole set with a 400 that names it.
  • browser fill takes secret in place of text: NAME for a variable, NAME.username, NAME.password or NAME.code — the six RFC 6238 digits of this moment, computed here from the seed — for a login. A login is typed only when the page's origin is one of the login's sites: same scheme and port, same host or a subdomain of one, and a site is https:// unless it is localhost. Any other page is refused with a sentence that names the rule. The answer says which field was filled and with which name; the password, the digits and a private key are replaced with [redacted NAME.password], [redacted NAME.totp] and [redacted NAME.privateKey] in every tool answer. Usernames and sites are not secrets and are not redacted.
  • A passkey is the teammate's own, because a person's never leaves their authenticator. Every granted passkey is loaded into a WebAuthn virtual authenticator on each browser tab, from the delivered set at every start and change, so a site's navigator.credentials.get() is answered inside Chromium and nothing is typed.
  • Making one is the desk's act. PUT /passkeys/registration {"rpId"} arms this computer for one site for ten minutes and readies the browser; while armed, and only on that site, navigator.credentials.create() may mint one credential. A guard script on every document gates creation behind a token the page cannot read, and the service's own check on every look removes any credential that is neither delivered nor minted under the current arming, so the teammate cannot give itself a passkey, keep one made for another site, or keep one past the ten minutes. GET /passkeys/registration answers idle, armed, or registered with the minted credential as a whole passkey record; DELETE ends the arming. Bearer-only, like /secrets.
  • state info lists the stored secrets by name and kind, and the skill tells the agent how each kind is used and that it will never see a value.

Hotline desk 0.16.0 is the first that stores logins, arms a passkey and grants either; a desk on 0.15.x drives this computer as before and grants variables alone. Existing computers retain their running version until updated from the teammate's pane; state info and state guide identify the attached computer.

Validation: native ARM64/x86_64 release gates passed all 22 scenarios per architecture, the image contract (now including the login and passkey pass), restart plus recreate recovery on the same home and store volumes, image-identity checks, and cold pulls.

Cold registry pulls: 18.63 s ARM64 / 20.84 s x86_64. Downloaded-image start-to-health: 0.358 s / 0.879 s. Compressed layers: 425,050,395 / 424,904,919 bytes. The combined image digest is sha256:0c5e0e60c087b534a7eb08d1ef54e7ecb56a90971ad41ce0da69668f442e7431.

Use ghcr.io/1broseidon/hotline-computer:0.8.0.

Hotline Computer 0.7.0

Choose a tag to compare

@1broseidon 1broseidon released this 20 Sep 19:57

Hotline Computer 0.7.0 takes the person's secrets from the desk and keeps every value out of what it answers.

  • PUT /secrets, bearer in the Authorization header, hands the computer the whole set of secrets the desk was told to grant: a JSON object of name to value, replaced whole each time. The set lives in the service's memory and nowhere else. Every job the agent starts through shell or files run finds each entry as an environment variable under the name the person gave it — above the workspace's saved environment, under the agent's own env. A preparation job is left out, because what it captures is written into the workspace.
  • Nothing answers a value. The route is PUT-only, state info lists the names alone, and every text a tool returns has each value replaced with [redacted NAME] on its way out, in the spelling JSON gives it too. That keeps a value out of the agent's context when a command prints it; it does not stop a command written to get one out, and the README says so. One entry the computer would not put in a job's environment refuses the whole set with a 400 that names it.
  • A job no longer inherits HOTLINE_COMPUTER_TOKEN. The bearer is the service's door key; it should not lie in every command's environment.
  • /files also takes the bearer as an Authorization header, so a caller that is not a browser — the desk, bringing over cookies — keeps the token out of the URL. The token query stays for the viewer page, which cannot set a header.
  • The skill tells the agent how to use a secret it was given and that it will never see one: state info for the names, $NAME in a command, ask the person for one it was not given.

Hotline desk 0.15.0 is the first that stores secrets and grants them; a desk on 0.14.x drives this computer as before and grants nothing. Existing computers retain their running version until updated from the teammate's pane; state info and state guide identify the attached computer.

Validation: native ARM64/x86_64 release gates passed all 22 scenarios per architecture, the image contract (now including the secrets pass), restart plus recreate recovery on the same home and store volumes, image-identity checks, and cold pulls.

Cold registry pulls: 15.25 s ARM64 / 15.57 s x86_64. Downloaded-image start-to-health: 0.953 s / 0.468 s. Compressed layers: 424,842,126 / 424,696,238 bytes. The combined image digest is sha256:7d2fe99752ec31437c62db9a7376b847e605e126be50b5cbd2fd8b6fad71827f.

Use ghcr.io/1broseidon/hotline-computer:0.7.0.

Hotline Computer 0.6.0

Choose a tag to compare

@1broseidon 1broseidon released this 17 Sep 22:39
e52eb5a

Hotline Computer 0.6.0 answers to its new name.

  • Toad Computer is Hotline Computer. The binary and the image are hotline-computer, the environment it reads is HOTLINE_COMPUTER_*, the operator commands are hotline-computer prepare, packages, open and shell, and the skill the running release serves names itself hotline-computer — which is the name the desk writes it under, so the two halves agree. The desktop's own pieces move with it: the observer terminal's window class, the managed Chromium policy, the Alacritty config at /etc/hotline-computer/alacritty.toml, and the data-hotline-ref attributes the browser tool puts on a page.
  • A prepared workspace keeps its environment under .hotline/ and the person's shell reads ~/.hotline/bashrc. A computer created before this release has those under the old name and will prepare its workspace again; nothing else in a home changes.
  • The image publishes to ghcr.io/1broseidon/hotline-computer. The toad-computer package keeps every image it has and gains nothing new.
  • The repository says its license: MIT or Apache-2.0, at your option.

This release is a break, not a patch. A desk that speaks the old environment cannot drive this computer: it passes TOAD_COMPUTER_TOKEN, and this computer reads HOTLINE_COMPUTER_TOKEN. Hotline desk 0.14.0 is the first that speaks it, and 0.6.0 is the floor it points at (BRO-67). A desk on 0.13.x should stay on ghcr.io/1broseidon/toad-computer:0.5.4.

Use ghcr.io/1broseidon/hotline-computer:0.6.0. Existing computers retain their running version until recreated; state info and state guide identify the attached computer. A tab already watching a computer keeps its page across a recreate; reload it.

Validation: native ARM64/x86_64 release gates passed all 22 scenarios per architecture, the image contract, restart plus recreate recovery on the same home and store volumes, image-identity checks, and cold pulls.

Cold registry pulls: 16.57 s ARM64 / 15.49 s x86_64. Downloaded-image start-to-health: 0.297 s / 0.461 s. Compressed layers: 427,570,355 / 427,364,788 bytes. The combined image digest is sha256:84dd01e488ad8864e2b14d9090a130184b8aba716e8beedd8a996d4cc49c9fcf.