Jesse A. Green / notebook

ImHex Admin & Developer Guide

Generated June 2026 from WerWolv/ImHex at 8a6be85

AI-generated documentation. The library is checked by sampling (three repositories so far); this guide was not individually reviewed. Verify against the project before relying on it.

This guide is the deep reference for people who build, package, extend, deploy, or operate ImHex: system architects, plugin developers, packagers, and power users. It documents ImHex's architecture, the libimhex SDK and ContentRegistry extension surface, the event system, the build and compile pipeline, configuration, security posture, operations, and a code-quality and improvement analysis.

End-user installation and feature usage live in the companion User Guide; this document assumes that material and focuses on internals.

Note

ImHex is GPLv2-licensed overall, with two components under LGPLv2.1 to permit proprietary plugins: lib/libimhex (the plugin interface library) and plugins/ui (shared UI elements). This split is deliberate — see §9 Security & Licensing.


Table of Contents

  1. Executive Summary
  2. Architecture Overview
  3. Repository Structure
  4. Process Model & Startup
  5. The libimhex SDK
  6. The ContentRegistry: Extension Surface
  7. The Event System
  8. Plugins Inventory
  9. Security & Licensing
  10. Building & Compiling
  11. Plugin Development
  12. Scripting (C# / .NET and C)
  13. The MCP Server
  14. Configuration Reference
  15. Filesystem & Path Resolution
  16. Operations
  17. Code Quality & Conventions
  18. Testing
  19. Potential Improvements & Tech Debt
  20. Quick Reference

1. Executive Summary

ImHex is a cross-platform hex editor and binary-analysis platform written in modern C++ (C++23). Architecturally it is not a monolith but a small native core (main) plus a plugin runtime (libimhex) that loads feature plugins as shared libraries at startup. Almost every user-facing capability — the hex editor view, the Pattern Language integration, hashing, diffing, disassembly, YARA, visualizers, the script loader, OS integrations — lives in a plugin that registers itself through a central ContentRegistry and communicates via a decoupled EventManager.

Key design properties:

Property How it's realized
Extensibility Plugins are shared libs discovered at runtime; everything user-facing is registered through ContentRegistry
Decoupling Components never call each other directly — they post/subscribe to typed events via EventManager
Provider abstraction All features operate on a prv::Provider byte source (file, disk, memory, GDB, remote…)
Portability One codebase targets Windows, macOS, Linux, FreeBSD, and WebAssembly (Emscripten)
Resilience Crash handlers capture stack traces, save a crash-backup project, and run cleanup hooks
GUI Dear ImGui (immediate-mode) rendered via OpenGL 3.0+

The codebase analyzed here is commit 8a6be85 (2026-05-30): ~796 files, ~1.05 M characters of source, 474 code files, organized into a core library, a GUI host, an updater, a Windows forwarder, and ~13 plugins.


2. Architecture Overview

                        ┌─────────────────────────────────────────────┐
                        │                  Executables                 │
                        │                                              │
  Explorer / Terminal ─▶│  imhex.exe (forwarder, Windows only)         │
                        │      └─ launches ──▶ imhex-gui (main host)   │
                        │  imhex-updater  (standalone updater)         │
                        └───────────────────────┬──────────────────────┘
                                                 │
                  ┌──────────────────────────────▼───────────────────────────┐
                  │                  main/gui  (host process)                  │
                  │  • main(): locale, TaskManager, crash handlers, native    │
                  │    init, messaging, CLI dispatch, then runImHex()          │
                  │  • Window: GLFW + OpenGL + Dear ImGui render loop          │
                  └──────────────────────────────┬───────────────────────────┘
                                                 │ links
                  ┌──────────────────────────────▼───────────────────────────┐
                  │              lib/libimhex  (the SDK / runtime)             │
                  │                                                            │
                  │   PluginManager   ContentRegistry   EventManager          │
                  │   TaskManager     ImHexApi          ShortcutManager        │
                  │   ThemeManager    LayoutManager     WorkspaceManager       │
                  │   LocalizationMgr AchievementMgr    TutorialManager        │
                  │   ProjectFile     prv::Provider     MCP server             │
                  └───┬───────────┬───────────┬───────────┬───────────┬────────┘
                      │ loads     │ loads      │ loads      │ loads     │ loads
                  ┌───▼───┐  ┌────▼────┐  ┌────▼────┐  ┌────▼────┐  ┌───▼─────┐
                  │builtin│  │ hashes  │  │disassem.│  │  yara   │  │ ...etc  │
                  │plugin │  │ plugin  │  │ plugin  │  │ plugin  │  │ plugins │
                  └───────┘  └─────────┘  └─────────┘  └─────────┘  └─────────┘

The flow at runtime:

  1. The host (main/gui) starts, sets up the TaskManager, crash handlers, and native window, then asks PluginManager to load libraries and plugins.
  2. Each plugin, on init, registers content (views, tools, data inspector rows, hashes, providers, menu items, settings, pattern functions, …) into the ContentRegistry, and subscribes to events it cares about.
  3. The render loop draws registered views with Dear ImGui every frame, dispatches shortcuts, and posts frame events.
  4. Features interact only through events (EventManager) and the shared provider byte source — never by direct cross-plugin calls.

Note

This is a classic registry + event-bus plugin architecture. Adding a feature means writing a plugin that registers entries and subscribes to events — no core changes required. That is the single most important fact for anyone extending ImHex.


3. Repository Structure

Path Purpose
main/gui/ The GUI host executable: main(), window/render loop, init tasks, crash handlers, messaging, CLI entry
main/forwarder/ Windows-only launcher that manages the console window and forwards stdio to imhex-gui
main/updater/ Standalone cross-platform updater executable
lib/libimhex/ The SDK: public headers (include/hex/...) + implementation (source/...). The LGPL plugin interface
lib/trace/ Stack-trace / exception-tracing helper library
plugins/builtin/ The default plugin — most core ImHex functionality (views, tools, providers, CLI)
plugins/ui/ Shared UI widgets and the pattern text editor (LGPL, so plugins can reuse it)
plugins/hashes/ Hashing algorithms and the Hashes view
plugins/disassembler/ Capstone-based disassembler and views
plugins/yara_rules/ YARA scanning integration
plugins/diffing/ Data diffing algorithms and view
plugins/decompress/ Decompression support for the data processor
plugins/visualizers/ Pattern Language visualizers (images, audio, 3D, …)
plugins/remote/ Remote (SSH/SFTP) and network providers
plugins/fonts/ Font loading and management
plugins/windows/ Windows-specific integrations
plugins/script_loader/ Loads .NET (C#) and C scripts as content
cmake/ Build modules, the plugin SDK template, toolchain helpers
dist/ Packaging, dependency installer scripts, compiling guides, vcpkg manifest
resources/ Logos, banners, sample projects
tests/ Unit/integration tests (common, helpers, algorithms, plugins)

Each plugin follows the same internal shape: source/ (implementation), include/ (its own headers), and romfs/ (embedded resources: localization lang/, themes, shaders, MCP tool definitions, etc.) baked into the binary via a ROM-filesystem mechanism.


4. Process Model & Startup

Executables

ImHex ships three executables:

  • imhex-gui — the real application (the host + plugins).
  • imhex (Windows forwarder) — works around a Windows limitation: a GUI app launched from Explorer would otherwise get a stray console window, while a console app would always allocate one. The forwarder calls FreeConsole() when launched from Explorer (hiding the console) and enables ANSI escape sequences when launched from a terminal, then spawns imhex-gui.exe, wiring stdio through pipes and a Job Object so the child dies with the parent. It sets __IMHEX_FORWARD_CONSOLE__=1 to tell the GUI to forward its console output.
  • imhex-updater — downloads and installs updates (see §16).

Note

The forwarder exists purely because Windows lacks a "console-like GUI app" subsystem. On macOS/Linux a single executable behaves correctly, so there is no forwarder there.

main() sequence (host)

From main/gui/source/main.cpp, startup runs in this order:

  1. setlocale(LC_ALL, "en_US.utf8").
  2. TaskManager::setMainThreadId(...) and name the main thread ("ImHex 🔍").
  3. crash::setupCrashHandlers() — install signal/exception handlers first, to catch early crashes.
  4. trace::enableExceptionCaptureForCurrentThread().
  5. Window::initNative() — platform window init.
  6. messaging::setupMessaging() — single-instance / inter-instance messaging.
  7. If argc > 1: disable the crash callback and run init::runCommandLine().
  8. Log version, commit, and OS/arch info (so user-submitted logs are useful).
  9. init::runImHex() — enter the render loop.

CLI dispatch

runCommandLine() (in main/gui/source/init/run/cli.cpp) loads plugin libraries and plugins (without initializing them), then calls hex::subcommands::processArguments(args). Subcommands are matched against the --long / -short names registered by each plugin via IMHEX_PLUGIN_SUBCOMMANDS. On Windows the raw UTF-16 command line is re-parsed with CommandLineToArgvW and converted to UTF-8. Plugins are intentionally not unloaded after CLI handling — some CLI commands configure plugin state and then let ImHex start normally.

Crash handling

main/gui/source/crash_handlers.cpp installs handlers for SIGSEGV, SIGILL, SIGABRT, SIGFPE (and SIGINT, SIGBUS where present); on Windows it uses SetUnhandledExceptionFilter mapping structured exceptions to the same path. On a crash it:

  • Posts EventAbnormalTermination so plugins can clean up.
  • Exports the current workspace and, if any provider is open, writes a crash_backup.hexproj to a writable config path.
  • Writes crash.json (pointing at the log file and the backup project).
  • Prints a demangled stack trace and runs exit tasks, then terminates.

The crash callback starts as a native message box (for very early failures) and is swapped to the file-saving handler once EventImHexStartupFinished fires.


5. The libimhex SDK

lib/libimhex is the LGPL library that both the host and every plugin link against. Public headers live under include/hex/. The major managers (all static "manager" classes, deliberately non-instantiable) are:

Class / namespace Responsibility
PluginManager Discover, load (load/loadLibraries), initialize, enable/disable, and unload plugins; expose plugin metadata and subcommands
ContentRegistry The registration surface for all extensible content (see §6)
EventManager Typed publish/subscribe event bus (see §7)
TaskManager Async/background/blocking task scheduling, deferred (doLater) calls, thread naming
ImHexApi Runtime facade: System, Provider, HexEditor, Bookmarks, etc.
ShortcutManager Global and view-local keyboard shortcuts, remapping, macOS mode
ThemeManager Load/apply themes, color & style handlers, accent color, export
LayoutManager Save/load/lock window layouts (ImGui docking state)
WorkspaceManager Create/switch/import/export workspaces
LocalizationManager (Lang/UnlocalizedString) Translation lookup; compile-time "..."_lang hashing
AchievementManager Achievement graph (requirements/visibility), progress persistence
TutorialManager Interactive tutorials (steps, highlights, message boxes)
ProjectFile Load/store .hexproj projects; per-provider and global handlers
prv::Provider Abstract byte source interface every feature reads/writes

Localization & UnlocalizedString

A recurring pattern: APIs take UnlocalizedString keys, not display text. ImHex resolves them through LocalizationManager at draw time. The _lang user-defined literal computes a hash at compile time for fast lookup. This is why plugin code is full of identifiers like hex.builtin.view.hex_editor.name — the human-readable strings live in each plugin's romfs/lang/*.json.

TaskManager

Tasks come in three flavors: foreground (shown in the footer task list), background (hidden), and blocking (modal). Task objects support progress (update/setMaxValue), cooperative interruption (interrupt/shouldInterrupt), and exception capture. doLater and doLaterOnce defer work to the start of the next frame on the main thread — essential because the GUI is immediate-mode and most state must be touched on the main thread.

Important

When extending ImHex, never block the render thread. Long operations belong in TaskManager::createTask(...); UI mutations from worker threads must be routed back via TaskManager::doLater(...).


6. The ContentRegistry: Extension Surface

ContentRegistry (implemented in lib/libimhex/source/api/content_registry.cpp) is the single namespace through which plugins add functionality. Each sub-namespace owns a registry of entries plus add(...) functions. The full set:

Namespace Registers…
Settings Setting categories, sub-categories, and widgets; onChange/onSave hooks; persistence to settings.json
CommandPalette Command-palette entries and handlers
PatternLanguage Pattern Language functions, dangerous functions, types, pragmas, and (inline) visualizers; owns the per-provider runtime
Views Dockable windows (the UI views), plus the fullscreen view slot
Tools Entries in the Tools panel
DataInspector Data Inspector row types (generator + optional editor)
DataProcessor Node types for the node graph
UserInterface Main-menu items, toolbar items, sidebar items, footer items, welcome-screen entries, title-bar buttons, taskbar menu items
Provider Data-source provider types (creation functions + names)
DataFormatter "Copy as / export as" formatters and find-result exporters
FileTypeHandler Handlers keyed by file extension
HexEditor Data visualizers and minimap visualizers for the hex grid
Diffing Diff algorithms
Hashes Hash algorithm implementations
BackgroundServices Long-running background services
CommunicationInterface External communication endpoints
DataInformation Data Information analyzers (entropy, distribution, …)
Disassemblers Disassembler backends
Experiments Experimental, opt-in features
Reports Report generators

Registration is uniform: a plugin calls e.g. ContentRegistry::Hashes::add(std::make_unique<MyHash>()) or ContentRegistry::Views::add(...) during its init function. Many add calls log::debug(...) the registration, so running with --verbose prints a complete inventory of what each plugin contributed — invaluable for debugging missing content.

Settings widgets

The settings system ships reusable widget types: Checkbox, SliderInteger, SliderFloat, SliderDataSize, ColorPicker, DropDown, TextBox, FilePicker, Label, and Spacer. Each implements draw/load/store against nlohmann::json. Settings persist to settings.json in a config path; on the Web build they persist to browser localStorage instead.

The Pattern Language runtime

ContentRegistry::PatternLanguage owns a per-provider pl::PatternLanguage runtime. On creation it wires the runtime's data source to the provider's read/write, sets include paths from the includes/patterns data folders, registers all plugin-contributed functions/types/pragmas, and defines __IMHEX__ and __IMHEX_VERSION__. "Dangerous" functions (those with side effects beyond reading) are registered separately and gated.

Caution

Pattern Language dangerous functions can perform side-effectful operations. They are registered via addDangerousFunction and treated distinctly from pure functions. Be deliberate about which capabilities a plugin exposes to user-supplied pattern code.


7. The Event System

EventManager is a typed publish/subscribe bus. Events are declared with the EVENT_DEF(Name, ParamTypes...) macro (or EVENT_DEF_NO_LOG for high-frequency events like per-frame ticks), which generates a struct with static subscribe/unsubscribe/post methods. Event identity is a compile-time FNV hash of the event name; handlers are stored in a multimap keyed by that id.

Conventions:

  • Events live in category headers under include/hex/api/events/ (events_gui.hpp, events_lifecycle.hpp, events_provider.hpp, events_interaction.hpp) — never declared inline elsewhere.
  • Events (EventXxx) broadcast that something happened; Requests (RequestXxx) ask something to happen.
  • Subscriptions can be token-based (pass a void* owner token) so a plugin can unsubscribe all its handlers at unload.
  • In release builds, event callbacks are wrapped in try/catch and log the exception (then rethrow); in debug builds they run unguarded for easier debugging.

Representative events (non-exhaustive):

Category Examples
Lifecycle EventImHexStartupFinished, EventImHexClosing, EventFirstLaunch, EventImHexUpdated, EventAbnormalTermination, EventCrashRecovered
Provider EventProviderCreated, EventProviderOpened, EventProviderChanged, EventProviderClosed, EventProviderDataModified, EventProviderDirtied
Interaction EventDataChanged, EventRegionSelected, EventBookmarkCreated, EventPatchCreated, EventPatternExecuted, EventFileDropped
GUI EventViewOpened, EventDPIChanged, EventWindowClosing, EventFrameBegin/EventFrameEnd, EventThemeChanged
Requests RequestOpenFile, RequestOpenWindow, RequestCreateProvider, RequestHexEditorSelectionChange, RequestSetPatternLanguageCode, RequestCloseImHex, RequestRestartImHex

Note

The in-source documentation candidly flags several events as unused (FIXME: this event is unused and should be scrapped). Treat the events_*.hpp headers as the source of truth, but don't assume every declared event has a live publisher.

Example: how a feature wires up

The introduction tutorial (plugins/builtin/.../tutorials/introduction.cpp) illustrates the idioms: it builds a TutorialManager tutorial with steps that highlight named UI elements (by their localized window names), and advances steps by subscribing to events like EventProviderOpened and EventViewOpened. UI elements are addressed by stable string IDs, and pattern code is injected with RequestSetPatternLanguageCode::post(...) followed by RequestTriggerPatternEvaluation::post().


8. Plugins Inventory

Plugin Role Notes
builtin The bulk of ImHex: hex editor view, data inspector, find/replace, bookmarks, patches, providers, the CLI subcommands, settings, tutorials Largest plugin; author WerWolv
ui Shared UI widgets + pattern text editor LGPL so other (incl. proprietary) plugins can reuse it
hashes All hash algorithms + Hashes view See User Guide for the full algorithm list
disassembler Capstone disassembler + views Pluggable architectures
yara_rules YARA scanning Rules from yara/ data folder + Content Store
diffing Data diffing (edit-distance based) Table + highlight diff views
decompress Decompression nodes Feeds the data processor
visualizers Pattern visualizers Images, audio, 3D models, coordinates, shaders
remote Remote/network providers SSH/SFTP, UDP, etc.
fonts Font loading Bundled and custom fonts
windows Windows-only integrations Taskbar progress, etc.
script_loader Load C# (.NET) and C scripts as content See §12

Plugins are distinguished as library plugins (shared infrastructure like ui, loaded via loadLibraries) versus feature plugins (loaded via load). A plugin exports a fixed set of C functions (getPluginName, initializePlugin, getSubCommands, getFeatures, getCompatibleVersion, …) that PluginManager resolves by symbol — defined for you by the IMHEX_PLUGIN_SETUP macros.


9. Security & Licensing

Licensing

Component License Why
ImHex (most of it) GPLv2-only Copyleft for the application
lib/libimhex LGPLv2.1 Lets proprietary plugins link the SDK
plugins/ui LGPLv2.1 Lets proprietary plugins reuse UI elements
plugins/ui/.../text_editor MIT (BalazsJako) Vendored ImGuiColorTextEdit

Code signing

Windows builds are signed via SignPath.io (certificate by the SignPath Foundation). ImHex's stated policy: it "will not transfer any information to other networked systems unless specifically requested by the user or the person installing or operating it." Push access to the repository is limited to a small named set of maintainers.

Network behavior

ImHex only reaches the network on explicit user action. Network touchpoints to be aware of when assessing or sandboxing it:

  • Updater — fetches release metadata from the GitHub API and downloads artifacts.
  • Content Store — downloads patterns/magic/rules/themes from the ImHex-Patterns repo.
  • Remote providers — SSH/SFTP, UDP, GDB, process memory.
  • Tools — the HTTP Requests and TCP Client/Server tools, the Wikipedia tool, and the --save-editor gist command (GitHub Gist API).

Warning

ImHex is a reverse-engineering tool routinely pointed at untrusted binaries and malware. Run it in an isolated VM when analyzing hostile samples. Note these capability surfaces:

  • Pattern Language dangerous functions and scripts (C#/.NET, C) can execute side-effectful logic — only run patterns/scripts you trust. YARA-style sources can be embedded in downloadable content.
  • Process Memory / GDB / Raw Disk providers touch live system state and may need elevated privileges.
  • The updater runs platform installers with elevated privileges (msiexec, sudo, zenity password prompts) and on macOS uses AppleScript with administrator privileges. Prefer OS package managers in managed environments and pin the update channel.

MCP exposure

The MCP server binds an internal loopback port (19743) for a local stdio bridge (imhex --mcp), not a remote service. Still, treat it as a control channel: anything able to drive that bridge can drive ImHex.


10. Building & Compiling

Toolchain requirements

Requirement Detail
Compiler GCC or Clang with C++23 support (latest GCC for Windows/Linux, latest LLVM Clang for macOS)
CMake ≥ 3.20
Generator Ninja (default in presets)
Submodules Many deps are bundled as git submodules

Important

MSVC and AppleClang are NOT supported — both lack C++23 features ImHex relies on. Use GCC/LLVM Clang even on Windows/macOS. Clone with --recurse-submodules; non-bundled dependencies install via the scripts in /dist.

CMake presets

CMakePresets.json defines configure presets (CMake ≥ 3.20, Ninja, Debug by default):

Preset Purpose
base Hidden base: GCC/G++, IMHEX_PATTERNS_PULL_MASTER=ON, USE_SYSTEM_CAPSTONE=ON, IMHEX_USE_DEFAULT_BUILD_SETTINGS=ON, install prefix ./install
x86_64 Standard x86-64 build (inherits base)
xcode macOS Xcode generator with Clang overrides
vs2022 / vs2022-x86 Visual Studio environments using the vcpkg toolchain (VCPKG_MANIFEST_DIR=dist)

A typical Linux/macOS build:

git clone --recurse-submodules https://github.com/WerWolv/ImHex
cd ImHex
cmake --preset x86_64
cmake --build build/x86_64 --target imhex_all

The imhex_all build target is wired in the x86_64 build preset. Per-platform instructions live in dist/compiling/{windows,linux,macos}.md.

Notable CMake options

Option Effect
IMHEX_BUNDLE_PLUGIN_SDK=ON Install the plugin SDK (for out-of-tree plugin dev)
USE_SYSTEM_CAPSTONE=ON Link the system Capstone instead of bundled
IMHEX_PATTERNS_PULL_MASTER=ON Pull the latest patterns database during build
IMHEX_USE_DEFAULT_BUILD_SETTINGS=ON Apply the project's standard build flags

11. Plugin Development

ImHex is built to be extended out-of-tree. The workflow:

  1. Start from the ImHex Plugin Template.
  2. Get the SDK. Build ImHex with the SDK bundled and install it:
    cmake -G Ninja -DIMHEX_BUNDLE_PLUGIN_SDK=ON -B build
    cd build
    DESTDIR=install ninja install
    
    The SDK lands at install/usr/local/share/imhex/sdk. Point the IMHEX_SDK_PATH variable at that absolute path.
  3. In CI, use the imhex-download-sdk action to fetch a matching SDK automatically.
  4. In your plugin's init, register content via ContentRegistry::*::add(...) and subscribe to events via EventXxx::subscribe(...).
  5. Validate the built plugin before shipping:
    imhex --validate-plugin /path/to/your_plugin.hexplug
    
    This checks the plugin loads, has a valid setup block, and initializes.

Important

A plugin must be built against the same ImHex version's SDK. The getCompatibleVersion export lets PluginManager reject mismatched plugins — which is exactly what --validate-plugin surfaces ("make sure the plugin was built using the SDK of this ImHex version"). A plugin missing its IMHEX_PLUGIN_SETUP/IMHEX_LIBRARY_SETUP block is reported as invalid.

Plugins live in the plugins data/plugin folder at runtime; --plugins <path> adds extra load paths, and --plugins with no argument lists what's loaded.


12. Scripting (C# / .NET and C)

The script_loader plugin lets you add content using compiled scripts instead of full C++ plugins:

  • .NET / C# — plugins/script_loader/support/dotnet builds an AssemblyLoader and a managed ImHexLibrary; CMake compiles the C# projects (dotnet build ... -c Release) into DLLs installed alongside the plugins. Project templates live in plugins/script_loader/templates/CSharp (ImHexLibrary, ImHexScript).
  • C — plugins/script_loader/support/c exposes a versioned C script API (script_api/v1: bookmarks, logger, mem, ui) compiled into a c_api object library linked against libimhex and ui.

This is the lighter-weight extension path: write a script in C# or C against the provided API rather than maintaining a native plugin and SDK build.

Caution

Scripts execute as native/managed code inside the ImHex process — they are not sandboxed. Only load scripts from sources you trust, exactly as you would a plugin.


13. The MCP Server

ImHex exposes a Model Context Protocol server so AI assistants can drive it.

Topology

  • The server lives in libimhex (lib/libimhex/source/mcp/server.cpp, header include/hex/mcp/server.hpp) and runs inside ImHex on the internal loopback port 19743 (Server::McpInternalPort).
  • The client/bridge is launched by imhex --mcp (handled by the builtin plugin's handleMCPCommand), which runs an mcp::Client over std::cin/ std::cout — the stdio transport AI hosts expect — relaying to the internal server.

Protocol

The server speaks JSON-RPC 2.0 and implements MCP protocol version 2025-06-18. The JsonRpc class parses single and batched requests, validates the envelope (jsonrpc == "2.0", string method), and maps standard JSON-RPC error codes (ParseError -32700, InvalidRequest -32600, MethodNotFound -32601, InvalidParams -32602, InternalError -32603).

initialize returns server info (ImHex + the running version) and advertises a tools capability. Methods are dispatched by suffix:

  • notifications/* → notification handlers (e.g. initialized marks connected).
  • */list → enumerate registered primitives of a type and their capabilities.
  • */call → invoke a named primitive (a "tool") with arguments.

Tools (primitives) are registered with Server::addPrimitive(type, capabilities, function), where capabilities is a JSON description carrying the tool's name. The builtin plugin ships MCP tool definitions under plugins/builtin/romfs/mcp/tools.

Note

Because tools are registered the same way other content is, plugins can add MCP tools. The response framing appends a 0x00 terminator byte per message over the socket transport — relevant if you implement a custom bridge.


14. Configuration Reference

Settings store

Settings are a single JSON document persisted to settings.json in a config path (or browser localStorage on the Web build). Internally each setting is addressed by category / name (both unlocalized keys). Plugins register settings with ContentRegistry::Settings::add(category, subCategory, name, widget) and react with onChange/onSave callbacks. Defaults are materialized lazily when a setting is first read.

Setting categories

The builtin plugin registers these top-level categories (display names from localization):

Key Display name
hex.builtin.setting.general General
hex.builtin.setting.interface Interface
hex.builtin.setting.hex_editor Hex Editor
hex.builtin.setting.pattern_editor Pattern Editor
hex.builtin.setting.folders Folders
hex.builtin.setting.proxy Proxy
hex.builtin.setting.toolbar Toolbar
hex.builtin.setting.shortcuts Shortcuts
hex.builtin.setting.plugins Plugins
hex.builtin.setting.loaded_plugins Plugins to be loaded
hex.builtin.setting.experiments Experiments
hex.builtin.setting.imhex ImHex (internal/meta)

Note

Reading a setting in code: ContentRegistry::Settings::read<T>(category, name, default). For example, the builtin plugin reads hex.builtin.setting.general / hex.builtin.setting.general.debug_mode_enabled at startup to decide whether to enable debug mode (always on in DEBUG builds).

Reset

imhex --reset-settings clears and re-stores settings (requires typing YES I AM ABSOLUTELY SURE). Deleting settings.json has the same effect.


15. Filesystem & Path Resolution

ImHex resolves directories through hex::paths (default_paths.{hpp,cpp}). Three path classes exist:

  • ConfigPath — config-home-rooted (config, recent, updates).
  • DataPath — data-home-rooted, can include system folders (patterns, magic, themes, scripts, …).
  • PluginPath — plugin/library directories.

Each exposes all(), read() (existing dirs only), and write() (existing & writable). The base directories per platform:

Platform Config Data
Windows (installed) %LOCALAPPDATA%\imhex %LOCALAPPDATA%\imhex
Windows (portable) next to the executable next to the executable
macOS ~/Library/Application Support/imhex same (+ executable dir as system folder)
Linux/Web $XDG_CONFIG_HOME/imhex $XDG_DATA_HOME/imhex + $XDG_DATA_DIRS

Resolution rules worth knowing for packaging:

  • Portable Windows deliberately skips %LOCALAPPDATA% and uses only the executable directory.
  • Linux AppImage restricts plugin loading to inside the AppImage ($APPDIR/usr/lib/imhex).
  • A compile-time SYSTEM_PLUGINS_LOCATION adds a system plugin dir on Linux.
  • The directory of a loaded project file and any additional folders configured by the user are added to the data search path.

Named subfolders (postfixes) are listed in the User Guide; the canonical list is the 22-entry hex::paths::All array (Config, Recent, Updates, Libraries, Plugins, Patterns, PatternsInclude, Magic, Yara, YaraAdvancedAnalysis, Backups, Resources, Constants, Encodings, Logs, Scripts, Inspectors, Themes, Nodes, Layouts, Workspaces, Disassemblers).

Tip

Because most data paths are multi-rooted (user dir + system dirs), packagers can ship read-only content (patterns, magic, themes) in a system data dir while users add their own in the writable home dir. read() merges them; write() only ever targets writable locations.


16. Operations

Logging

Logs are written to the logs data folder and the console. --verbose / -v enables debug logging (which, among other things, prints every ContentRegistry registration and posted event). --debug-mode enables additional debugging features. Debug builds enable debug mode automatically and show a warning banner (suppressible with NO_DEBUG_BANNER).

Caution

A known data race exists in log::debug() when debug logging is disabled (reported upstream). If you build tooling around ImHex logs under heavy multithreaded load, be aware of it.

Updates (the updater executable)

imhex-updater <stable|nightly> is invoked by ImHex to self-update. It:

  1. Queries the GitHub releases API and selects the release matching the channel (stable releases have target_commitish starting releases/v; nightly is tagged nightly).
  2. Picks the artifact for the current OS+arch by filename suffix — e.g. Windows-x86_64.msi, macOS-arm64.dmg, Ubuntu-24.04-x86_64.deb, Fedora-42-x86_64.rpm, ArchLinux-x86_64.pkg.tar.zst, x86_64.AppImage, x86_64.flatpak, x86_64.snap.
  3. Downloads to a writable updates path and runs the platform installer.

Install commands by type:

Artifact Command
.msi msiexec /i "<file>" /qb
.dmg mounts, copies the .app to /Applications via AppleScript admin
.deb sudo apt install --fix-broken (via zenity password)
.rpm sudo rpm -i
.pkg.tar.zst sudo pacman -U
.AppImage / .flatpak / .snap copy / flatpak install / snap install --dangerous

If the install type can't be auto-updated, the updater opens the latest release page in a browser for a manual update. Portable Windows is intentionally not auto-updated via .msi.

Backup & recovery

  • Crash backup: crash_backup.hexproj + crash.json written to a config path on crash. After a crash, reopen the backup project to recover work.
  • Backups folder: the backups data path holds additional backups.
  • Workspaces are exported on crash so the layout survives.

Single-instance messaging

messaging::setupMessaging() enables sending commands (e.g. "open this file") to an already-running ImHex instance rather than spawning a new one. Cross-instance payloads arrive as EventNativeMessageReceived.


17. Code Quality & Conventions

Observed patterns across the codebase:

  • Modern C++23 throughout — concepts, ranges, std::optional, <=>, consteval literals, std::source_location, designated initializers.
  • AutoReset<T> wrappers hold global registry state so it can be cleanly reset (important for the Web build and for plugin reloads).
  • Static "manager" classes with deleted constructors as the API style; internal state lives in impl namespaces exposed through accessor functions.
  • PerProvider<T> binds state to the active provider (e.g. the Pattern Language runtime is per-provider).
  • Strict separation of display text from logic via UnlocalizedString.
  • Defensive event dispatch (try/catch + log in release) and cooperative task interruption rather than thread cancellation.
  • ROM-FS embedded resources (romfs::get(...)) keep assets in the binary.
  • Honest in-source TODOs/FIXMEs — many event docs flag dead code for removal, which is good signal for contributors.
  • Heavy use of [[nodiscard]] on getters.

Naming: hex:: root namespace; plugins under hex::plugin::<name>; providers under hex::prv; pattern-language types under pl::; the bundled wolv:: utility library (io/fs/utils/net/types) is used pervasively.


18. Testing

Tests live under tests/ and are wired through CMake:

Suite Path Focus
Common tests/common Shared test harness / entry point
Helpers tests/helpers Helper-function tests
Algorithms tests/algorithms Algorithmic correctness
Plugins tests/plugins Plugin-level tests

The harness (tests/common/source/main.cpp) runs a single named test, supports expected-failure tests (shouldFail inverts the result), and tears down via TaskManager::exit(), EventImHexClosing, EventManager::clear(), and PluginManager::unload(). Tests are declared with the TEST_SEQUENCE(name) macro and assert with TEST_ASSERT / TEST_SUCCESS.

Example — the builtin provider read/write test (plugins/builtin/tests/source/main.cpp) initializes the Built-in plugin, creates a mem_file provider, and asserts resize/read/write/zero-fill semantics, plus an expected-failure test that resizing to -1 returns false. New plugin tests are added to the AVAILABLE_TESTS list in plugins/builtin/tests/CMakeLists.txt and registered as CTest cases.

set(AVAILABLE_TESTS
    Providers/ReadWrite
    Providers/InvalidResize
)

19. Potential Improvements & Tech Debt

Drawn directly from in-source FIXME/TODO markers and community-reported issues at this commit.

Flagged in source

  • Dead events — several events are documented as unused and slated for removal: EventFileLoaded, EventPatternEditorChanged, EventStoreContentDownloaded, EventStoreContentRemoved, EventAnySettingChanged, RequestAddExitTask. Cleaning these would reduce API surface confusion.
  • Naming inconsistencies — MovePerProviderData lacks the Request prefix its siblings use; EventProviderClosing behaves like a request (it carries a mutable bool*) and is noted as belonging in the requests section.
  • EventImHexUpdated is flagged as misleadingly named (it fires every startup with previous/current versions, not only on update).

Community-reported (open issues at this commit)

Area Issue
Pattern editor Selection desync / skipping after edits (#2748, #2749)
Pattern eval Crash on pattern with pointer-to-struct (#2744)
Hashing CRC16 broken after restart (#2739)
CLI Opening a file from the command line yields an empty layout (#2742, #2715)
Visualizers Bitmap visualizer retains stale section data (#2743)
Logging Data race in log::debug() when debug logging is off (#2751)
Endianness Big-endian DOS date/time broken (#2723)
Paths Default paths not created if missing (#2726)
I/O GVFS SMB shares truncate files to zero bytes (#2660)

Architectural opportunities

  • The builtin plugin is very large and mixes many concerns; splitting cohesive feature groups (CLI, providers, views) into focused plugins would improve modularity and build times.
  • The dual GPU/NoGPU and native/Web/WASM matrix means OS-conditional code is spread across modules; consolidating platform shims behind the wolv/paths abstractions would reduce #if defined(OS_*) density.
  • Settings are untyped JSON addressed by string keys; a typed settings schema would catch key typos at compile time.

20. Quick Reference

Build

git clone --recurse-submodules https://github.com/WerWolv/ImHex
cd ImHex
cmake --preset x86_64          # Ninja, GCC, Debug, USE_SYSTEM_CAPSTONE=ON
cmake --build build/x86_64 --target imhex_all

Plugin SDK

cmake -G Ninja -DIMHEX_BUNDLE_PLUGIN_SDK=ON -B build
cd build && DESTDIR=install ninja install
# SDK at install/usr/local/share/imhex/sdk  → set IMHEX_SDK_PATH
imhex --validate-plugin your_plugin.hexplug

Key facts

Item Value
Language / standard C++23
Supported compilers GCC, LLVM Clang (not MSVC/AppleClang)
Build system CMake ≥ 3.20 + Ninja
GUI Dear ImGui over OpenGL 3.0+
Disassembly engine Capstone
MCP internal port 19743 (loopback), JSON-RPC 2.0, protocol 2025-06-18
Crash backup crash_backup.hexproj + crash.json in config dir
Overall license GPLv2 (libimhex + ui: LGPLv2.1)
Maintainer WerWolv (+ small core team)

Core managers (libimhex)

PluginManager · ContentRegistry · EventManager · TaskManager · ImHexApi · ShortcutManager · ThemeManager · LayoutManager · WorkspaceManager · LocalizationManager · AchievementManager · TutorialManager · ProjectFile · prv::Provider

Key dependencies

Dear ImGui (UI) · ImPlot (plots) · ImNodes (data processor) · ImGuiColorTextEdit (pattern editor) · nlohmann/json · fmt · Capstone (disassembly) · YARA · edlib (diffing) · HashLibPlus (hashing) · miniaudio (audio) · nativefiledialog-extended · microtar · xdgpp · the wolv utility library · the standalone Pattern Language runtime.