HomeGamesUpdatesPricingMethodology
Steam News26 July 202616d ago

Demo Update - v0.11.0

Features Customize your UI layout - ~/.config/layout.cfg (same idea as blackdoor.conf's theme customization) lets you rearrange every pane on screen.

In this update3

Full notes

Full Blackdoor update

Read the full published notes in a cleaner layout. The original post stays linked below.

What changed

7 fixes10 additions4 changes2 removals
  • Server
  • Gameplay
  • Store
  • Balance
  • Fixes
  • UI and audio
addedFeaturesCustomize your UI layout - ~/.config/layout.cfg (same idea as blackdoor.conf's theme customization) lets you rearrange every pane on screen. Just write "width height content" per line and panels place themselves automatically, left to right, wrapping to a new row as needed - no coordinate math required. Want exact placement instead? Use the precise form (x y width height content) for full manual control. List two or more content types on one line (e.g. mission,network) to merge them into a single tabbed panel. Edits apply live the instant you save the file in-game - no restart needed, and if you make a mistake it tells you exactly what's wrong and keeps your last working layout until you fix it. Prefer a visual editor to hand-writing percentages? There's a drag-and-resize designer at blackdoor.tools/layout that exports a ready-to-paste config.
addedFeatureswget/curl can now authenticate - pass -u= -p= (or the long form --username= --password= ) to fetch a protected page directly, without opening browse first. Unlike browse's login form, credentials passed this way only authorize that one call - they don't grant a session or get remembered, matching real wget behaviour. The usage message and the 403 error both now actually explain this instead of just saying "Forbidden".
addedFeaturesA few new things to find - not saying what, or where. Good luck.
addedFeaturesNew top hardware tiers - CPU Mk.V ($12,000, 160 ticks/sec), RAM 12 Slots ($8,000), Storage Drive++ ($2,500, 400 files). For anyone who's capped out the shop and is still sitting on cash.
changedAPI ChangesNew: wget(url) / wget(url, username, password) - scripts can now fetch a web-served page directly, without needing connect() first. Previously there was no scriptable way to read HTTP content at all - download() only works on an authenticated SSH connection's real filesystem, and brute_web() only cracks the login without fetching anything. wget() fills that gap: resolves the target by hostname or IP, walks the web roots, checks the page's protected flag against an existing web session/credentials or the passed username/password, and writes the result to ~/downloads/ same as download(). Returns {success, path, size, local_path, error}.
addedAPI ChangesNew mission objective type: browse - the mission schema now supports checking that a player has viewed a specific page in the in-game browser. Infrastructure only for now - no missions use it yet, official or otherwise.

Blackdoor changes

addedCustomize your UI layout - ~/.config/layout.cfg (same idea as blackdoor.conf's theme customization) lets you rearrange every pane on screen. Just write "width height content" per line and panels place themselves automatically, left to right, wrapping to a new row as needed - no coordinate math required. Want exact placement instead? Use the precise form (x y width height content) for full manual control. List two or more content types on one line (e.g. mission,network) to merge them into a single tabbed panel. Edits apply live the instant you save the file in-game - no restart needed, and if you make a mistake it tells you exactly what's wrong and keeps your last working layout until you fix it. Prefer a visual editor to hand-writing percentages? There's a drag-and-resize designer at blackdoor.tools/layout that exports a ready-to-paste config.
addedwget/curl can now authenticate - pass -u= -p= (or the long form --username= --password= ) to fetch a protected page directly, without opening browse first. Unlike browse's login form, credentials passed this way only authorize that one call - they don't grant a session or get remembered, matching real wget behaviour. The usage message and the 403 error both now actually explain this instead of just saying "Forbidden".
addedA few new things to find - not saying what, or where. Good luck.
addedNew top hardware tiers - CPU Mk.V ($12,000, 160 ticks/sec), RAM 12 Slots ($8,000), Storage Drive++ ($2,500, 400 files). For anyone who's capped out the shop and is still sitting on cash.
changedNew: wget(url) / wget(url, username, password) - scripts can now fetch a web-served page directly, without needing connect() first. Previously there was no scriptable way to read HTTP content at all - download() only works on an authenticated SSH connection's real filesystem, and brute_web() only cracks the login without fetching anything. wget() fills that gap: resolves the target by hostname or IP, walks the web roots, checks the page's protected flag against an existing web session/credentials or the passed username/password, and writes the result to ~/downloads/ same as download(). Returns {success, path, size, local_path, error}.

Features

  • Customize your UI layout - ~/.config/layout.cfg (same idea as blackdoor.conf's theme customization) lets you rearrange every pane on screen. Just write "width height content" per line and panels place themselves automatically, left to right, wrapping to a new row as needed - no coordinate math required. Want exact placement instead? Use the precise form (x y width height content) for full manual control. List two or more content types on one line (e.g. mission,network) to merge them into a single tabbed panel. Edits apply live the instant you save the file in-game - no restart needed, and if you make a mistake it tells you exactly what's wrong and keeps your last working layout until you fix it. Prefer a visual editor to hand-writing percentages? There's a drag-and-resize designer at blackdoor.tools/layout that exports a ready-to-paste config.

  • wget/curl can now authenticate - pass -u= -p= (or the long form --username= --password=) to fetch a protected page directly, without opening browse first. Unlike browse's login form, credentials passed this way only authorize that one call - they don't grant a session or get remembered, matching real wget behaviour. The usage message and the 403 error both now actually explain this instead of just saying "Forbidden".

  • Quick-run from the editor - Ctrl+Enter while editing a script now saves and runs it immediately, without leaving the editor. The first time you use it, the editor shrinks slightly to make room for a small, still fully-interactive terminal strip below it, so you can watch the output (or type another command) without switching views.

  • A few new things to find - not saying what, or where. Good luck.

  • New top hardware tiers - CPU Mk.V ($12,000, 160 ticks/sec), RAM 12 Slots ($8,000), Storage Drive++ ($2,500, 400 files). For anyone who's capped out the shop and is still sitting on cash.

API Changes

  • New: wget(url) / wget(url, username, password) - scripts can now fetch a web-served page directly, without needing connect() first. Previously there was no scriptable way to read HTTP content at all - download() only works on an authenticated SSH connection's real filesystem, and brute_web() only cracks the login without fetching anything. wget() fills that gap: resolves the target by hostname or IP, walks the web roots, checks the page's protected flag against an existing web session/credentials or the passed username/password, and writes the result to ~/downloads/ same as download(). Returns {success, path, size, local_path, error}.

  • New mission objective type: browse - the mission schema now supports checking that a player has viewed a specific page in the in-game browser. Infrastructure only for now - no missions use it yet, official or otherwise.

  • connect() now returns a user field - the username you ended up authenticated as (if any), without a separate whoami() call. Shows up automatically if you log(conn) too, alongside target, hostname, etc.

  • Reconnecting to the same server no longer stales your old conn - calling connect() again without saving the new result used to make scripts' original conn variable silently invalid, even though nothing was actually disconnected. It's now only treated as stale if the active connection has genuinely moved to a different server - reconnecting to the one you're already on keeps the old conn working.

  • whoami() improvements - it now returns your own local account name when you're not connected to anything, instead of silently returning "" as if inheriting a remote session that doesn't exist (matches how the terminal whoami command already behaves). And whoami(conn) now actually checks the conn you pass it - previously it silently ignored the argument and just returned global auth state regardless of whether that specific connection was still active.

  • Pivot chains are now capped at 5 hops - keeps chaining proxies a real tradeoff instead of something you could stack indefinitely for a one-time noise cost. pivot() now fails past 5, same as it already does if the proxy's already in the chain or a trace is active.

  • EmoteNew: write_local(path, content)alias for save(), matching write_file()'s naming for the local side. Handy for testing a script's filtering/formatting locally before writing to a remote file.
  • New: ternary operator - condition ? true_value : false_value, for cutting down on nested if blocks.

  • New list methods: pop() and insert() - list.pop() / list.pop(i) removes and returns the last item (or item i); list.insert(i, val) inserts val at index i, shifting the rest right. Both accept negative indices, same as list[-1]. remove(i) already existed but was never documented anywhere in-game - it's now in the editor's cheatsheet alongside the rest.

Bug Fixes

  • /leave #lounge permanently removed the channel - #lounge isn't a regular NPC channel you can lose access to, it's core infrastructure like #blackdoor. Leaving it erased it from your channel list entirely, and /join #lounge afterward just returned "Unknown channel" - the only way back in was a fresh save load. It's now protected the same way #blackdoor already was.

  • Active IRC channel reset to #blackdoor on every load - loading a save correctly restored whatever channel you were last on, but ~2.5 seconds later the boot sequence unconditionally forced it back to #blackdoor anyway. If you load into #lounge, you now stay in #lounge.

  • Boot sequence stole focus back to the terminal - if you clicked into another pane (or used Ctrl+5 for IRC) while the boot animation was still playing out, it got yanked back to the terminal input the moment boot finished. It now leaves your chosen pane alone.

  • scp uploads to a folder (no filename) silently failed to complete mission drop objectives - scp file.txt user@host:/drops/ (trailing slash) wrote to the literal broken path /drops/ instead of /drops/file.txt, since the destination parsing never stripped the trailing slash before checking whether the target was a directory. Typing the full path with filename already worked correctly - only the folder-only form was affected. Fixed.

  • The default probe.bd script errored out around port 24,000 with "Script exceeded maximum execution limit"- a full 65,535-port scan legitimately needs about four times more execution steps than the old safety limit allowed. Raised the limit with plenty of headroom; a genuinely stuck script still gets caught quickly by the separate CPU-overload safeguard, which doesn't depend on this. Also fixed probe.bd itself only ever scanning up to port 65,534 (an off-by-one in its port range), despite claiming to scan all of them.

  • range() could be asked to build an effectively unbounded list in one shot - unlike a loop body, range() allocates its whole list immediately rather than one step at a time, so an oversized request (an extra typo'd zero, say) could hang or crash the game outright rather than getting caught gracefully. It now errors immediately past 1,000,000 elements - comfortably above any legitimate use (a full port scan needs 65,535).

  • "not connected" errors gave no hint why, even right after a successful connect() - list_files()/download()/crack()/etc. all validate that your conn is still the active connection, but the error never explained why an old one had gone stale. It now says so directly when it's because connect() was called again since without saving the new result.

  • upload() required a shop tool that no longer exists - it was gated behind a tool that got cut before launch because a different feature it was meant to unlock alongside upload() was never built. upload() itself has no dependency on that missing feature and was never meant to be affected - it's unlocked by default now, no purchase needed.

  • Killing a script that had connect()'d to a server left its trace running forever, with no way to stop it - a script owns whatever connection it opens itself, so disconnect (the terminal command) correctly refuses to touch it - that's there so a script can't accidentally hijack your real ssh session. But if you killed the script instead of letting it finish, nothing ever cleaned up its connection either, so the trace just kept ticking with no way to stop it. kill now releases the connection, and disconnect explains what's going on instead of just saying "not connected" if a script is still holding one open.

  • save()/write_local() wrote garbage when given anything but a string - save("out.dat", [0, 1, 2]) wrote the literal text instead of the list's contents, because the fallback conversion was stringifying the interpreter's internal value wrapper instead of the value itself. Non-string values now write the same readable form log() and str() already produce (so that example now writes [0, 1, 2]).

  • Static

Source

Steam News / 26 July 2026

Open original post

Changelog.gg summarizes and formats this update. How we read updates.