Last updated: 2026-06-27
This file is a compact project memory for future maintainers and Codex runs. Treat it as a starting map, then verify against the live tree before making changes.
ztoolis a tray-first desktop utility collection, not a SaaS-style web app.- Current stack: Tauri 2, Rust 2021, React 19, TypeScript, Vite, pnpm.
- Package manager is
pnpm@10.33.0; main npm scripts arepnpm dev,pnpm build, andpnpm tauri .... - Current product surface is a compact undecorated tray window plus extra Tauri windows for screenshot workflows.
- Bundled plugins are registered as
ztool.screenshotandztool.caffeine; preferences/about remain protected host surfaces. - The plugin MVP is Git-based: plugin authors publish
.zpluginZIP packages through GitHub Releases, and ZTool reads a hosted staticmarket.jsoninstead of using a server-backed marketplace.
src/main.tsxroutes the React root by Tauri window label:mainrendersMainApp.capturerenders the screenshot editorCaptureApp.pin-*rendersPinApp.
src/App.tsxrenders plugin navigation from the Rust-backed plugin registry viasrc/plugins/pluginHost/usePluginHost.ts; screenshot/caffeine still render through bundled adapters.src/plugins/pluginHost/owns the TypeScript side of the plugin host: IPC contracts, market/registry service wrappers, market and lifecycle models, bundled manifest definitions, extension isolation policy, and bridge permission checks.src/plugins/types.tsnow treats plugin ids as dynamic strings. Bundled ids areztool.screenshotandztool.caffeine; legacyscreenshot/caffeinevisibility keys are migrated by preferences normalization.src/plugins/preferences/owns local preferences:- storage key:
ztool.preferences.v1 - launch-at-login uses
@tauri-apps/plugin-autostart - language options are
system,zh-CN, anden-US - at least one tool must stay visible.
- storage key:
src-tauri/src/lib.rsregisters tray behavior, the global screenshot shortcut, managed native state, plugins, and command handlers.src-tauri/src/plugins/owns Rust plugin contracts, Git market fetch/cache,.zplugindownload/checksum/extraction, registry persistence under~/.ztool/plugins/, and guarded binary/script entrypoint execution.src-tauri/capabilities/default.jsonmust include every window family used by commands. It currently allowsmain,capture, andpin-*.
- The previous screenshot phase-2 work delivered a macOS-first custom editor while keeping Windows on the system screenshot launcher path. Preserve that platform split unless the user explicitly asks for a Windows custom editor.
- Global screenshot shortcut is
CommandOrControl+Shift+A. - macOS flow:
start_screenshothides the main window, captures the screen throughscreencapture, stores one active session, and opens the full-screencapturewindow.init_screenshot_sessionreturnssession_id,image_base64,initial_action,width, andheight.commit_screenshotvalidates the active session, decodes the final PNG, copies or saves it, closescapture, restoresmain, and clears the active session.cancel_screenshot_sessionclosescapture, restoresmain, and clears the active session.pin_screenshotcrops from the final rendered PNG and opens an always-on-toppin-*window.
- Non-macOS screenshot flow currently starts the system tool. Windows uses
explorer.exe ms-screenclip:withSnippingTool.exefallback; Linux reports unsupported for this path. - The main
ScreenshotPanelstill shows disabled/pending tool buttons. Do not infer actual editor capability from that panel alone:CaptureApphas select, rectangle, arrow, pen, text, mosaic, pin, undo/redo/delete, copy, save, and cancel paths. - Screenshot command payloads intentionally use Rust-facing snake_case fields through
captureSerialize.ts:session_id,png_base64, andsave_path. - Pin windows need unique labels like
pin-<id>, capability globbing withpin-*, and native size based on decoded PNG dimensions plus titlebar height. - Main risks in screenshot work:
- coordinate conversion between rendered image bounds and original screenshot pixels
- macOS Screen Recording permission failures from
screencapture - stale or mismatched
session_id - forgetting to restore the main window after commit, cancel, or capture failure
- breaking Windows by forcing macOS-only assumptions into shared code.
src-tauri/src/services/caffeine.rsowns native awake behavior.- macOS starts and later kills a
caffeinate -d -ichild process. - Windows uses
SetThreadExecutionStatewith display and system required flags. - Other platforms currently return unsupported.
- Keep the Rust state snapshot and frontend state in sync when changing this plugin.
Use focused helper tests for fast screenshot iterations:
pnpm exec tsc src/plugins/screenshot/capture/captureReducer.ts src/plugins/screenshot/capture/captureHotkeys.ts src/plugins/screenshot/capture/captureSerialize.ts src/plugins/screenshot/capture/captureCanvas.ts --module ES2020 --moduleResolution bundler --target ES2022 --outDir /private/tmp/ztool-capture-test --noEmit false --skipLibCheck
node --test tests/captureReducer.test.mjs tests/captureHotkeys.test.mjs tests/captureSerialize.test.mjs tests/captureCanvas.test.mjsOther useful checks:
node scripts/validate-plugin-package.mjs examples/plugins/minimal-view-command-setting
node --test tests/pluginHostService.test.mjs tests/pluginHostModel.test.mjs tests/pluginMarketModel.test.mjs tests/extensionRuntime.test.mjs tests/bundledPlugins.test.mjs
node --test tests/*.mjs
pnpm build
cd src-tauri && cargo check && cargo test
git diff --checkFor plugin lifecycle work, also run the focused Rust suites:
cargo test --manifest-path src-tauri/Cargo.toml --test plugin_package --test plugin_registry --test plugin_runtimeFor screenshot behavior, do at least one manual pnpm tauri dev pass on macOS when changing capture windows, copy/save, pin windows, or tray/shortcut behavior.
- If building a public website, present ZTool as a desktop toolbox and tray utility, not as a generic SaaS.
- A separate static
site/app is a better first shape than mixing product-site content into the Tauri appindex.html. - Prior planning favored Astro + Vercel: Astro for the lightweight static site framework, Vercel for previews, CDN, domains, SSL, and Git-based deploys.
- A good first site structure: hero + CTA, short feature blocks, real screenshots/demo, download section, docs/FAQ, then i18n and changelog later.
- Reference balance: Maccy suggests a minimal single-message homepage; CC Switch suggests denser multilingual/docs-oriented product structure.
- For bug reports, trace the actual codepath and interaction path before fixing. Avoid stopping at a plausible theory.
- For screenshot work, prioritize making every tool path usable before visual polish.
- Preserve macOS and Windows differences when the user explicitly asks for platform-specific behavior.
- Before saying work is complete, run repo-native verification or state clearly what could not be run.
- If asked to commit, stage only relevant files and commit intentionally.