RimBridgeServer is a RimWorld mod that turns the running game into a bridge an external tool can use.
In practice, that means a test harness, developer tool, or AI agent can start RimWorld, inspect live game state, drive built-in UI, manage mods and mod settings, execute debug actions, take targeted screenshots, and verify behavior against the real game instead of a simulation.
This project is aimed at automated mod development and testing:
- integration testing against a real RimWorld session
- UI and UX verification through semantic dialogs, targets, and screenshots
- faster repro loops for debug actions, saves, settings, and load-order changes
- AI-assisted mod development through GABS or direct bridge connections
Architecture and design notes live in docs/architecture.md, docs/lua-frontend-design.md, docs/semantic-state-design.md, and docs/attention-policy.md.
RimBridgeServer runs inside RimWorld and exposes a tool surface for:
- reading game, map, camera, selection, notification, and UI state
- driving high-level game actions such as debug actions, main tabs, Architect designators, and selection changes
- changing mod settings and mod load order
- capturing screenshots, including clipped screenshots for known UI or screen targets
- running small automation scripts through JSON or Lua front-ends
It is designed to stay as close as possible to RimWorld's own logical seams instead of reimplementing gameplay logic outside the game.
GABS is the best way to use RimBridgeServer from an AI or automation harness.
Why this is the recommended mode:
- GABS can start and stop RimWorld for you
- GABS can discover the live bridge tool surface after the game connects
- you do not need to manage ports or tokens manually
- this is the cleanest setup for autonomous mod testing
Basic setup:
- Install RimBridgeServer into your RimWorld
Modsfolder. - Enable
RimBridgeServerin RimWorld's mod list. - Install and configure GABS.
- Start RimWorld through GABS and connect to the running game.
Once RimWorld is up, GABS exposes the game-management tools (games.start, games.connect, games.call_tool) and then the live RimBridgeServer tool surface behind them.
RimBridgeServer now also publishes blocking attention when severe async failures happen after a call boundary, such as hard log errors or failed bridge operations. In GABS this surfaces through games.get_attention and games.ack_attention: ordinary game calls pause until the attention item is reviewed and acknowledged, while rimbridge/get_bridge_status, rimbridge/list_operation_events, and rimbridge/list_logs remain available for diagnosis. The current built-in policy is documented in docs/attention-policy.md.
If you want the same stack used for real mod repro-and-fix sessions, use:
Harmonyplus the mod you are testingRimBridgeServerinside RimWorld for live game inspection and control- GABS to launch RimWorld and surface the live tools to your AI client
- DecompilerServer to inspect
Assembly-CSharp.dlland related managed code while debugging
There is a short setup order here: docs/rimworld-mod-debugging-stack.md.
Direct mode still works if you do not want to use GABS.
Basic setup:
- Install RimBridgeServer into your RimWorld
Modsfolder. - Enable
RimBridgeServerin RimWorld's mod list. - Start RimWorld normally.
- Read the RimWorld log for the bridge startup lines.
In direct mode, RimBridgeServer logs lines like:
[RimBridge] GABP server running standalone on port 5174
[RimBridge] Bridge token: abc123...
Your client then connects to:
- address:
127.0.0.1 - port: the logged bridge port
- token: the logged bridge token
For cross-repo development in a sibling workspace, RimBridgeServer supports an opt-in local NuGet source override without switching the project to ProjectReferences.
- default local source path:
../.nuget-local - enable it with
EnableLocalNuGetOverride=true - override package versions with
LibGabPackageVersionandRimBridgeServerAnnotationsPackageVersion
Example:
dotnet restore Source/RimBridgeServer.csproj \
-p:EnableLocalNuGetOverride=true \
-p:LibGabPackageVersion=1.0.0-local.1 \
-p:RimBridgeServerAnnotationsPackageVersion=1.1.0-local.1Populate the local source by packing the sibling library into ../.nuget-local, for example:
dotnet pack ../Lib.GAB/Lib.GAB/Lib.GAB.csproj \
-o ../.nuget-local \
-p:PackageVersion=1.0.0-local.1Release-facing assets are kept in source control so the in-game metadata, GitHub release packaging, and external post copy stay aligned.
About/ModIcon.pngis the small in-game mod iconAbout/Preview.pngis the preview/banner imageSource/Originals/Steam-Post.txtandSource/Originals/Ludean-Post.txthold the maintained workshop/forum copyscripts/render-mod-icon.swiftregeneratesAbout/ModIcon.pngfrom the preview art
If you only need the shortest possible mental model, use this:
- Install the mod and enable it in RimWorld.
- Prefer GABS if you want AI or harness control.
- Start RimWorld.
- Wait until the bridge is connected.
- Use tools like
rimbridge/get_bridge_status,rimworld/start_debug_game,rimworld/get_ui_layout,rimworld/take_screenshot,rimworld/list_mods, andrimworld/update_mod_settingsto drive and validate the game.
Third-party mods can expose bridge tools by referencing the RimBridgeServer.Annotations NuGet package and annotating ordinary public methods. RimBridgeServer delays its own GAB startup until RimWorld has finished initializing all loaded mods, then scans every loaded mod assembly exactly once, registers all discovered annotated tools exactly once, and exposes them through the same capability registry and top-level GAB tool surface as built-in tools.
Practical rules:
- use
RimBridgeServer.Annotationsas the only shared dependency - annotate public static methods, public instance methods on your
Verse.Modclass, or public instance methods on a type with a public parameterless constructor - use
[ToolParameter]for argument docs,Tool.ResultDescriptionfor a short successful-result summary, and[ToolResponse]for response field docs when useful - expect per-mod fault isolation: one broken mod should not block discovery for other mods
- assume that blocking attention is still owned centrally by RimBridgeServer; there is not yet a public cross-mod API for third-party mods to publish their own async attention items directly
Minimal example:
using RimBridgeServer.Annotations;
public sealed class MyModBridgeTools
{
[Tool(
"mymod/ping",
Description = "Example tool exposed through RimBridgeServer",
ResultDescription = "A success flag and the resolved label returned to the caller.")]
public object Ping(
[ToolParameter(Description = "Optional label")] string label = null)
{
return new
{
success = true,
label = label ?? "pong"
};
}
}The current public tool surface is grouped below by function. For the generated parameter-level reference pulled straight from the annotated source and kept fresh by CI, see docs/tool-reference.md.
Lua authoring note: rimbridge/run_lua is intentionally a lowered Lua subset, not general-purpose Lua. Start with rimbridge/get_lua_reference and rimbridge/compile_lua; prefer local bindings, rb.call/rb.poll, static field access, and static one-based indexes such as names[1]. Dynamic indexing such as names[i], arbitrary global assignment, and most broader Lua features are rejected in v1.
rimbridge/ping- Connectivity test. Returns 'pong'.rimworld/get_game_info- Get basic information about the current RimWorld gamerimbridge/get_operation- Get the latest retained journal snapshot for a specific operation id, including any bounded retained result payloadrimbridge/get_bridge_status- Get the current bridge and RimWorld state snapshot without mutating game staterimbridge/list_capabilities- List registered bridge capabilities so an agent can discover the live bridge surface instead of relying on hardcoded tool knowledgerimbridge/get_capability- Get one registered bridge capability descriptor by capability id or aliasrimbridge/list_operations- List recent bridge operations from the in-memory operation journal, optionally expanding retained result payloadsrimbridge/list_operation_events- List recent bridge operation lifecycle events from the in-memory event journalrimbridge/list_logs- List recent captured RimWorld and bridge log entries from the in-memory log journal, including operation correlation when availablerimbridge/wait_for_operation- Wait for an operation in the journal to reach a terminal statusrimbridge/wait_for_game_loaded- Wait until RimWorld has finished loading a playable game and, optionally, until screen fade is completerimbridge/wait_for_long_event_idle- Wait until RimWorld reports no long events in progress
rimbridge/get_script_reference- Get a machine-readable authoring reference forrimbridge/run_script, including statement types, expressions, conditions, limits, and examplesrimbridge/get_lua_reference- Get a machine-readable authoring reference for the loweredrimbridge/run_luasubset, including quick-start rules, common pitfalls,paramsbinding, compile errors, limits, and examplesrimbridge/run_script- Execute a JSON script containing ordered capability calls and generic control statements; callrimbridge/get_script_referencefor the machine-readable language referencerimbridge/run_lua- Compile a small lowered Lua subset, not general-purpose Lua, into the shared script runner and execute it through the normal capability registry; start withrimbridge/get_lua_referenceorrimbridge/compile_luarimbridge/run_lua_file- Load a.luafile, treat it as the same lowered Lua subset used byrimbridge/run_lua, and execute it through the shared script runnerrimbridge/compile_lua- Compile the supported lowered Lua subset, not general-purpose Lua, into the JSON script model without executing capability calls; use this first for new script shapesrimbridge/compile_lua_file- Load a.luafile and compile it as the same lowered Lua subset used byrimbridge/run_luawithout executing capability calls
rimworld/pause_game- Pause or unpause the gamerimworld/set_time_speed- Set RimWorld's current time speed directlyrimworld/play_for- Unpause the current game at a requested time speed for a bounded real-time duration, then pause it again, ending early if the game is paused, returns to the main menu, or the session changesrimworld/list_debug_action_roots- List top-level RimWorld debug action roots using stable internal debug-action pathsrimworld/list_debug_action_children- List direct children of a RimWorld debug action pathrimworld/search_debug_actions- Search the full RimWorld debug-action tree globally by path, label, category, and source metadata so callers do not need to walk one subtree at a timerimworld/get_debug_action- Get metadata for one RimWorld debug action path and, optionally, its immediate childrenrimworld/execute_debug_action- Execute a supported RimWorld debug action leaf by stable path, including pawn-target actions when pawnName or pawnId is providedrimworld/set_debug_setting- Set a RimWorld debug setting toggle by stable path to a deterministic on/off staterimworld/set_colonist_job_logging- Deterministically enable or disable job-tracker logging for one current-map colonist and return a log cursor plus recommendedrimbridge/list_logsarguments for consuming future job linesrimworld/list_mods- List installed RimWorld mods, whether each one is enabled in the current configuration, and whether it matches the currently loaded sessionrimworld/get_mod_configuration_status- Read semantic mod-configuration status for the current active load order, including warnings, ordering issues, and whether a restart is required to match the loaded sessionrimworld/set_mod_enabled- Enable or disable one installed mod by stable mod id, package id, name, or folder name, optionally persisting the updatedModsConfig.xmlimmediatelyrimworld/reorder_mod- Move one currently enabled mod to a new zero-based active load-order index, optionally persisting the updatedModsConfig.xmlimmediatelyrimworld/list_mod_settings_surfaces- List loaded mod handles that expose a settings dialog, a persistentModSettingsstate object, or bothrimworld/get_mod_settings- Read one loaded mod's semanticModSettingsobject by stable mod id, package id, settings category, or handle type namerimworld/update_mod_settings- Apply one or more field-path updates to a loaded mod'sModSettingsobject, with optional immediate persistence throughMod.WriteSettings()rimworld/reload_mod_settings- Reload a loaded mod'sModSettingsobject from disk, discarding unsaved in-memory changesrimworld/open_mod_settings- Open RimWorld's nativeDialog_ModSettingswindow for one loaded mod without foreground-dependent input
rimworld/get_designator_state- Get the current Architect/designator selection state, including god mode and the selected designatorrimworld/set_god_mode- Enable or disable RimWorld god mode deterministicallyrimworld/list_architect_categories- List RimWorld Architect categories using stable category idsrimworld/list_architect_designators- List Architect designators for one category, flattening dropdown widgets into actionable child designatorsrimworld/select_architect_designator- Select an Architect designator by stable id without relying on foreground UI interactionrimworld/apply_architect_designator- Apply an Architect designator to one cell or a rectangle, with optional dry-run validationrimworld/list_zones- List current-map zones such as stockpiles and growing zonesrimworld/list_areas- List current-map areas such as home, roof, snow-clear, and allowed areasrimworld/create_allowed_area- Create a new allowed area and optionally make it the selected allowed-area targetrimworld/select_allowed_area- Select an allowed area by id for area-designator flows, or clear the selection when areaId is omittedrimworld/set_zone_target- Set or clear the explicit existing-zone target on a zone-add designatorrimworld/clear_area- Clear all cells from a mutable area such as a custom allowed arearimworld/delete_area- Delete a mutable area such as a custom allowed arearimworld/delete_zone- Delete an existing zone by idrimworld/get_cell_info- Inspect one map cell, including things, blueprints, frames, designations, zones, and areasrimworld/get_cells_info- Inspect every map cell in a rectangle up to 1024 cells, including things, blueprints, frames, designations, zones, and areasrimworld/find_random_cell_near- Use RimWorld's expanding-radius random cell search to find a nearby cell or footprint that satisfies generic map criteriarimworld/flood_fill_cells- Analyze a contiguous area from one root cell using RimWorld's generic cell flood-fill algorithm and the same reusable footprint criteria as find_random_cell_near
rimworld/get_ui_state- Get the current RimWorld window stack and input state for background-safe UI automationrimworld/list_main_tabs- List RimWorld main tabs such as Work, Assign, Research, and mod-provided tabs with stablemain-tabtarget idsrimworld/open_main_tab- Open one RimWorld main tab by stable target id,defName, label, or tab window typerimworld/close_main_tab- Close the currently open RimWorld main tab, optionally asserting which tab is open firstrimworld/get_ui_layout- Capture a generic structured layout snapshot of the current dialogs, windows, or main tabs, including actionable control target idsrimworld/click_ui_target- Activate an actionable UI control target returned byrimworld/get_ui_layouton the next real draw framerimworld/set_hover_target- Set a persistent virtual hover target for UI review and screenshots, using either an actionableui-elementtarget id or a current-map cell, pawn, or thingrimworld/clear_hover_target- Clear the current virtual hover target so screenshots and mouseover-driven UI return to the real cursor staterimworld/press_accept- Send semantic accept input to the active RimWorld window stack without requiring OS focusrimworld/list_languages- List installed RimWorld languages, including a recommended ASCII-safe switch query for each language and the currently active languagerimworld/press_cancel- Send semantic cancel input to the active RimWorld window stack without requiring OS focusrimworld/close_window- Close an open RimWorld window by type name or, if omitted, the topmost windowrimworld/open_window_by_type- Open a RimWorld window by short or full .NET type name when the window exposes a public parameterless constructorrimworld/click_screen_target- Semantically click a known actionable target id returned byrimworld/get_screen_targetswithout requiring OS focusrimworld/switch_language- Switch RimWorld to an installed language by the recommendedQuery fromrimworld/list_languagesor another exact language name match, mirroring the main-menu language picker and saving prefsrimworld/start_debug_game- Start RimWorld's built-in quick test colony from the main menurimworld/go_to_main_menu- Return to the RimWorld main menu entry scene, or no-op if already there
rimworld/list_colonists- List player-controlled colonists available for selection and drafting, including stable pawn idsrimworld/clear_selection- Clear the current map selectionrimworld/select_pawn- Select a single colonist by name or stable pawn idrimworld/deselect_pawn- Deselect a single selected pawn by name or stable pawn idrimworld/set_draft- Draft or undraft a colonist by name or stable pawn idrimworld/get_selected_pawn_inventory_state- Read the selected pawn's carried thing and inventory contents, including Pick Up And Haul tracked items when available
rimworld/get_selection_semantics- Get structured details for the current selection, including inspect strings, inspect-tab types, and the current selection fingerprintrimworld/list_selected_gizmos- List the current selection's actionable grouped gizmos using deterministic selection-scoped gizmo idsrimworld/execute_gizmo- Execute one grouped gizmo for the current selection by gizmo id returned fromrimworld/list_selected_gizmosrimworld/list_messages- List live RimWorld messages with native message ids and structured look-target metadatarimworld/list_letters- List current letter-stack entries with native letter ids, semantic letter content, and structured look-target metadatarimworld/open_letter- Open a specific letter by native letter id, mirroring a normal left-click on the letter stack entryrimworld/dismiss_letter- Dismiss a specific dismissible letter by native letter id, mirroring a normal right-click on the letter stack entryrimworld/list_alerts- List active RimWorld alerts with structured culprit targets and alert-snapshot-scoped alert idsrimworld/activate_alert- Activate one alert by alert id returned fromrimworld/list_alerts, mirroring a normal left-click on the alert readout
rimworld/get_camera_state- Get the current map camera position, zoom, and visible rectrimworld/get_screen_targets- Get current screen-space targets such as open windows and active context-menu geometryrimworld/get_map_target_info- Resolve a current-map pawn or thing to its map position and occupied cell rectanglerimworld/jump_camera_to_pawn- Jump the camera to a pawn by name or stable pawn idrimworld/jump_camera_to_cell- Jump the camera to a map cellrimworld/move_camera- Move the camera by a cell offsetrimworld/zoom_camera- Adjust the current camera zoom/root sizerimworld/set_camera_zoom- Set the current camera root size directlyrimworld/frame_pawns- Frame a comma-separated list of pawns by name and/or stable pawn id so they fit in viewrimworld/frame_cell_rect- Frame a requested map-cell rectangle plus optional margin cells and leave the camera at the tightest full-viewport view that keeps the padded rect visiblerimworld/screenshot_cell_rect- Frame a requested map-cell rectangle plus optional margin cells, capture the full viewport at the tightest view that keeps the padded rect visible, and restore the prior camera immediately after by defaultrimworld/take_screenshot- Take an in-game screenshot and return the saved file path plus optional target metadata
rimworld/list_saves- List saved RimWorld gamesrimworld/spawn_thing- Spawn a thing on the current map at a target cellrimworld/save_game- Save the current game to a named saverimworld/load_game- Load a named RimWorld saverimworld/load_game_ready- Load a named RimWorld save and wait until the game is automation-ready before returning
rimworld/open_context_menu- Dispatch a live map click at a target pawn or cell and capture the resulting context menu when one remains openrimworld/right_click_cell- Dispatch a live map click interaction for the current pawn selection so vanilla and modded handlers see the same input path as a real clickrimworld/get_context_menu_options- Get the currently opened debug context menu optionsrimworld/execute_context_menu_option- Execute a context menu option by index or labelrimworld/close_context_menu- Close the currently opened debug context menu
- docs/architecture.md - implementation strategy and architectural direction
- docs/lua-frontend-design.md - Lua front-end design and current execution model
- docs/semantic-state-design.md - rationale for the semantic inspection and notification surfaces
- docs/tool-reference.md - generated per-tool reference derived from the
[Tool]and[ToolParameter]annotations in source