Contributing to Focalet

Focalet Capture and Focalet Desktop live in one repository with shared capture libraries. See product use cases and the component map. Credentials, canonical history, tools and permissions stay with the user's selected agent.

Work on Capture independently

Native Capture apps are in src/Focalet.CaptureTool (Windows), src/Focalet.Capture.Mac (Swift/AppKit) and src/Focalet.Capture.Linux (Python/GTK). The shared Windows capture library is in src/Focalet.Capture.Windows. Capture does not depend on Flutter, the Desktop helper executable or the Rust agent broker.

Install .NET SDK 8 and PowerShell 7 on Windows, then run:

dotnet build src/Focalet.CaptureTool/Focalet.CaptureTool.csproj --configuration Release
# Build the self-contained package from committed source:
python scripts/package_capture.py windows

On macOS, use Xcode command-line tools and .NET 8, then run python3 scripts/package_capture.py macos. On Ubuntu 24.04, install Rust 1.93, .NET 8, a C compiler, GTK/GStreamer development packages, Python GI/Cairo and GNOME 46, then run python3 scripts/package_capture.py linux. Neither builds Flutter or the agent broker. scripts/build_capture_installer.py wraps a verified Capture package in an independent installer. The native Capture CI lists exact Ubuntu build and acceptance dependencies.

For managed and Windows native tests, also install Python 3.10+ and run python scripts/check.py --suite capture. The interactive paste acceptance additionally uses Node.js 22 and the pinned Electron fixture:

npm ci --prefix tests/clipboard-electron --ignore-scripts --no-audit --no-fund
node tests/clipboard-electron/node_modules/electron/install.js
dotnet run --project tests/Focalet.Windows.Tests --configuration Release -- --paste-acceptance

Run interactive acceptance on a disposable Windows desktop: it controls focus, keyboard input and the clipboard. The PR Capture job provides that environment without a personal browser profile or agent account. No Rust or Flutter setup is needed for these Capture checks. On Linux, the capture suite runs portable contracts and cross-compiles the Windows consumers; native interaction still requires Windows.

Set up

Clone the repository and install:

  • Rust 1.93.0 (rustup reads rust-toolchain.toml).
  • Flutter 3.47.2, including its Dart SDK, on PATH.
  • Python 3.10+, Node.js 22+, .NET SDK 8, and FFmpeg (including ffprobe, for reviewed demo metadata).
  • Chromium, Chrome or Edge for browser capture tests. Set FOCALET_TEST_CHROMIUM to the executable if it is not on PATH.
  • Ubuntu 24.04 LTS x64 (the supported Linux target): SQLite, GTK and Chromium's runtime dependencies: sudo apt-get install binutils libsqlite3-dev libgtk-3-0t64 libwebkit2gtk-4.1-dev libgstreamer1.0-dev libgstreamer-plugins-base1.0-dev gstreamer1.0-pipewire libepoxy-dev libasound2t64 ffmpeg.
  • Windows: Visual Studio 2022 or later C++ tools for Rust and native builds; ATL and the NuGet CLI on PATH are also needed for Flutter packaging. Use PowerShell 7 for native checks.

