IRCafe is a Java 25 desktop chat client with a Swing UI and a Spring Boot backend, supporting IRC, Quassel Core, and Matrix backends.
* Light Theme
* Dark Theme
./gradlew bootRunThis launches the Swing app and loads runtime config from ${XDG_CONFIG_HOME}/ircafe/ircafe.yml (or ~/.config/ircafe/ircafe.yml).
- Multi-server connections with add/edit/manage server dialogs.
- TLS and SASL (
AUTO,PLAIN,SCRAM-SHA-256,SCRAM-SHA-1,EXTERNAL,ECDSA-NIST256P-CHALLENGE). - Auto-reconnect with backoff + jitter, plus heartbeat timeout detection.
- Global SOCKS5 proxy plus per-server proxy override (auth, remote DNS, connect/read timeouts, proxy test).
- Auto-join channels or PM targets and per-server perform-on-connect commands.
- Native IRC flood protection in Preferences > Network > Flood protection is enabled by default for new and existing configurations. Ordinary commands share a two-command burst allowance per connection, starting full and rebuilding one credit every 2000 ms, capped at two. Once the allowance is spent, further commands wait for credit to rebuild, without a warm-up penalty. Auto-joins start five seconds after registration (and NickServ identification when required), run in the background, and stop on disconnect. Both timings are configurable. Uncheck "Enable outgoing rate limiting" to completely bypass command pacing; the separate auto-join startup delay still applies (set it to zero to join immediately). Changes apply on reconnect. Protocol negotiation, keepalives, and QUIT remain immediate.
- Rich slash command support for connection/session control, channel/user ops, invite workflows, monitor, ignore/soft-ignore, CTCP, DCC, CHATHISTORY, filters, and raw IRC.
- Matrix transport backend with homeserver probe + token-authenticated connect flow.
- Room and DM messaging, room joins/leaves, room directory/listing, and sync-based timeline ingestion.
- Matrix-backed compose features mapped into IRCafe flows, including reply/react/edit/redact, typing, read markers, and history navigation.
- Matrix support is active and tested, but full slash-command parity with IRC is still in progress.
- Capability negotiation with per-capability runtime toggles.
- IRCv3 capability negotiation includes
message-tags,server-time,echo-message,standard-replies,labeled-response,batch,draft/read-marker,draft/multiline,draft/chathistory, anddraft/message-redaction, alongsideznc.in/playback. - Replies (
+reply), reactions (+draft/react,+draft/unreact), and typing (+typing) use client-only tags overmessage-tags; these tag names are not requested as capabilities. Message editing remains experimental and is excluded from capability negotiation. - See the IRCv3 review evidence guide for protocol checks and reproducible screenshots.
- See the IRCv3 specification comparison for supported protocol names, coverage, and known conformance gaps.
- Partial IRCv3
stssupport: secure-connection policy learning and persistence with later TLS/port upgrades; immediate plaintext-to-TLS upgrade is not implemented. - Message reply/reaction/edit/redaction flows in chat UI and command layer.
- Typing indicators (send + receive) and read-marker updates.
- ZNC and soju network discovery with ephemeral server entries, per-network auto-connect preferences, and optional save of discovered entries to the main server list.
- Docked chat workspaces with per-buffer state.
- Multiple buffers can be open on screen simultaneously.
- Unread + highlight counters in the server tree.
- Presence folding (join/part/quit/nick condensation).
- Transcript context menu actions (reply, react, redact, inspect, must be enabled on the server).
- Find-in-transcript support, load-older controls, and history context actions.
- Command history, nick completion, and alias expansion.
- Nick context menu actions for query/whois/ctcp, moderation, DCC, and ignore toggles.
- CTCP request routing options and configurable CTCP auto-replies (
VERSION,PING,TIME).
- Theme system with FlatLaf, DarkLaf, curated IntelliJ themes, optional full IntelliJ pack list, and live preview.
- Accent overrides, chat palette controls (timestamp/system/mention), mention strength, and chat font family/size controls.
- FlatLaf tweak controls for density and corner radius, plus optional global UI font override.
- Preferences tabs for appearance, startup, tray/notifications, chat, CTCP replies, IRCv3, embeds/previews, history/storage, notifications, commands, diagnostics, filters, network, and user lookups.
- Persistent per-server monitor nick list with
/monitorand/mon, plus a dedicated monitor panel. - Automatic monitor resync on connect; ISON fallback polling when MONITOR is unavailable.
- Hard ignore and soft ignore lists (with CTCP behavior toggles).
- WeeChat-style render-time filters with:
- Scope matching
- Direction/kind/source/tag/text matching
- Global defaults and per-scope overrides
- Filter placeholders/hints with collapse behavior and history-batch controls.
- Optional embedded HSQLDB logging with Flyway-managed schema.
- Remote-only history mode when DB logging is disabled.
- Logging controls for PM logging, soft-ignored line logging, and retention.
- History loading integrates local DB data with IRCv3 CHATHISTORY and ZNC playback remote fill.
- Duplicate suppression in storage paths (message-id and exact-match checks where applicable).
- Per-server Log Viewer node with async search/export (off-EDT), sortable columns, and configurable column visibility.
- Log Viewer filters: nick, message text, hostmask, channel, date range, and protocol/server-event suppression controls.
- Per-server interceptor system with a dedicated
Interceptorstree group. - Multiple interceptor definitions, each with:
- Server scope (
this serverorany server) - Channel include/exclude rules (
All,None,Like,Glob,Regex) - Trigger rules by event type plus message/nick/hostmask matching
- Server scope (
- Action pipeline per interceptor:
- Status bar notification
- Desktop toast
- Sound (built-in or custom file)
- External script execution
- Captured hits table and per-server hit counts shown in the tree.
- System tray integration (close-to-tray, minimize-to-tray, start minimized).
- Desktop notifications for highlights, private messages, and connection state.
- Notification sound selection (built-in and custom).
- Event-driven notification rules (kicks, bans, invites, modes, joins/parts, PM/notice/CTCP, topic changes, netsplit, etc.).
- Rule actions can route to toast, status bar, sound, notifications node, script, and optional Pushy forwarding.
- Rule cooldown plus toast dedupe/rate-limiting behavior to reduce spam.
- A number of built-in sounds to choose from, or customize with your own.
- Optional inline image embedding for direct image links (
png,jpg,gif,webp). - Optional animated GIF playback.
- Link previews (OpenGraph/oEmbed + dedicated resolvers for sites such as Wikipedia, YouTube, Slashdot, IMDb, Rotten Tomatoes, X, Instagram, Imgur, GitHub, Reddit, Mastodon, and major news pages).
- DCC chat/file workflows (
/dcc ...,/dccmsg) plus a DCC Transfers panel with action hints and quick follow-up actions.
- Channel List node for
/listresults with filtering and double-click join. - User command alias editor with HexChat
commands.confimport. - Monitor and Notifications nodes per server for quick operational actions.
- Runtime diagnostics surfaces under
Application(Unhandled Errors, AssertJ Swing, jHiccup, Inbound Dedup, JFR, Spring, Terminal), including bounded event feeds plus clear/export actions.
New profiles are offered a short wizard for an IRC server/nickname, an existing account's SASL login, and channels to join when connecting. Every page has Skip this step, and Skip setup is available throughout. Closing the wizard or pressing Escape also skips setup entirely. Skipping the server page keeps the default connection; skipping account or channels leaves those choices empty.
Choices are saved only with Save and finish (or by skipping the final page). Skipping setup entirely discards all wizard edits and preserves the default settings. IRCafe stays disconnected after the wizard so you can choose when to connect. Settings can be changed later in Servers.
Completion or dismissal is remembered in the user's runtime config. Existing profiles, including upgrades from versions without this wizard, do not see it. The wizard works with all distribution formats, including the Windows MSI and ZIP.
- Java 25 for local run/build tasks (
./gradlew bootRun,./gradlew test,./gradlew jpackage,java -jar ...). - GNU Make + Docker only if using the optional Makefile Docker shortcuts.
- Flatpak +
flatpak-builderonly if building Flatpak bundles on Linux. - Windows + WiX Toolset on
PATHonly if building the Windows MSI installer. - Linux +
fakeroot,dpkg-dev, andrpmonly if building both native Linux packages. - Linux +
curlandfileonly if building a single-file AppImage (the build downloads pinned packaging tools).
- Entry point:
src/main/java/cafe/woden/ircclient/IrcSwingApp.java src/main/java/cafe/woden/ircclient/ui: Swing UI, docking, dialogs, rendering, tray integration.src/main/java/cafe/woden/ircclient/app: orchestration, mediator flow, command dispatch, notifications.src/main/java/cafe/woden/ircclient/irc: IRC/Matrix/Quassel protocol integrations and capability handling.src/main/java/cafe/woden/ircclient/config: runtime config models, property binding, registries.src/main/java/cafe/woden/ircclient/logging: log persistence, history ingestion, log viewer services.src/main/java/cafe/woden/ircclient/net: TLS/proxy bootstrapping and lightweight HTTP utilities.src/test/java/cafe/woden/ircclient: unit + integration + architecture tests.src/functionalTest/java/cafe/woden/ircclient: Swing functional tests (*FunctionalTest).
The repository includes a root Makefile with convenience commands that call Gradle directly.
make help
make build
make test
make checkIf you prefer a Make-first workflow, these cover most tasks:
| Workflow | Make | Gradle equivalent |
|---|---|---|
| Run app from source | make bootrun |
./gradlew bootRun |
| Build runnable jar | make jar |
./gradlew bootJar |
| Fast local feedback | make quick-check |
./gradlew quickCheck |
| Run lint checks | make lint |
./gradlew lint |
| Run unit/non-functional tests | make test |
./gradlew test |
| Run integration tests | make integration-test |
./gradlew integrationTest |
| Run architecture guardrails | make architecture-test |
./gradlew architectureTest |
| Find architecture refactoring candidates | make architecture-report |
./gradlew architectureReport |
| Run Swing functional tests | make functional-test |
./gradlew functionalTest |
| Verify UI changes | make verify-ui-change |
./gradlew verifyUiChange |
| Verify Spring changes | make verify-spring-change |
./gradlew verifySpringChange |
| Verify architecture changes | make verify-architecture-change |
./gradlew verifyArchitectureChange |
| Run strict analysis | make strict-analysis |
./gradlew strictAnalysis |
| Generate coverage report | make coverage-report |
./gradlew coverageReport |
| Build app image | make jpackage |
./gradlew jpackage |
| Run full verification | make check |
./gradlew check |
Run any Gradle task(s) via:
make gradle TASKS="bootRun"
make gradle TASKS="integrationTest --tests 'cafe.woden.ircclient.irc.QuasselCoreContainerIntegrationTest'"Build/test in Docker (no local JDK install required):
make docker-image
make docker-build
make docker-check
make docker-gradle TASKS="test"
# Also available: make docker-lint, make docker-integration-test, make docker-architecture-test, make docker-functional-testNotes:
- Local Make targets default
GRADLE_USER_HOMEto./.gradle-local(override withLOCAL_GRADLE_USER_HOME=/path). - Docker shortcuts run
./gradlewinside a local image built from versionedDockerfile.build. Dockerfile.buildpinseclipse-temurin:25-jdkby digest for reproducible toolchain resolution.- Docker targets auto-build the image if missing (override with
DOCKER_IMAGE=...if needed). - A persistent repo-local cache directory (
./.gradle-docker) is used for Docker Gradle cache reuse between runs.
From the project root:
./gradlew bootRun
# or:
make bootrunThis launches the Swing UI.
./gradlew bootJar
# or:
make jar
java -jar build/libs/*.jarThe Release (jpackage + flatpak) workflow verifies the exact tagged commit before building or publishing release assets. Its verification job runs the same five checks as CI, with the version from the tag:
./gradlew --no-daemon lint test integrationTest architectureTest functionalTest -Pversion=<release-version>The checks use CI's headless mode; dialog-dependent functional tests are skipped.
If verification fails, times out, or is cancelled, the JAR and platform packaging
jobs cannot publish a release. Available test and analysis reports are uploaded to the
workflow's release-verification-<attempt> artifact, including on failure, and
retained for seven days.
Manual workflow runs on branches skip the release checks and produce development artifacts without publishing a GitHub release. Manual runs on tags use the same verification gate as tag pushes.
Pushing a v* tag runs the Release (jpackage + flatpak) workflow and publishes
a GitHub release with automatically generated notes. GitHub selects the previous
release as the comparison base and includes merged pull requests, contributors,
and a Full Changelog comparison link. The JAR publishing step generates the
notes first; subsequent platform package uploads preserve that release body.
Manual workflow runs on branches upload build artifacts without publishing a release.
Notes use PR titles, so give pull requests descriptive titles. The categories in
.github/release.yml use the existing enhancement, bug,
and documentation labels; unlabeled PRs appear under Other changes.
Direct commits are visible through the full comparison link rather than individual
release-note bullets. Notes live on the GitHub release page; there is no generated
CHANGELOG.md committed back to the repository.
This applies to new releases after the workflow change is included in the tagged commit. To add notes to an existing release, edit it on GitHub, select the previous tag, click Generate release notes, review the result, and save it.
./gradlew jpackage
# or:
make jpackageOutput is written under build/dist/ using the platform's app-image layout.
This is a directory bundle; use jpackageAppImage below for a single .AppImage file.
On Linux, the generated app image also includes:
IRCafe.desktopinstall.shuninstall.sh
You can customize the Linux desktop launcher install prefix used in generated desktop entries:
./gradlew jpackage -PappInstallDir=/opt/IRCafeTo install just the desktop entry for the current user on Linux:
./gradlew installLinuxDesktopEntryOn Windows, install JDK 25 and WiX Toolset (CI uses WiX 3.14). For WiX 3,
add its bin directory, containing candle.exe and light.exe, to PATH.
Then run in PowerShell:
.\gradlew.bat clean jpackageMsiThe build uses IRCafe's Git-derived project version automatically. Tagged release
CI supplies the release tag's version; use -Pversion=<release-version> only when
explicitly building a particular release locally. Output is
build/installer/IRCafe-<version>.msi; the portable app image remains in
build/dist/IRCafe/. The MSI bundles Java, so users do not need to install a JRE.
It installs for all users (requires administrator approval), offers a destination
directory chooser and shortcut options, and supports removal through Windows Settings.
A fixed upgrade UUID lets newer release versions replace an existing installation.
Windows Installer versions must be numeric major.minor.patch, with major/minor
at most 255 and patch at most 65535. Snapshot/prerelease suffixes are stripped;
builds sharing the same numeric version are not distinct upgrades.
MSIs must be built on Windows; jpackage does not cross-compile installers.
Tagged releases publish ircafe-<version>-windows-x64.msi alongside the portable ZIP.
The Manual Test Build workflow's windows target also uploads both formats.
Both workflows run an install/uninstall smoke test on the Windows runner before
uploading the MSI. The installer is currently unsigned.
On Linux, install JDK 25 and the native packaging tools. For Ubuntu/Debian:
sudo apt-get install fakeroot dpkg-dev rpm
./gradlew clean jpackageLinuxUse jpackageDeb or jpackageRpm to build just one format. Packages are written to
build/installer/deb/ and build/installer/rpm/; the portable app image remains in
build/dist/IRCafe/. Each package bundles Java, installs under /opt/ircafe, and
adds an application-menu entry. Installation and removal use the system package
manager; user configuration and history stay in the user's profile. The optional
first-launch setup wizard works the same way as in other distribution formats.
For example, install a downloaded package with one of:
sudo apt install ./ircafe-VERSION-linux-x64.deb
sudo dnf install ./ircafe-VERSION-linux-x64.rpmNewer packages upgrade the existing ircafe package. Remove it with
sudo apt remove ircafe or sudo dnf remove ircafe. These downloads do not
configure an update repository; install a newer downloaded package to upgrade.
The package version comes from the same Git-derived project version as the other
native installers. Snapshot/prerelease suffixes are stripped. The package revision
defaults to 1 and can be overridden with -PlinuxPackageRelease=<revision>;
builds with the same numeric version and revision are not distinct upgrades.
DEB maintainer metadata can be overridden with -PlinuxDebMaintainer=<email>.
Native packages must be built on Linux for the target architecture.
Tagged releases attach .deb and .rpm files alongside the portable archives for
both linux-x64 and linux-arm64. The Manual Test Build workflow's linux
target uploads these formats plus AppImage for x64. CI builds on Ubuntu 24.04 and checks
installation, upgrade, GUI startup with the bundled runtime, and removal in
disposable Ubuntu 24.04 and Fedora 43 containers before uploading the packages.
Other distributions and older releases have not been verified.
To reproduce the package checks, run
bash packaging/linux/build-native-packages.sh from the repository root. It
builds revision 0 fixtures in build/installer-test/, followed by revision 1
packages. Run bash packaging/linux/test-native-package.sh CURRENT_PACKAGE PREVIOUS_PACKAGE
as root only inside a disposable container, with the packages mounted read-only;
the script installs system dependencies and creates a test user. The Linux steps
in .github/workflows/release-jpackage.yml show the complete container commands.
./gradlew jpackageAppImageThis wraps the bundled Java runtime and application in an executable AppImage.
Output is build/installer/appimage/IRCafe-<version>-<architecture>.AppImage, using
the existing Git-derived numeric packaging version and the build machine's
x86_64 or aarch64 architecture. Build on Linux with Temurin JDK 25 (as in CI)
and the curl and file utilities; distro-provided JDKs can introduce additional
system-library dependencies.
The build downloads version-pinned, SHA-256-verified appimagetool and runtime
releases into build/appimage/tools/; it does not require FUSE or root privileges.
To run a downloaded release:
chmod +x ircafe-VERSION-linux-x64.AppImage
./ircafe-VERSION-linux-x64.AppImageNo separate Java installation or package-manager installation is needed. The host still needs a graphical desktop and its usual X11, fontconfig, and ALSA libraries. Configuration and history use the same user profile as other IRCafe distributions, including the optional first-launch setup wizard. Replace the file to upgrade; removing it leaves your profile intact. Menu integration depends on the desktop's AppImage integration tools.
If FUSE is unavailable, run with --appimage-extract-and-run. This extracts to a
temporary directory for that run and requires additional free disk space.
Release CI builds AppImages for x64 and ARM64 and attaches them to GitHub releases.
The manual linux target also uploads an x64 AppImage. Before upload, both
workflows test extraction, desktop metadata, the bundled runtime, and launching
the actual file from a path containing spaces in disposable Ubuntu 24.04 and
Fedora 43 containers. Those tests use extract-and-run mode because containers
lack /dev/fuse; FUSE mounting and desktop integration are not exercised by CI.
The test script is packaging/appimage/test-appimage.sh and is intended only for
disposable containers. Older distributions have not been verified.
Install tooling (example for Debian/Ubuntu):
sudo apt-get update
sudo apt-get install -y flatpak flatpak-builder
flatpak remote-add --if-not-exists flathub https://flathub.org/repo/flathub.flatpakrepoBuild the app image and Flatpak repo/bundle:
./gradlew jpackage generateFlatpakMetainfo
flatpak-builder --force-clean --repo=build/flatpak/repo --default-branch=stable --install-deps-from=flathub build/flatpak/workdir packaging/flatpak/cafe.woden.IRCafe.yml
flatpak build-bundle build/flatpak/repo build/dist/ircafe.flatpak cafe.woden.IRCafe stable --runtime-repo=https://flathub.org/repo/flathub.flatpakrepoOn tagged GitHub releases, CI now publishes ircafe-<version>-linux-x64.flatpak as a release asset.
Common local checks:
./gradlew quickCheck
./gradlew lint
./gradlew test
./gradlew checkOne-time contributor setup:
./scripts/setup-git-hooks.shThis enables the repo's commit-msg hook for Conventional Commit validation.
Targeted suites:
# Spring/context integration tests from src/test (classes ending with IntegrationTest)
./gradlew integrationTest
# Modulith/jMolecules/ArchUnit guardrails
./gradlew architectureTest
# Advisory refactoring candidates, with Markdown/JSON reports
./gradlew architectureReport
# Swing UI functional tests from src/functionalTest (classes ending with FunctionalTest)
./gradlew functionalTestSee architecture report tooling for the rules, thresholds, baseline comparison, and interpretation limits.
Functional tests default to headless mode, which skips tests requiring a dialog.
Use -PfunctionalTestHeadless=false with a display to exercise those interactions.
For example, the optional setup wizard can be verified on Linux with:
xvfb-run -a ./gradlew :functionalTest -PfunctionalTestHeadless=false --tests '*FirstRunSetupDialogFunctionalTest'Quassel support integration matrix:
QuasselCoreRealServerIntegrationTest: validate against an already-running Quassel Core.QuasselCoreContainerIntegrationTest: validate containerized Quassel bootstrap/connect/sync.QuasselCoreContainerNetworkE2eIntegrationTest: validate Quassel + real ircd network flow.- All Quassel integration tests are opt-in and gated by
quassel.it.*properties.
Real Quassel Core integration (opt-in):
# Validates live Quassel Core connect/auth/sync, lag probe heartbeat, disconnect, reconnect.
# Requires a reachable Quassel Core and credentials.
QUASSEL_IT_LOGIN=alice QUASSEL_IT_PASSWORD=secret \
./gradlew :integrationTest --tests 'cafe.woden.ircclient.irc.quassel.QuasselCoreRealServerIntegrationTest' \
-Dquassel.it.enabled=true \
-Dquassel.it.host=127.0.0.1 \
-Dquassel.it.port=4242 \
-Dquassel.it.login=alice \
-Dquassel.it.password=secretOptional knobs (env vars or -D properties): quassel.it.server-id, quassel.it.tls,
quassel.it.nick, quassel.it.real-name.
Containerized Quassel Core integration via Testcontainers (also opt-in):
# Starts Quassel Core in Docker and validates setup/connect/sync/heartbeat/reconnect.
./gradlew :integrationTest --tests 'cafe.woden.ircclient.irc.quassel.QuasselCoreContainerIntegrationTest' \
-Dquassel.it.container.enabled=trueOptional knobs: quassel.it.container.image, quassel.it.container.login,
quassel.it.container.password, quassel.it.container.startup-timeout-seconds.
Default image is pinned to linuxserver/quassel-core:0.14.0 for amd64 compatibility.
Expanded Quassel E2E (Quassel Core + local ngIRCd, with a second IRC server for network isolation):
# Validates network creation/connection, inbound and outbound messages/notices/actions,
# backlog selector boundaries, ordering, stable IDs/timestamps after reconnect,
# routing between networks with matching channel/nick names, automatic recovery,
# native read-marker sync across clients/reconnects, and network edit/removal persistence.
./gradlew :integrationTest --tests 'cafe.woden.ircclient.irc.quassel.QuasselCoreContainerNetworkE2eIntegrationTest' \
-Dquassel.it.container.e2e.enabled=trueTranscript overlap and network isolation can also be checked without Docker or a display:
./gradlew :functionalTest --tests 'cafe.woden.ircclient.ui.chat.QuasselHistoryTranscriptFunctionalTest'Optional knobs: quassel.it.container.e2e.quassel-image,
quassel.it.container.e2e.irc-image, quassel.it.container.e2e.channel,
quassel.it.container.e2e.message, quassel.it.container.e2e.login,
quassel.it.container.e2e.password.
When enabled with Docker available, these tests require successful runtime network
creation and round trips; missing network creation fails the suite.
Direct IRC backend E2E (Pircbotx + local ngIRCd, no Quassel):
# Validates direct IRC backend connect/ready/join/inbound+outbound messages/reconnect.
./gradlew integrationTest --tests 'cafe.woden.ircclient.irc.PircbotxContainerNetworkE2eIntegrationTest' \
-Dirc.it.container.e2e.enabled=trueOptional knobs: irc.it.container.e2e.irc-image, irc.it.container.e2e.channel,
irc.it.container.e2e.bot-message, irc.it.container.e2e.app-message,
irc.it.container.e2e.nick, irc.it.container.e2e.login.
Matrix Synapse container integration (opt-in):
# Starts a local Synapse container and validates probe/whoami/send/sync/history flows.
./gradlew integrationTest --tests 'cafe.woden.ircclient.irc.matrix.MatrixSynapseContainerIntegrationTest' \
-Dmatrix.it.container.enabled=trueOptional knobs (property/env): matrix.it.container.image / MATRIX_IT_CONTAINER_IMAGE,
matrix.it.container.server-name / MATRIX_IT_CONTAINER_SERVER_NAME,
matrix.it.container.http-port / MATRIX_IT_CONTAINER_HTTP_PORT,
matrix.it.container.startup-timeout-seconds / MATRIX_IT_CONTAINER_STARTUP_TIMEOUT_SECONDS,
matrix.it.container.registration-secret / MATRIX_IT_CONTAINER_REGISTRATION_SECRET.
When to run which tests:
- Spring Modulith/jMolecules/ArchUnit or module-boundary refactors:
./gradlew architectureTest test - Spring wiring/integration changes (new beans, events, transactional boundaries):
./gradlew integrationTest - Swing UI behavior changes (dialogs, tree interactions, panel flows, rendering):
./gradlew functionalTest test - Non-UI feature work:
./gradlew test - Pre-merge on larger changes:
./gradlew checkplus relevant targeted suites above
Shortcut aliases:
./gradlew quickCheck
./gradlew verifyUiChange
./gradlew verifySpringChange
./gradlew verifyArchitectureChange
./gradlew verifyRefactorAuto-fix workflow (Error Prone auto-corrects first, then Spotless formatting):
./gradlew spotlessApply
# Run Error Prone auto-corrects, then Spotless lint check
./gradlew spotlessLint
# Optional: override which Error Prone patch checks are applied
./gradlew spotlessApply -PerrorPronePatchChecks=CheckReturnValue,ReturnValueIgnoredAdditional verification/reporting tasks:
./gradlew mutationTest
./gradlew pitest
./gradlew themeValidate
./gradlew strictAnalysis
./gradlew coverageReport
./gradlew jacocoTestReport
./gradlew jacocoIntegrationTestReport
./gradlew jacocoFunctionalTestReport
./gradlew dependencyCheckAnalyze
./gradlew cyclonedxBom
./gradlew taskTree --task check
./gradlew jmh/helpshows the main command groups (including backend-specific helpers)./help dccshows DCC chat/file commands./help chathistory,/help markread, and/help uploadshow focused usage for those flows./help edit,/help redact, and/help deleteshow IRCv3 compose mutation command help.- Quassel-specific workflows:
/quasselsetupand/quasselnet .... /filter helpshows local filter command usage./monitor helpshows monitor command usage.
When running IRCafe (from source or as a packaged jar), edit the runtime config file (loaded on startup and overrides the defaults in application.yml):
- Default path:
${XDG_CONFIG_HOME}/ircafe/ircafe.ymlwhenXDG_CONFIG_HOMEis set. - Otherwise falls back to:
~/.config/ircafe/ircafe.yml(i.e.${user.home}/.config/ircafe/ircafe.yml)
To use a different location, set ircafe.runtime-config (environment variable: IRCAFE_RUNTIME_CONFIG) or pass it on the command line:
IRCAFE_RUNTIME_CONFIG=/path/to/ircafe.yml java -jar build/libs/ircafe-*.jar
# or:
java -jar build/libs/ircafe-*.jar --ircafe.runtime-config=/path/to/ircafe.ymlServer definitions (IRC, Quassel Core, Matrix) use the irc.servers section.
IRC example:
irc:
servers:
- id: "libera"
host: "irc.libera.chat"
port: 6697
tls: true
# Optional: IRC PASS / server password (commonly needed for bouncers like ZNC)
# ZNC examples: "username:password" or "username/network:password"
serverPassword: "${IRCAFE_SERVER_PASSWORD:}"
nick: "${IRCAFE_NICK:IRCafeUser}"
login: "${IRCAFE_IDENT:ircafe}"
realName: "${IRCAFE_REALNAME:IRCafe User}"
sasl:
enabled: false
username: "${IRCAFE_SASL_USERNAME:}"
password: "${IRCAFE_SASL_PASSWORD:}"
mechanism: "PLAIN"
autoJoin:
- "#irclient"Matrix example:
irc:
servers:
- id: "matrix-main"
backend: "matrix"
# Host can be a plain host or a full base URL (for example with a path prefix).
host: "https://matrix.example.org"
port: 443
tls: true
# Matrix access token (preferred here). IRCafe also falls back to sasl.password if this is blank.
serverPassword: "${IRCAFE_MATRIX_ACCESS_TOKEN:}"
# Optional local display identity used by IRCafe UI defaults.
nick: "@ircafe:example.org"
login: "ircafe"
realName: "IRCafe Matrix"
# Optional auto-join targets (room id or alias).
autoJoin:
- "!someroom:example.org"
- "#ircafe:example.org"You can also override UI behavior under the ircafe.ui prefix. For inline image previews (direct image links in chat),
this is disabled by default:
ircafe:
ui:
imageEmbedsEnabled: falseYou can toggle this at runtime from the GUI: Settings -> Preferences… -> Inline images.
Other runtime settings (theme and appearance tweaks, tray/notifications, CTCP replies, IRCv3 capability toggles, STS cache entries, monitor nick lists, filters, command aliases, interceptors, notification rules, logging preferences, and more) are persisted to the runtime config file as you change them in the UI.
The default application.yml uses these environment variables:
IRCAFE_NICK(defaults toIRCafeUser)IRCAFE_IDENT(defaults toircafe)IRCAFE_REALNAME(defaults toIRCafe User)IRCAFE_CTCP_VERSION(defaults toIRCafe)IRCAFE_SERVER_PASSWORD(no default) — IRCPASS/ server password (useful for ZNC:username:passwordorusername/network:password)IRCAFE_SASL_USERNAME(no default)IRCAFE_SASL_PASSWORD(no default)
You can set them for a single run:
IRCAFE_NICK=myNick ./gradlew bootRunOr export them in your shell:
export IRCAFE_NICK=myNick
export IRCAFE_IDENT=myIdent
export IRCAFE_REALNAME="My IRC Client"To enable SASL, set irc.servers[].sasl.enabled: true in your config and set IRCAFE_SASL_USERNAME and IRCAFE_SASL_PASSWORD.
- Runtime config and UI state default to
${XDG_CONFIG_HOME}/ircafe/ircafe.ymlwhenXDG_CONFIG_HOMEis set, otherwise~/.config/ircafe/ircafe.yml. - With logging enabled (default
ircafe.logging.hsqldb.nextToRuntimeConfig: true), HSQLDB files (for exampleircafe-chatlog.*) are stored next to the runtime config file. - Linux
uninstall.shremoves the installed app image and desktop entry, but does not remove user config/history data.
- Keep
irc.client.tls.trustAllCertificates: falseunless you are intentionally testing with self-signed certs in a trusted environment. - For an IRC server, ZNC/other bouncer, or Quassel Core with a self-signed certificate, enable Allow self-signed and insecure certificates on the Connection tab of Add/Edit Server. This persists as
irc.servers[].trustAllCertificates(defaultfalse) and skips certificate validation for that server's TLS connections, including SOCKS connections and discovered bouncer networks. The existing global trust-all setting still applies when enabled. - Interceptor and notification rule script actions execute local scripts. Only use scripts and paths you trust.
- System tray and desktop notification behavior depends on OS/session support.
- Linux supports D-Bus notification actions when enabled (
ircafe.ui.tray.linuxDbusActionsEnabled: true). - Linux app-image builds include desktop/install helper files; other platforms keep standard app-image packaging.
- Commit messages follow Conventional Commits:
<type>(<scope>): <subject>. - Local hooks are configured by
./scripts/setup-git-hooks.sh; CI validates the same rules. - Allowed types:
feat,fix,refactor,perf,test,docs,build,ci,chore,style,revert.
Please feel free to file an issue, or get in touch on Libera.Chat channel #ircafe
GPL-3.0. See LICENSE.