Do not add AI-tool attribution trailers to commit messages in this repository — not "Generated with Codebuff", not "Co-Authored-By: Codebuff", and not the equivalent footers from other AI tools (Copilot, Claude, Codex, ChatGPT, Gemini, Cursor, etc.). Commit messages should consist of the subject line, an optional body, and nothing else. Human "Co-Authored-By: Person" trailers are fine.
A local-first, cross-platform website screenshot tool and portfolio mockup generator. The interface is native Qt Widgets; a private Playwright worker does the rendering and capturing. Everything runs locally — no accounts, uploads, or template services.
Four processes, each with a narrow job:
| Process | Responsibility | Persistent state |
|---|---|---|
CyberSnapper (GUI) |
Native Qt Widgets UI | Window/UI preferences only |
cybersnapper-agent |
Single project owner, job queue, schedules, REST API, tray | QSettings and project SQLite databases |
cybersnapper-cli |
Native automation CLI | None; talks to the agent |
worker/dist/main.cjs |
One capture job using Playwright and Sharp | Artifacts inside the selected project |
- GUI/CLI ↔ agent: versioned, length-prefixed JSON frames over
QLocalSocket(protocol v1,Rpc.h/Rpc.cpp, frames capped at 16 MiB). The OS user is the IPC security boundary. - Agent ↔ worker: one worker process per active job, protocol-v2 newline-delimited JSON. The agent assigns final event sequence numbers, applies state changes transactionally, then broadcasts events.
- Projects are portable SQLite databases (WAL mode, foreign keys, per-project lock file). Only the agent opens them for normal operation.
- REST v1 is disabled by default, binds to
127.0.0.1only, and requires a high-entropy bearer token (only the SHA-256 digest is stored).
See docs/ARCHITECTURE.md for the full security model (capture boundary,
visual review model, scheduling) and docs/PROJECT_FORMAT.md for the project
format.
native/— C++20/Qt 6.8+ application:src/core(shared library),src/gui,src/agent,src/cli, plustests/(CMake + ctest).worker/— TypeScript Playwright worker (src/), bundled by esbuild todist/*.cjs, withtest/*.test.cjsrun vianode --test.scripts/— release, packaging, docs-screenshot, and site tooling.docs/— architecture, project format, API, building, packaging, release notes (docs/releases/).site/— static marketing site, built withscripts/build-site.mjs, no framework or remote runtime dependencies.
- Follow the existing style:
namespace CyberSnapperwith nested namespaces (e.g.CyberSnapper::Paths), members prefixedm_, file-local constants prefixedk, andQStringLiteralfor string literals. - Data structures live in
src/core/Models.has plain structs withtoJson/fromJsonfree functions; keep the JSON contract stable — it is shared across GUI, CLI, and worker. - The worker speaks protocol v2 (
worker/src/protocol.ts); the native side mirrors those shapes inModels.h. When you change one side, keep the other in sync. cybersnapper_corelinks QtCore/Network/Sql; the GUI addsWidgets/Svg. Register new core sources innative/CMakeLists.txt.cpp-httplibis used for REST; if absent, CMake fetches the pinned v0.52.0 source — do not bump it casually.- Keep
package.jsonandCMakeLists.txtversions in sync;scripts/check-release-version.mjsenforces this in CI.
- Strict TypeScript, compiled by esbuild to CommonJS targeting Node 20 with
playwrightandsharpexternal. protocol.tsis the single source of truth for job/artifact/event shapes.network.tsimplements the URL policy: only explicithttp/https, no embedded credentials, private/LAN/link-local destinations blocked, localhost only when the project opts in. Never weaken these checks — the filtering proxy is the capture boundary.- Tests are plain
.test.cjsfiles usingnode:testandnode:assert/strict, exercising internals exported fromworker/dist/testing.cjs. Runnpm run typecheck:workerandnpm run test:workerafter worker changes.
npm install
npm run typecheck:worker
npm run build:worker
npm run test:worker
cmake -S . -B build/native -DCMAKE_BUILD_TYPE=Debug
cmake --build build/native --parallel
ctest --test-dir build/native --output-on-failureDevelopment binaries land in build/native/native/. Install Chromium for
local capture work with npx playwright install chromium.
Packaging is driven by .github/workflows/release.yml; each platform
(AppImage/tar.gz, NSIS/ZIP, DMG/ZIP) runs scripts/smoke-packaged-capture.mjs
before anything is published. See docs/PACKAGING.md for details and
RELEASE.md for the release process. Never move a published v* tag.
- Keep features centered on CyberSnapper's primary job: portfolio-ready website screenshots.
- Respect the security boundaries (IPC, capture, REST) documented in
docs/ARCHITECTURE.md; treat them as invariants, not suggestions. - Keep the docs site deterministic:
npm run screenshots:docsnever touches the live network; only the explicitnpm run screenshots:sourcesdoes. - For UI changes, attach before/after screenshots to the pull request.