This page is the human-friendly entry point for understanding how Draxul is put together.
Use it when you want to answer:
- where a change probably belongs
- how the main libraries relate to each other
- which generated diagrams to look at first
- which validation flows are most relevant after a change
If you only want the shortest path to orientation:
- Read the top-level layout in README.md.
- Read the maintained high-level dependency shape below, then use the generated deps.svg for exact edges from its last documentation build.
- Look at the class diagram in draxul_classes.svg.
- Generate local API docs with
python scripts/build_docs.py --api-only, then opendocs/api/index.html. - Check active follow-up items in kanban/pending/.
- Use the snapshot and smoke flows through do.py when touching UI or rendering.
CMakeLists.txt files are authoritative. At a useful orientation level, the current
target graph has four layers:
draxul executable
├── draxul-app
├── draxul-client / draxul-server
├── draxul-markdown-host
├── draxul-kanban
└── optional products: draxul-megacity / SatView + ScoreView + PCBView plugins
│
├── product-specific model, scene, service, and renderer targets
└── shared host / renderer / UI infrastructure
│
├── draxul-host (including RemoteTerminalHost) /
│ draxul-runtime-support / draxul-render-test
├── draxul-config / draxul-gui / draxul-ui / draxul-nanovg
└── draxul-http / draxul-font / draxul-grid / draxul-nvim /
draxul-renderer / draxul-window / draxul-imgui-core
│
└── narrow foundations: draxul-types / draxul-performance /
draxul-agent / draxul-session-model / draxul-bmp / draxul-host-identity /
draxul-terminal-core / draxul-terminal-process
This is a dependency shape, not a promise that every target in one row links every
target below it. Consult the target's CMakeLists.txt for exact public/private edges.
In particular, draxul-app deliberately has no source-level dependency on the
SatView or ScoreView product runtimes; the executable discovers their modules.
Top-level orchestration only.
Owns:
- process startup/shutdown
- wiring between window, renderer, text service, grid, and Neovim RPC
- the
ITopologyMutationRouteadapter boundary: local controller mutations and server-backed command translation share one App-facing operation surface - smoke/render-test entry points
Good place for:
- app lifecycle
- top-level CLI/test harness behavior
- integration glue
Bad place for:
- backend-specific renderer logic
- low-level font logic
- grid mutation rules
Shared low-level data types and cross-module contracts.
Owns:
- shared structs
- event types
- highlight/logging/support types
- canonical small helpers shared across the tree:
string_util.h(trim/trim_view/ascii_lower/describe_text_for_log),input_types.hmodifier normalization (normalize_modifiers/has_only_modifiers, lock-key aware),process_util.h(Windows arg quoting,spawn_detached,resolve_exec_paths,build_child_environment,current_unix_time_ms,process_start_token), andruntime_path.huser directories (user_config_dir/user_data_dir/user_cache_dir)
Good place for:
- narrow shared contracts
- POD-like data passed between modules
draxul-types (headers + static lib) also ships with the draxul-plugin-sdk
install component so out-of-tree product builds can link it.
Compiled BMP I/O, runtime performance collection, and host/provider identity are
deliberately not owned here. They live in the narrowly named draxul-bmp,
draxul-performance, and draxul-host-identity targets so changing those facilities
does not rebuild or extend the universal value-type archive.
| Directory | Ownership |
|---|---|
sdk/ |
Installable, versioned native plugin C ABI and the dependency-free Draxul::PluginSDK CMake target |
plugins/support/imgui/ |
Product-owned optional ImGui Vulkan/Metal encoder, the shared PluginImGuiContext lifecycle and ImGuiInputBridge event routing, and public UI-style service client, linked inside native plugin modules and never exposed across the ABI |
libs/draxul-imgui-core/ |
The single SDL-scancode-to-ImGuiKey table and IImGuiHost backend interface; leaf-narrow (links only ImGui + SDL headers) so core UI, the renderer, and plugin support all consume the same definitions (Draxul::PluginSupport::ImGuiCore) |
libs/draxul-plugin-support/ |
Same-build plugin leaves: C-ABI path/storage wrappers, the plugin adapter shell (Draxul::PluginSupport::Adapter — result factories, config parse, pane-state persistence, action registrar, kApi assembly; its header-only core draxul/plugin_adapter.h ships with the SDK install component), product lifecycle/viewport vocabulary, backend-neutral render contracts, Vulkan resource ownership incl. the shared adapter VMA allocator, the HDR/MSAA scene scaffolding (Draxul::PluginSupport::VulkanResources — attachments, the per-format MSAA probe, shader loading, immediate image upload, and HdrScenePipeline, which owns the one set of scene/tone-map subpass dependency masks both 3D products use), the camera key-latch and drag-inertia layer (Draxul::PluginSupport::CameraInput), explicit-path TOML documents, and tooltip layout; exports only Draxul::PluginSupport::* targets |
libs/draxul-performance/ |
Runtime timing collection and the PERF_MEASURE instrumentation API |
libs/draxul-bmp/ |
RGBA frame BMP read/write only; depends on frame value types and performance support |
libs/draxul-host-identity/ |
Neutral HostKind identity/parsing contract shared by host and runtime APIs |
libs/draxul-plugin/ |
Refreshable manifest discovery, immutable generation shadow staging, platform dynamic loading, ABI/identity validation, and active/retired module residency; consumes the public SDK but does not own it |
libs/draxul-agent/ |
Neutral agent identity/profile/runtime values plus bundled, versioned terminal-status and process-discovery evaluators |
libs/draxul-session-model/ |
Renderer-free durable Session/Space/tab/pane snapshot values, validation, versioned TOML codec, and transactional file replacement shared by the app and server |
libs/draxul-control/ |
Versioned, authenticated local Session control transport and client, plus the cancellable framed local-stream primitive used by persistent Session delivery. Its public facade owns request dispatch, compatibility error mapping, and bounded diagnostic snapshots; private common sources own framing, absolute deadlines, metadata caching, and typed stage/native failures, while CMake selects exactly one current-user-only backend (Windows named pipes or POSIX Unix-domain sockets). Diagnostics retain attempts, listener occupancy, bounded method/failure buckets, and queue/dispatch/response timing without exposing backend handles or native error types; white-box access is limited to the test-only draxul-control-test-internals target. |
libs/draxul-protocol/ |
Renderer- and transport-neutral server hello/status, versioned topology and sanitized agent-projection values, terminal pane/snapshot/delta/controller/clipboard/scrollback values, the bounded session.poll request/response contract, and the session-stream-v1 open/update/event/heartbeat envelopes and negotiated budgets; also the single topology→session layout conversion (topology_tab_to_layout in topology_layout.h, agent identity preserved), the shared topology traversal (find_space/find_tab/find_pane/find_node), topology_id_serial, and the split-ratio bounds constants used by both the server (reject) and app (clamp) sides |
libs/draxul-client/ |
Singleton discovery/launch/status/shutdown plus renderer-free remote-terminal and sanitized-agent delivery, and TopologyProjection, which owns remote/local Space-tab-pane identities, stable leaf/split projection, structural signatures, divider-node mapping, and topology command activation bookkeeping behind the app's thin controller/PaneManager adapters. RemoteSessionCoordinator owns terminal registrations, commands, recovery, visibility generations, projection mailboxes, and coalesced UI wakes; it prefers one session-stream-v1 connection, falls back to one recurring session.poll worker, and uses the Phase-1 per-channel workers only for older servers. Stream/poll batches externally feed topology and agents while one coordinator thread owns terminal cursors and projections. The library also owns the scrollback-page client, attach-latency metric, headless probe API, ServerControlChannel (the one control-plane envelope + transient-error/epoch-refresh retry policy), and the RevisionPolledClient base shared by AgentClient/TopologyClient |
libs/draxul-server/ |
Headless server kernel, authoritative revisioned/idempotent topology service, Session-scoped agent discovery, sanitized status projection, profile-resolved managed-agent launch/restore, headless agent inspection/input/restart control, and epoch/runtime-pinned native-session reporting, server-owned periodic/graceful v4 Session checkpoint and cold restore, deterministic fake terminal plus a stable-ID registry of lazy real server-owned shell runtimes, semantic scrollback, per-terminal controller leases, sanitized transport metrics, bounded per-client terminal event queues, a bounded fair per-Session batch scheduler, and one kernel-wide asynchronous Session-stream listener with authenticated tickets, heartbeats, bounded per-UI writers, and off-state-thread connection reaping. server_kernel.h is the stable public façade; the grouped state/method inventory and state-thread, mutex, task, lease, generation, cache, and shutdown invariants live in private src/server_kernel_impl.h. Façade, client-lease, lifecycle/state-loop, and authenticated request-routing definitions are isolated in responsibility TUs without changing runtime ownership. ServerAgentService and other white-box collaborators remain private under src/; tests opt into them through draxul-server-test-internals. The target deliberately has no window, renderer, host, or product dependency. |
libs/draxul-terminal-core/ |
Renderer-, window-, and process-free VT state machine, semantic full/dirty/cell snapshots (including the shared full_grid_update snapshot→dirty expansion), terminal identity/limits, alternate-screen state, attributes, and reusable scrollback storage |
libs/draxul-terminal-process/ |
UI-free PTY/ConPTY process adapters owned by server terminal runtimes |
These targets must not depend on product modules. Configure-time checks in
cmake/CheckDependencyBoundaries.cmake enforce that direction and the direct
draxul-host dependencies needed by its public and implementation headers.
Mounted native products register their module, manifest, runtime payload,
product targets, and focused test targets through cmake/DraxulPlugins.cmake.
That file owns platform-neutral staging and accepts shared C++ dependencies only
through the explicit Draxul::PluginSupport::* allowlist. It also verifies that
the allowlisted leaves cannot reach broader core libraries. Root CMake can enable
a mounted plugin without knowing its shader names or packaging layout; removing
the plugin directory therefore cannot leave reverse product dependencies in
core. The shared C++ support is statically linked into a same-build plugin and
does not change the runtime boundary, which remains Draxul::PluginSDK's C ABI.
draxul-host privately consumes draxul-client for the RemoteTerminalHost
renderer adapter, including client-local viewport/selection/mouse/paste behavior.
The client-local terminal surface (selection, copy-on-select, copy mode, mouse
reporting hand-off, hyperlink activation, pixel→cell mapping) lives once in
TerminalSurfaceHostBase, which sits between GridHostBase and both
TerminalHostBase (hence LocalTerminalHost) and RemoteTerminalHost.
It also owns the generic PluginHost and its Vulkan/Metal render-pass adapters;
plugin modules remain dynamically linked and are never product dependencies of the
server. The spinning-triangle is the first module staged through the generic
registration contract. SatView, MegaCity/BioView, and ScoreView now use the same
strict contract and only consume their own targets, third-party targets, or the
named plugin-support leaves.
The process adapter, client, and server libraries remain free of host, window,
renderer, font, SDL, and product dependencies.
Shared shader code follows the same allowlist idea in a single directory:
shaders/include/ holds GLSL and MSL includes that any mounted product may
consume (currently the ACES tone-map curve). Products reach it through
draxul_shared_shader_includes() in cmake/DraxulPlugins.cmake, which returns
the include directory for glslc -I / xcrun metal -I and the file list for
add_custom_command(DEPENDS ...). Each shared include has a declarative
contract under shaders/contracts/, and tests/shader_abi_parity_tests.cpp
re-derives both language copies from source and asserts they match it.
SDL windowing and platform-facing input/display behavior.
Owns:
- window creation
- DPI/display queries
- event pump / wake behavior
- clipboard / IME / title / focus plumbing
Good place for:
- platform window behavior
- SDL event translation
Public renderer API plus Vulkan/Metal backends.
Owns:
- renderer implementation hierarchy (
IBaseRenderer→IGridRenderer) - shared renderer CPU-side state
- GPU upload/submission code
- frame capture for render snapshots
Renderer hierarchy:
IBaseRenderer ← swapchain, device, frame lifecycle, resize, typed render passes
└── IGridRenderer ← grid cells, atlas, cursor, overlay, font metrics
Good place for:
- draw/update behavior
- backend-specific GPU work
- readback/capture paths
- new render pass implementations (implement
IRenderPass::record(IRenderContext&))
The generic IBaseRenderer/IFrameContext/IRenderPass contract and typed
Vulkan/Metal render contexts live in libs/draxul-plugin-support; the renderer
implements that leaf contract but plugins do not inherit its window, swapchain,
grid, capture, or presentation dependencies.
Text pipeline and atlas management.
Owns:
- primary/fallback font loading
- shaping
- glyph cache / atlas population
- text service API
- the shared CPU cluster blit (
cluster_blit.h) used by tooltip rendering and the text-atlas builder (wide clusters advance two cells)
Good place for:
- fallback/font selection
- glyph rasterization
- color emoji support
The terminal cell model.
Owns:
- cell storage
- dirty tracking
- scroll/copy/clear behavior
Good place for:
- redraw correctness
- cell mutation rules
Embedded Neovim process, RPC, redraw parsing, and input encoding.
Owns:
- child process lifecycle
- msgpack-RPC transport
- UI event parsing
- keyboard/mouse/text input encoding
Good place for:
- Neovim API/event handling
- transport behavior
- input fidelity
| Directory | Ownership |
|---|---|
libs/draxul-http/ |
Cross-platform HTTP transport (WinHTTP on Windows, Foundation on macOS) |
libs/draxul-config/ |
Config schema, TOML document I/O, and keybinding parsing |
libs/draxul-gui/ |
GPU-grid-native overlays such as palettes, tooltips, and toasts; no ImGui frame loop |
libs/draxul-ui/ |
ImGui diagnostics and developer-facing UI (key translation lives in libs/draxul-imgui-core) |
libs/draxul-runtime-support/ |
Shared grid-render pipeline, printing, resource monitoring, and background UI requests |
libs/draxul-host/ |
UI/process host adapters, terminal/Neovim hosts, PTY/ConPTY behavior, selection, copy mode, and client-side terminal presentation |
libs/draxul-nanovg/ |
Two targets: draxul-nanovg-backend (NanoVG core + custom Vulkan/Metal backends and their GLSL shaders; leaf-narrow, exported as Draxul::PluginSupport::NanoVG with a settable shader root for plugin hosts) and draxul-nanovg (the in-process INanoVGPass render-pass integration) |
libs/draxul-render-test/ |
Render-test driver and reusable render-test hosts |
libs/draxul-app-support/ |
Interface target bundling reusable config/runtime/render-test dependencies |
| Directory | CMake gate | Main targets and responsibility |
|---|---|---|
modules/markdown/ |
Always built | draxul-markdown parses/layouts documents; draxul-markdown-host integrates the native pane and platform render pass |
modules/kanban/ |
Always built | draxul-kanban owns board storage, layout/navigation, and the native Kanban host |
plugins/megacity/ |
DRAXUL_ENABLE_MEGACITY |
Submodule → draxul-megacity. Self-contained MegaCity/BioView product: code semantics, Tree-sitter, geometry, scene, Vulkan/Metal renderer, UI, shaders, assets, tests, and dynamic module |
plugins/satview/ |
DRAXUL_ENABLE_SATVIEW |
Submodule → draxul-satview. Self-contained satellite product: core, scene, services, runtime, Vulkan/Metal renderer, shaders, assets, tests, and the dynamic module |
plugins/scoreview/ |
DRAXUL_ENABLE_SCOREVIEW |
Submodule → draxul-scoreview. Self-contained notation, learning, transport, worker, MIDI/audio/microphone, UI, NanoVG Vulkan/Metal rendering, assets, tests, and dynamic module |
plugins/pcbview/ |
DRAXUL_ENABLE_PCBVIEW |
Submodule → draxul-pcbview. Self-contained millimetre board/routing model, strict JSON loader, bounded multilayer autorouter, VKLive-derived 2D viewport, back-to-front NanoVG Vulkan/Metal rendering, route inspection and ImGui layer/failure controls, deterministic prototype asset, tests, and dynamic module |
plugins/rezonality/ |
DRAXUL_ENABLE_REZONALITY |
Submodule → draxul-rezonality. Fault-tolerant live graphics product ported from VkLive; owns its watched project loader, compiler tools, immutable raster/ray candidates, Assimp, cameras, PBR/HDR resources, Vulkan ray pipelines and acceleration structures, native Metal ray kernels, examples, bounded agent diagnostics, transient-state handoff, layout tooling, and tests |
All optional product directories own their third-party dependency
declarations, sanitizer/coverage target lists, shader compilation, package
payload, test source inventory, and focused CTest wiring. The root build contains
only their feature switches and mount-point add_subdirectory calls. SatView's
catalog and texture generators likewise live under plugins/satview/tools/, so
the product can become a submodule without leaving maintenance scripts in core.
Each mount point is a cache path (DRAXUL_MEGACITY_PLUGIN_DIR,
DRAXUL_SATVIEW_PLUGIN_DIR, DRAXUL_SCOREVIEW_PLUGIN_DIR, or
DRAXUL_REZONALITY_PLUGIN_DIR). An enabled but
absent checkout is reported and skipped, making no-product and partial-submodule
trees supported configurations rather than configure errors.
Their registrations use strict dependency checking: SatView and MegaCity/BioView
consume the generic plugin runtime, render, configuration, text, HTTP,
performance, tooltip/ImGui, and platform GPU leaves as needed; ScoreView keeps
its standalone product stack and uses the same in-tree registration/support
naming. None of the product targets links draxul-host, the renderer
implementation, app orchestration, or another product.
Markdown and Kanban are linked directly into draxul. MegaCity/BioView, SatView,
ScoreView, and Rezonality are staged and loaded only as native modules. Core has no product
host kinds, provider factories, renderer bridge, or compiled-in fallback.
This file is generated from a configured build and may reflect the options used for that documentation build. Use it when:
- checking module boundaries
- spotting unexpected library dependencies
- deciding where a new abstraction belongs
Use this when:
- exploring object relationships inside a subsystem
- understanding which class owns a responsibility
Generated locally at docs/api/index.html via Doxygen.
Use this when:
- you want browsable symbol and header docs
- you want include/call/reference graphs tied to public headers
- you want a more traditional API-reference view than the diagrams provide
python do.py test debug— build and run core unit shards in the shared Debug cachepython do.py test debug --megacity|--satview|--scoreview|--pcbview— add only an affected product suitepython do.py test debug --products— add every product suite for shared plugin seamspython do.py test debug --all— explicit complete unit inventorypython do.py smoke --skip-build— startup-check that already-built apppython do.py run release— final Release build and startup confirmation
python do.py basicpython do.py cmdlinepython do.py unicodepython do.py blessall
python do.py shot
- Active work items: kanban/pending/
- Design notes: plans/design
- Review notes: plans/reviews
- Learnings: docs/learnings/learnings.md
- If the issue is about what Neovim sent or how input is encoded, start in
draxul-nvim. - If the issue is about what the screen should contain, start in
draxul-grid. - If the issue is about how the screen is drawn, start in
draxul-renderer. - If the issue is about glyph choice, shaping, emoji, tofu, or atlas behavior, start in
draxul-font. - If the issue is about DPI, focus, clipboard, IME, or visible window behavior, start in
draxul-window. - If the issue is about config parsing/validation, start in
draxul-config. - If the issue is about VT parsing, terminal modes, semantic cells, alternate-screen
behavior, or reusable scrollback storage, start in
draxul-terminal-core. - If it is about a shell process, PTY/ConPTY lifecycle, selection, copy mode, or
client presentation, start in
draxul-host. - If the issue belongs to SatView, MegaCity/BioView, or ScoreView, start in its
directory under
plugins/. Markdown and Kanban remain undermodules/. - If the issue crosses several modules, start in
app/to trace orchestration, then move reusable logic downward. Shared Session identity/split projection belongs indraxul-client::TopologyProjection;app/only adapts it to controllers and pane hosts.
As the repo grows, humans need a small number of reliable views into its structure:
- a module map
- generated dependency/class diagrams
- clear validation entry points
- current planning documents
Without that, the architecture becomes harder to hold in your head, even if the code itself stays clean.