Files
ObsidianDragon/CLAUDE.md
DanS a78a13edf3 docs(lite): add v2 implementation plan, source-hygiene guard, and CLAUDE.md
- docs/lite-wallet-implementation-plan-v2-2026-06-04.md: vertical-slice plan that
  supersedes the v1 plan (now banner-marked); carries over the inherited artifact/
  signing/phase-2 design docs for reference.
- scripts/check-source-hygiene.sh: pre-commit/CI guard rejecting >80-char filenames
  and chained churn-token names, to stop the deleted "_plan"/"_batch" scaffolding
  from regrowing.
- CLAUDE.md: repository guidance for future sessions.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-04 21:15:11 -05:00

6.9 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

What this is

ObsidianDragon is a portable, full-node GUI wallet for DragonX (DRGX), written in C++17 using SDL3 + Dear ImGui (immediate-mode). It drives a dragonxd full node over JSON-RPC and can embed/extract the daemon itself. A separate Lite variant (ObsidianDragonLite) drops the full node and instead talks to an external lite-wallet backend library.

Build & run

build.sh is the single entry point for all builds. setup.sh (repo root) installs/validates dependencies.

./build.sh                       # Dev build (native, no packaging) -> build/linux/bin/ObsidianDragon
./build.sh --lite                # Dev build of the Lite variant      -> build/linux/bin/ObsidianDragonLite
./build.sh --clean               # Wipe the build dir first
./build.sh --linux-release       # Release zip + AppImage             -> release/linux/
./build.sh --win-release         # Windows cross-compile (mingw-w64)  -> release/windows/
./build.sh --mac-release         # macOS .app bundle + DMG
./setup.sh --check               # Report missing build deps without installing

Dev builds use build/linux/ (or build/mac/). To re-build incrementally without re-running CMake config: cmake --build build/linux -j$(nproc).

The wallet connects to the daemon using credentials in ~/.hush/DRAGONX/DRAGONX.conf (rpcuser/rpcpassword/rpcport). It searches for dragonxd/dragonx-cli binaries in the executable's own directory first, so dropping custom node builds next to the wallet binary overrides the bundled ones.

Tests

Tests live in tests/test_phase4.cpp — a single large translation unit using a custom assertion harness (EXPECT_TRUE/EXPECT_EQ/EXPECT_NEAR macros, one main(), exit code = failure count). include(CTest) enables BUILD_TESTING=ON by default, so the ObsidianDragonTests executable is built alongside the app.

cd build/linux && ctest --output-on-failure     # run the suite
./build/linux/bin/ObsidianDragonTests            # run the binary directly (same thing)

There is no per-test filtering — it is one binary that runs every assertion. The suite exercises the services layer, lite-wallet bridge, and pure helpers (parsers, formatters, model classes) without launching the GUI. Fixtures are under tests/fixtures/ (path injected as DRAGONX_TEST_FIXTURE_DIR).

Architecture

Entry & main loop. src/main.cpp owns SDL3 window creation, ImGui/OpenGL(or DX11 on Windows) setup, and the frame loop. The App class is the central controller; because it is large it is split across four files that all implement the same class:

  • src/app.cpp — core lifecycle, the per-frame render(), tab dispatch
  • src/app_network.cpp — RPC orchestration, sync, peers, daemon lifecycle
  • src/app_security.cpp — encryption, PIN/lock screen, key import/export, backup
  • src/app_wizard.cpp — first-run wizard

RPC. All daemon calls go through src/rpc/ (rpc_client, connection, rpc_worker). Never block the main/UI thread with synchronous network I/O — dispatch through RPCWorker (async). rpc/types.h holds the shared DTOs.

Services (src/services/) hold the non-UI state machines that the App owns: NetworkRefreshService + RefreshScheduler (polling/refresh of balance, peers, txs on intervals) and the WalletSecurity* controller/workflow stack (encryption & unlock flows).

Data model (src/data/): WalletState, address_book, transaction_history_cache, exchange_info. UI reads from these.

UI (src/ui/): windows/ are the tabs and dialogs (one pair per screen, e.g. send_tab, mining_tab, console_tab), pages/ are multi-section screens (Settings), screens/ are layout headers, material/ is the design-system layer, schema/ loads the TOML UI schema/skins, effects/ is GL post-processing (blur/acrylic).

Lite wallet (src/wallet/): the bridge to an external litelib_* C-ABI backend (lite_client_bridge, lite_bridge_runtime, lite_connection_service, lite_sync_service, result parsers, and the artifact-contract/resolver that validates a prebuilt backend library). The real frontend entry points are lite_wallet_lifecycle_ui_adapter and lite_wallet_server_selection_adapter (used by src/ui/pages/settings_page.cpp); everything else is reachable through them.

⚠️ Do not regrow the _plan/_batch churn. This directory previously held ~160 dead lite_wallet_*_plan / *_batch*_receipt_custody_acceptance_confirmation_archive_handoff_* files (filenames up to 250 chars) — auto-generated scaffolding that never reached the shipping binary. They were deleted. When extending lite-wallet behavior, edit the named service/bridge/runtime files in place; never add another "promotion/receipt/custody/handoff/stewardship" wrapper layer. scripts/check-source-hygiene.sh (wired as a .git/hooks/pre-commit hook) blocks >80-char filenames and chained churn-token names — run it in CI too.

Chat (src/chat/chat_protocol.cpp): experimental HushChat protocol, compiled in only when DRAGONX_ENABLE_CHAT=ON.

Build variants & feature gating

Variants are selected with CMake options (set by build.sh flags), surfaced to C++ as compile definitions:

  • DRAGONX_BUILD_LITE (--lite) → DRAGONX_LITE_BUILD define; renames the app to ObsidianDragonLite and excludes embedded-daemon / full-node assets (Sapling params, asmap, dragonxd).
  • DRAGONX_ENABLE_LITE_BACKEND → links a real external lite backend. Requires --lite, link mode imported, ABI sdxl-c-v1, and a symbols inventory file (built by scripts/build-lite-backend-artifact.sh); CMake hard-fails if any required litelib_* symbol is missing.
  • DRAGONX_ENABLE_CHATDRAGONX_ENABLE_CHAT define gating the chat module.

Guard full-node-only code paths with #if DRAGONX_LITE_BUILD / chat code with DRAGONX_ENABLE_CHAT.

Versioning

The version has a single source of truth: project(... VERSION 1.2.0 ...) plus DRAGONX_VERSION_SUFFIX in CMakeLists.txt. CMake generates build/.../generated/dragonx_generated_version.h from src/config/version.h.in. Do not hand-edit generated version output or hardcode version strings — bump the project() version in CMakeLists.txt.

Conventions

  • C++17. Match the surrounding code's style per file.
  • Icons: use the Material Design icon font defines (ICON_MD_*); never raw Unicode glyphs.
  • UI layout values belong in res/themes/ui.toml, read via schema::UI() — do not hardcode pixel sizes/offsets in code.
  • i18n: user-facing strings are translated via src/util/i18n; translation JSON lives in res/lang/ (de, es, fr, ja, ko, pt, ru, zh, English fallback in code). Translation/font helper scripts are in scripts/ (gen_*.py, CJK subset tooling).
  • Commits: the history uses Conventional Commits (feat(scope): …, fix(scope): …). PRs target master.