Install the Python test dependencies in a virtual environment (required for Ubuntu's OS-managed Python):

python3 -m venv .venv
source .venv/bin/activate
python -m pip install -r tests/requirements.txt

In PowerShell, activate it with .\.venv\Scripts\Activate.ps1 instead.

You do not need an agent account, model credentials, or a running gateway to run contract tests. Process tests launch the Rust broker with local protocol fixtures. Do not replace those fixtures with your personal agent installation. Linux CI also runs the real Gemini and Claude Code CLIs pinned in tests/runtime-clis/package-lock.json, through the Rust broker. Gemini uses its test response generator; Claude uses a local Messages API fixture. Temporary runtime profiles and a network namespace prevent personal-account access and external requests. This validates CLI compatibility, not cloud authentication or model quality. To run the same acceptance checks on Ubuntu after building the broker:

npm ci --prefix tests/runtime-clis --ignore-scripts --no-audit --no-fund
node tests/runtime-clis/node_modules/@anthropic-ai/claude-code/install.cjs
sudo --preserve-env=PATH unshare --net -- bash -c 'ip link set lo up; exec runuser -u "$SUDO_USER" --preserve-environment -- python3 scripts/verify-runtime-clis.py'

The runtime fixture tests cover failure recovery, cancellation and approval identity on all platforms. Update the pinned CLI version and its acceptance assertion together; Gemini's fake-response switches are upstream test interfaces. The check runner enables FOCALET_RUNTIME_DISCOVERY_MODE=configured-only and temporary binding/discovery/override stores for its child processes. This disables automatic native/WSL discovery only in that test invocation. Individual fixtures supply explicit commands; ordinary app launches still discover agents.

Run checks

For documentation changes, install requirements-docs.txt in your virtual environment and run python scripts/check_docs.py. This builds the searchable site with strict link and anchor validation. Preview it with python -m mkdocs serve. The site publishes the existing contributor and agent guides directly from their root files; edit those originals instead of generated site output.

From the repository root on Ubuntu:

python3 scripts/check.py

This checks Rust formatting/lints/tests, builds the broker, restores the locked Flutter dependencies, checks Dart formatting/analysis, runs every Flutter test, then runs Python, relay, managed capture and real headless-browser tests. It stops on the first failure. SQLite's linker alias is prepared in a temporary directory if the system only provides its versioned library.

Run just the affected suites during development:

python3 scripts/check.py --suite rust --suite flutter
python3 scripts/check.py --suite contracts
python3 scripts/check.py --suite capture --suite browser

Build the broker before Python or Dart process tests (--suite rust). Do not skip a failing process test because no real agent is installed.

On Windows:

python scripts/check.py --suite windows

This checks the core, all Dart process fixtures, Windows paths/SQLite/desktop contracts, the capture helper and deployment retry logic. Linux runs the full widget suite and its pixel baselines. The macOS PR job runs the full Flutter suite with its own baselines and native selection geometry tests. All three PR jobs compile and verify a native desktop package. Build and publish release automatically builds and publishes Windows, Ubuntu and both macOS installers when a PR changing the app's release version lands on main. It also accepts manual builds and retries. Native acceptance retains additional interactive desktop checks. See release preparation.

To build a native package locally or run interactive acceptance:

bash scripts/package-unix.sh linux
# macOS: bash scripts/package-unix.sh macos
./scripts/package-windows.ps1 -Runtime win-x64

Native Linux builds additionally need Clang, Ninja, pkg-config, GTK development headers, X11 and Ayatana AppIndicator. See Ubuntu testing, Windows acceptance, Mac testing and release preparation.

Choose the right regression test

Change Tests to extend
Runtime protocol, identity, history or recovery Rust adapter tests; Dart *_process_test.dart against crates/focalet-core-host/tests fixtures
Session switches, late replies, drafts or edit/resend session_*, background_runtime_*, message_rewind_*, chat_switch_recovery_*
Capture fidelity and privacy tests/Focalet.Capture.Tests, tests/Focalet.Browser.Tests, Rust context_handoff tests and core_bridge_process_test.dart
UI layout, streaming, hotkeys or notification behavior Flutter widget/desktop tests; packaged native acceptance when the OS is involved
Packaging, installers or publishing Python test_release_package.py and test_public_release.py
Contributor workflows test_contributor_checks.py

Test observable behavior and failure cases. A fake should reproduce a protocol boundary, including delayed, malformed, duplicate or out-of-order responses. Verify the exact runtime and session when IDs collide. An accepted turn must not be automatically sent again after an uncertain transport failure.

Use temporary data and loopback-only fixtures. Close child processes before deleting their temporary directories. Use bounded waits for events; avoid pumpAndSettle while an animation or stream intentionally remains active. Screenshot baselines are OS-specific: golden guidance. Inspect changed images before committing them; updating goldens is not a fix for an unexplained regression.

Pull requests

The PR checks workflow runs for every PR, including forks, on disposable GitHub-hosted runners. Documentation and CI-policy checks always run. An explicit allowlist of Markdown and documentation media can skip native builds. Capture app, clipboard fixture or Capture packaging changes run the dedicated Capture contracts jobs on Windows, Ubuntu and both Mac architectures without Flutter or the agent broker. Desktop UI/runtime changes run Linux, Windows and both macOS Desktop jobs. Shared capture, dependency, workflow, build configuration and unknown changes run both products' native checks. A change touching both apps also runs both sets.

PR checks passed requires documentation and each selected product's jobs to succeed. A skip is accepted only when the scope job explicitly excluded that product; missing scope, failure and cancellation fail the gate. CI uses read-only repository access, no deployment secrets and pinned action revisions. It does not run fork code on maintainers' persistent machines. Rust and Flutter caches are separated by OS/toolchain and dependency lockfiles.

Repository maintainers should require PR checks passed in the main branch rules and require review for workflow changes. This file does not enable GitHub branch protection by itself. Release publication additionally verifies the latest main-push run of checks.yml for the exact source revision. The documentation deployment starts after successful main checks and uses that same revision. The Native acceptance workflow is manual and reserved for reviewed source. Do not dispatch unreviewed fork code onto a persistent runner.

Keep changes focused and describe the user-visible result, validation and any native checks still needed. Include a regression for a behavior change. Never upload personal transcripts, settings, session catalogs, tokens, or raw desktop logs. Public demos must use synthetic content and pass the recording review.

License

Contributions are provided under the repository's Apache 2.0 license. Preserve third-party copyright and license notices when updating dependencies or assets; see third-party notices.