Skip to content

Releases: fireflyframework/flycanon

v26.10.4

Choose a tag to compare

@github-actions github-actions released this 14 Oct 23:52
5ae3ca8

Workspace creation now returns a clear 400 workspace_scope_mismatch when the body id differs from X-Workspace-Id. The request is rejected before a row or lifecycle event is written. Matching requests retain 201 and their existing response.

The API reference now describes the actual workspace lookup error and list behavior. Python and Java SDK instructions explain how to select the workspace being created. Server and SDK versions are aligned at 26.10.4; dependency pins, RLS policies, SDK methods and request/response schemas are unchanged. The published Python SDK 26.10.3 remains compatible with the corrected server.

Local qualification covers the production non-bypass PostgreSQL role, actual HTTP and SDK calls, persisted rows and outbox events, foreign-scope visibility and rejected credentials. The configured unit suite passes 1,219 tests, with 52 integration tests passing and three optional backend integrations skipped. Python and Java SDK suites pass 61 and 62 tests.

Lifecycle-event delivery remains best-effort after a successful workspace write. Platform API keys retain their existing trusted operator authority.

Install the Python SDK from the release wheel:

uv add https://github.com/fireflyframework/flycanon/releases/download/v26.10.4/flycanon_sdk-26.10.4-py3-none-any.whl

For the standalone server, follow the released-server installation guide. Verify downloaded files against SHA256SUMS. Java consumers use com.firefly:flycanon-sdk:26.10.4 through GitHub Packages.

v26.10.3

Choose a tag to compare

@github-actions github-actions released this 14 Oct 20:32
efb221b

Python SDK

Install the wheel for this release with uv:

uv add https://github.com/fireflyframework/flycanon/releases/download/v26.10.3/flycanon_sdk-26.10.3-py3-none-any.whl

Or pin it in your pyproject.toml:

[project]
dependencies = ["flycanon-sdk"]

[tool.uv.sources]
flycanon-sdk = { url = "https://github.com/fireflyframework/flycanon/releases/download/v26.10.3/flycanon_sdk-26.10.3-py3-none-any.whl" }

Java SDK

<dependency>
  <groupId>com.firefly</groupId>
  <artifactId>flycanon-sdk</artifactId>
  <version>26.10.3</version>
</dependency>

Resolve from GitHub Packages -- add to your pom.xml:

<repositories>
  <repository>
    <id>github-fireflyframework</id>
    <url>https://maven.pkg.github.com/fireflyframework/flycanon</url>
  </repository>
</repositories>

What's Changed

  • Serialize expiring agent tokens and release 26.10.3 by @ancongui in #83

Full Changelog: v26.10.2...v26.10.3

Canon 26.10.2 — stable Agentic adoption

Choose a tag to compare

@github-actions github-actions released this 14 Oct 19:47
9586e1c

Stable Agentic adoption

Canon 26.10.2 adopts the published Agentic 26.10.1 wheel and aligns the server, Python SDK, and Java SDK versions. The HTTP schemas change only their version metadata. Canon's application code, migrations, Azure support, and existing RLM behavior remain unchanged.

pyfly stays at the qualified v26.09.04 reference. A later pyfly upgrade needs a separately qualified drain or replay of queued legacy EDA events; this release does not perform that cutover.

Install

For the server, follow Install the released server. The release requirements file selects the server wheel, qualified pyfly reference, and immutable public Agentic wheel. Use the matching source archive for the migration scaffold and runtime configuration. SHA256SUMS covers all eight package and operator assets.

Install the Python SDK directly from this release:

uv add https://github.com/fireflyframework/flycanon/releases/download/v26.10.2/flycanon_sdk-26.10.2-py3-none-any.whl

The Java SDK is available as com.firefly:flycanon-sdk:26.10.2 through GitHub Packages, with a downloadable JAR also attached here.

Verification

All seven required checks passed on the reviewed PR commit before the guarded merge. Local native validation passed 1,270 unit and integration tests; three optional Chroma/Qdrant cases were skipped because their clients were absent. Fresh installations from the public server requirements and Python SDK wheel passed, including all 59 SDK tests on Python 3.11.

The full installed application also passed authenticated ingestion, cited hybrid retrieval, tenant/workspace isolation, scoped agent-token refusals, and native PostgreSQL row-security checks in an owned local environment. That environment used an explicitly synthetic, deterministic loopback embedding service; it did not execute an external model. No paid provider calls or cloud application deployment were used. The container publisher verifies image publication separately from application runtime acceptance.

Earlier release tags and assets remain unchanged.

Full changelog

flycanon 26.10.1

Choose a tag to compare

@ancongui ancongui released this 14 Oct 18:22
aa2486a

Packages and installation

This patch aligns the flycanon server and its Python and Java clients at 26.10.1. The server installation guide selects the matching wheel, runtime requirements and configuration assets from the canonical GitHub release. SDK guides use the same version and the current Firefly framework-family banners across desktop/mobile and light/dark variants.

The Python SDK package metadata now identifies fireflyframework. Modified handwritten SDK sources retain their Foundation copyright and include the Apache 2.0 SPDX identifier. SDK version constants and user-agent headers match the package version.

Compatibility and verification

The HTTP contract, server implementation, client schemas, migrations, runtime configuration and framework dependency pins are unchanged. Both lockfiles change only the project's own version.

Local validation passed 1,213 server unit tests, 59 Python SDK tests, lint, formatting, type checks, Java 25 Maven verification and server/SDK package builds. Five existing local tests require Docker; the configured PR integration and container checks run separately before publication. The release includes checksums for the server/client packages and operator configuration files. Earlier releases remain available with their original assets.

Operators should apply the installation guide to their own configured PostgreSQL, object-store and authentication environment. No paid model-provider calls or cloud application deployments were used for this release validation.

Python SDK

Install the wheel for this release with uv:

uv add https://github.com/fireflyframework/flycanon/releases/download/v26.10.1/flycanon_sdk-26.10.1-py3-none-any.whl

Or pin it in your pyproject.toml:

[project]
dependencies = ["flycanon-sdk"]

[tool.uv.sources]
flycanon-sdk = { url = "https://github.com/fireflyframework/flycanon/releases/download/v26.10.1/flycanon_sdk-26.10.1-py3-none-any.whl" }

Java SDK

<dependency>
  <groupId>com.firefly</groupId>
  <artifactId>flycanon-sdk</artifactId>
  <version>26.10.1</version>
</dependency>

Resolve from GitHub Packages -- add to your pom.xml:

<repositories>
  <repository>
    <id>github-fireflyframework</id>
    <url>https://maven.pkg.github.com/fireflyframework/flycanon</url>
  </repository>
</repositories>

What's Changed

  • Document verified standalone server installation by @ancongui in #78
  • Align knowledge source and identity with Firefly Framework by @ancongui in #79
  • Use framework family banners throughout SDK guides by @ancongui in #80
  • Release canonical server and SDK packages as 26.10.1 by @ancongui in #81

Full Changelog: v26.10.0...v26.10.1

Flycanon 26.10.0

Choose a tag to compare

@github-actions github-actions released this 12 Oct 17:59
9d78dfd

Phone PII matching now respects hexadecimal identifier boundaries. Numeric fragments inside revision and digest identifiers no longer reject canonical memory writes. Standalone US and international phone numbers remain detected, and strict PII rejection remains enabled.

Server, Python SDK and Java SDK versions and runtime User-Agents are aligned at 26.10.0. The HTTP contract is unchanged. The release includes server and Python SDK wheels/source archives, the Java SDK JAR and SHA256SUMS.

Install the Python SDK directly from this release:

uv add https://github.com/firefly-operationOS/flycanon/releases/download/v26.10.0/flycanon_sdk-26.10.0-py3-none-any.whl

Server wheel: flycanon-26.10.0-py3-none-any.whl (Python 3.13). Java: com.firefly:flycanon-sdk:26.10.0 from GitHub Packages. Container: ghcr.io/firefly-operationos/flycanon:26.10.0 for Linux amd64 and arm64.

Validation includes the server PII regression suite, full server/SDK tests, native Docker integration, lint/type checks and the Docker image build. Cloud authentication and external provider acceptance are separate deployment checks. BuildKit SBOM/provenance publication is disabled; the workflow's attestation upload is advisory.

Standalone server installation

Use the verified server installation guide and versioned runtime requirements. A wheel installer does not consume repository uv-source settings: the requirements select PyFly v26.09.04 and Agentic v26.06.16 explicitly. A fresh full runtime installation resolved all 218 packages and served version 26.10.0; authenticated source/memory retrieval passed for two independently scoped project workspaces.

Keep the released source archive's pyfly.yaml, alembic.ini, migration directory and environment template in the runtime working directory. The configuration supplement is byte-identical to the released configuration. Starting without it can activate unintended framework defaults, including Kafka and a separate management listener. Configure the PostgreSQL database, credentials and provider settings for your operator environment before starting.

These installation supplements are documented in PR 78. The existing tag, wheel, source archives and Java package are unchanged; SHA256SUMS now covers all eight payload files. GHCR image access requires the registry package's permissions.

v26.9.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 23:45
2585f24

Python SDK

Install the wheel for this release with uv:

uv add https://github.com/firefly-operationOS/flycanon/releases/download/v26.9.0/flycanon_sdk-26.9.0-py3-none-any.whl

Or pin it in your pyproject.toml:

[project]
dependencies = ["flycanon-sdk"]

[tool.uv.sources]
flycanon-sdk = { url = "https://github.com/firefly-operationOS/flycanon/releases/download/v26.9.0/flycanon_sdk-26.9.0-py3-none-any.whl" }

Java SDK

<dependency>
  <groupId>com.firefly</groupId>
  <artifactId>flycanon-sdk</artifactId>
  <version>26.9.0</version>
</dependency>

Resolve from GitHub Packages -- add to your pom.xml:

<repositories>
  <repository>
    <id>github-firefly-operationOS</id>
    <url>https://maven.pkg.github.com/firefly-operationOS/flycanon</url>
  </repository>
</repositories>

What's Changed

  • The answer engine speaks Azure, and three places stop creating an extension a managed PostgreSQL reserves by @ancongui in #75

Full Changelog: v26.8.0...v26.9.0

v26.8.0

Choose a tag to compare

@github-actions github-actions released this 24 Sep 17:29
1f0f3c4

Python SDK

Install the wheel for this release with uv:

uv add https://github.com/firefly-operationOS/flycanon/releases/download/v26.8.0/flycanon_sdk-26.8.0-py3-none-any.whl

Or pin it in your pyproject.toml:

[project]
dependencies = ["flycanon-sdk"]

[tool.uv.sources]
flycanon-sdk = { url = "https://github.com/firefly-operationOS/flycanon/releases/download/v26.8.0/flycanon_sdk-26.8.0-py3-none-any.whl" }

Java SDK

<dependency>
  <groupId>com.firefly</groupId>
  <artifactId>flycanon-sdk</artifactId>
  <version>26.8.0</version>
</dependency>

Resolve from GitHub Packages -- add to your pom.xml:

<repositories>
  <repository>
    <id>github-firefly-operationOS</id>
    <url>https://maven.pkg.github.com/firefly-operationOS/flycanon</url>
  </repository>
</repositories>

What's Changed

  • feat(26.8.0): any embedder, and a way to change it by @ancongui in #74

Full Changelog: v26.7.1...v26.8.0

v26.7.1 — Multi-tenant hardening for a shared deployment

Choose a tag to compare

@ancongui ancongui released this 24 Sep 14:11
2b56108

Multi-tenant hardening for a shared deployment

This release is what a second caller found. The dworkers control plane runs one shared flycanon for all of its tenants, and wiring it against 26.7.0 turned up defects a single-tenant stack cannot see — where every process is the database owner and the only client is the one that wrote the docs. The API-key gate that was read by nothing is now enforced, an erased document is erased from the object store and not only from the index, outbound fetches and callbacks refuse anything that is not globally routable, callbacks are signed, a whole workspace can be purged, search returns rows under the NOBYPASSRLS serving role that docs/deployment.md prescribes, the boot-time DDL that role could not run has moved into a migration, and the RLM can finally be pointed at Claude 4.6+ / 5.

Security

  • FLYCANON_API_KEYS is now enforced. The setting existed since the first release and was read by nothing: anyone who could reach port 8500 could read or write any tenant and mint agent tokens for it. ApiKeyMiddleware now requires X-API-Key: <key> or Authorization: ApiKey <key> on every /api/v1/* route except GET /api/v1/version, and on the admin dashboard, whenever at least one key is configured (401 missing_api_key / 401 invalid_api_key, RFC 7807, constant-time comparison). /api/v1/agent/* requests that carry X-Agent-Token are exempt -- the token is their credential. With the setting empty the service stays open as before and the boot log says so (api-key gate DISABLED); with keys it logs api-key gate ENABLED: n key(s).
  • Admin dashboard requires authentication (pyfly.admin.require-auth defaults to true, overridable with FLYCANON_ADMIN_REQUIRE_AUTH=false for loopback dev). A validated platform key is bridged into pyfly's SecurityContext (ApiKeyPrincipalFilter) so the dashboard answers to the key and refuses everything else.
  • Outbound host policy (SSRF guard). uri fetches and callback_url webhooks refuse every address that is not globally routable -- loopback, private (RFC 1918 / ULA), link-local (instance metadata), multicast, reserved, unspecified, RFC 6598 shared address space (100.64.0.0/10: CGNAT, Tailscale, the pod CIDR of most managed Kubernetes clusters), site-local, documentation and benchmarking blocks; the decision is ipaddress's is_global, the named checks only shape the message -- literal, DNS-resolved, and on every redirect hop (redirects are now followed by hand, at most five) -- with 400 url_fetch_forbidden_host / 400 callback_url_not_allowed. FLYCANON_URL_FETCH_ALLOW_PRIVATE=true lifts the denylist for private dev stacks. Fetcher failures now render as problem+json (url_fetch_* codes, 400 / 413 / 502) instead of the framework 500. Documented gap: DNS rebinding between check and dial.
  • Signed webhooks. Async-ingest callbacks carry X-Flycanon-Signature: t=<unix>,v1=<hex HMAC-SHA256 over the raw body> when FLYCANON_WEBHOOK_SECRET is set (unsigned + boot warning otherwise), and the payload now carries tenant_id / workspace_id. verify_signature ships in flycanon.web.conventions.webhook_signature.

Added

  • User-tier DELETE /api/v1/sources/{id} (204; 404 source_not_found). Both it and the agent-tier DELETE now delete the stored original from the object store as well as the index, chunks and row -- before, an "erased" document stayed readable by the RLM corpus. IntakeService.remove returns a SourceRemoval, and its original_deleted is a fact, not a promise: the store is asked whether the object exists before the (no-op-on-missing) delete, and a key that is not in this process's store is logged as a warning and reported false -- the audit payload, the SourceRemoved event and the purge counter all carry that same value.
  • POST /api/v1/workspaces/{id}:purge -> WorkspacePurgeResult. Removes every source through the full pipeline, then knowledge items / versions / citations / relations, candidates, conversations / turns, ingest jobs / events and cost events in one transaction, closes the workspace and emits WorkspaceDeleted; audit rows are kept and a workspace.purged row records the counts. X-Workspace-Id must equal the path id (400 workspace_scope_mismatch). Idempotent in the literal sense: every counter is what this call erased, originals_deleted counts objects actually found and deleted, and closed is true only for the call that moved the row to closed (WorkspaceRepository.close_if_open); a repeat is all zeros with closed: false, restamps nothing, publishes no second WorkspaceDeleted and writes no second audit row.
  • Job-stream resume. GET /api/v1/ingest-jobs/{id}/stream accepts ?after_id=<id> and the standard Last-Event-ID header, and stamps id: on every event frame, so a reconnect no longer replays the whole history (the docs had promised after_id since 26.5).
  • FLYCANON_ADMIN_DATABASE_URL. WorkspaceRepository.list_for_tenant (GET /api/v1/workspaces) runs on this BYPASSRLS engine; under the production flycanon_app role the request engine could only ever return the caller's own header workspace.
  • OpenAPI wire contract. openapi.json declares securitySchemes (ApiKeyHeader, ApiKeyAuthorization, AgentToken) and reusable header parameters (X-Tenant-Id, X-Workspace-Id, X-Correlation-Id, Idempotency-Key) attached to every operation, so a generated client sends the mandatory headers. security describes what satisfies the operation, not what the middleware lets through: /api/v1/agent/* lists AgentToken alone (the platform key is neither required nor accepted there -- the route answers 401 missing_agent_token), every other tenant operation lists the two platform-key forms.
  • Scope on ingest events. Every flycanon.ingest payload (SourceIngested, SourceReplaced, SourceRemoved, SourceIngestionFailed, IngestSourceRequested, IngestSourceFinished, IngestSourceFailed) carries tenant_id / workspace_id -- including the IngestSourceRequested the stuck-job sweep republishes: IngestJobRepository.reclaim_stuck returns ReclaimedJob(job_id, tenant_id, workspace_id) and the service has no unscoped publish path.

Changed

  • Conversations use the same engine as /query. ConversationService is wired to AnswerDispatcher, so POST /conversations/{id}/turn answers with RLM by default and only with the deprecated RAG engine under FLYCANON_ANSWER_MODE=rag (then with the X-Flycanon-Deprecation header, like /query).
  • Framework pins moved to pyfly v26.09.04 and fireflyframework-agentic v26.06.14; the unit suite, ruff and pyright pass unchanged on them. uv.lock is now committed and CI / the Dockerfile run uv sync --locked.
  • API and worker no longer share a Postgres-outbox consumer group. pyfly's CQRS auto-configuration subscribes a cache-invalidation bridge on * in every process, so an API on the worker's group advanced the shared cursor past IngestSourceRequested events and ?mode=async jobs stayed queued forever. The API defaults to flycanon-api, flycanon worker to flycanon-workers (FLYCANON_EDA_GROUP overrides either).
  • FLYCANON_RLM_ANSWER_MODEL removed. CanonSettings.rlm_answer_model shipped with the RLM settings in 26.7.0, documented as "the model for the final single-shot answer synthesis", and was read by nothing: the RLM's final answer is produced by the root model, either as the final(...) tool call of the CodeAct loop or as the tool-less forced-final turn when the loop runs out (both chat_raw turns on FLYCANON_RLM_ROOT_MODEL); the sub model serves the llm() / rlm() helpers and the self-consistency selector. There is no single-shot synthesis step for a third model to drive, so the knob is gone rather than wired; CanonSettings ignores unknown FLYCANON_* variables, so an env file that still sets it boots unchanged. The docs, env_template and the README now name two RLM models and say which one answers (tests/unit/rlm/test_which_model_answers.py records the request bodies of a whole session and pins it).
  • Both entry points export pyfly's _PYFLY_SERVER_* variables. pyfly logs server_started in every process with 0.0.0.0:8080 as the fallback. flycanon serve exports uvicorn / 0.0.0.0 / FLYCANON_PORT so the line reports the real socket; flycanon worker, which runs no server, exports none / - / 0 so the line cannot claim a listener the process does not hold, and logs its own "no HTTP listener in this process" line beside it.

Fixed

  • The shipped image could not ingest. The localfs object-store default ./var/objects resolved to the root-owned /app/var under the canon user, so the first ingest failed with EACCES. The image now exports FLYCANON_OBJECT_STORE_LOCALFS_ROOT=/app/canon-data/objects (volume-backed) and pre-creates /app/canon-data/objects and /app/var/objects with canon ownership.
  • Sandbox child on macOS. RLIMIT_AS is not settable on Darwin; the RLM sandbox runner now tolerates that refusal there (CPU and file-size caps still apply) instead of dying at startup, which had failed 27 unit tests on every developer Mac.
  • Zero search hits under the application role. PostgresCorpus (the BM25 channel) ran its reads on a bare Core connection of its own engine, where the ORM after_begin listener that sets the app.tenant_id / app.workspace_id GUCs never fires; under FORCE RLS a NOBYPASSRLS serving role (flycanon_app, as docs/deployment.md prescribes) therefore saw no chunk on the lexical channel and no row on the RRF hydration, and /search and /agent/search answered hits: [] while the vector channel alone found the chunk. Invisible in a stack where every process is the database owner. Every scoped corpus read now binds the GUCs itself, from the explicit (tenant_id, workspace_id) it is handed, through `set_conf...
Read more

v26.7.0 — Agent-tier source replace + delete

Choose a tag to compare

@miguelgfierro miguelgfierro released this 23 Jul 06:37
80cdac4

Agent-tier source lifecycle: replace and delete

This release completes the agent-tier source API so an automated caller can keep an indexed document in sync across its whole lifecycle — not just create it. A machine client holding an agent.sources:ingest token can now replace a source's content in place or remove it entirely, with the dense vectors and BM25 rows kept consistent on every path. It also makes pyproject.toml the single source of truth for the service version.

Added

  • Agent-tier source replace. PUT /api/v1/agent/sources/{source_id} (scope agent.sources:ingest, mandatory Idempotency-Key) re-ingests an existing source in place through the same pipeline as the user-tier PUT: chunks and dense vectors are replaced under the same source_id. content_base64 is required; replays dedup under a route-specific scope.
  • Agent-tier source delete. DELETE /api/v1/agent/sources/{source_id} (scope agent.sources:ingest, mandatory Idempotency-Key, 204) removes a source within the tenant/workspace scope: BM25 rows and dense vectors are purged, chunk rows and the source row are deleted, an audit entry is recorded and a SourceRemoved EDA event is published. Object-store originals are not touched. A retried DELETE with the same key replays the original 204.

Changed

  • Single-source version. __version__ (and the version reported by pyfly_application / GET /api/v1/version) is now derived from the installed package metadata via importlib.metadata, so pyproject.toml is the only place a release bump touches.

Python SDK

Install the wheel for this release with uv:

uv add https://github.com/firefly-operationOS/flycanon/releases/download/v26.7.0/flycanon_sdk-26.7.0-py3-none-any.whl

Or pin it in your pyproject.toml:

[project]
dependencies = ["flycanon-sdk"]

[tool.uv.sources]
flycanon-sdk = { url = "https://github.com/firefly-operationOS/flycanon/releases/download/v26.7.0/flycanon_sdk-26.7.0-py3-none-any.whl" }

Java SDK

<dependency>
  <groupId>com.firefly</groupId>
  <artifactId>flycanon-sdk</artifactId>
  <version>26.7.0</version>
</dependency>

Resolve from GitHub Packages -- add to your pom.xml:

<repositories>
  <repository>
    <id>github-firefly-operationOS</id>
    <url>https://maven.pkg.github.com/firefly-operationOS/flycanon</url>
  </repository>
</repositories>

What's Changed

Full Changelog: v26.6.19...v26.7.0

v26.6.19

Choose a tag to compare

@miguelgfierro miguelgfierro released this 30 Jun 14:10
8590abf

RLM reliability fixes + tuning levers

This release hardens the RLM answer engine so it can no longer return a silent empty answer, and adds two opt-in levers for hard questions.

Fixed

  • Empty-answer bug. When the CodeAct loop exhausted its iteration budget without calling final(), it returned an empty string flagged as a valid answer (no_answer=false) that callers could not detect. A blank result is now surfaced as no_answer=true with an explanatory note, and the out-of-iterations fallback re-asks the model with no tools so a diverged run must emit text instead of nothing.

Added

  • CodeAct turn logging + convergence warnings — per-turn DEBUG trace and a WARNING when the loop exhausts its budget without converging.
  • Per-request extended_reasoning (AnswerRequest.extended_reasoning, default false) — runs the engine at twice the configured FLYCANON_RLM_MAX_ITERS for a single hard request, without a global default bump. RAG ignores it.
  • Self-consistency guard (FLYCANON_RLM_SELF_CONSISTENCY, default 1 = off) — when >1, the non-streaming answer path runs the engine N times in parallel and an LLM selector returns the most-grounded answer; token usage of all runs + the selector is merged.

Changed

  • Scoped RLM system prompt — requires verifying every benchmark/threshold/figure against the source documents and forbids stating a value not found in them.

Build

  • boto3 is now declared in the dev extra so the S3 object-store backend's unit tests and the pyright type-check of storage/s3.py run deterministically in CI (they previously relied on a transitive path that went away).

Python SDK

Install the wheel for this release with uv:

uv add https://github.com/firefly-operationOS/flycanon/releases/download/v26.6.19/flycanon_sdk-26.6.19-py3-none-any.whl

Or pin it in your pyproject.toml:

[project]
dependencies = ["flycanon-sdk"]

[tool.uv.sources]
flycanon-sdk = { url = "https://github.com/firefly-operationOS/flycanon/releases/download/v26.6.19/flycanon_sdk-26.6.19-py3-none-any.whl" }

Java SDK

<dependency>
  <groupId>com.firefly</groupId>
  <artifactId>flycanon-sdk</artifactId>
  <version>26.6.19</version>
</dependency>

Resolve from GitHub Packages -- add to your pom.xml:

<repositories>
  <repository>
    <id>github-firefly-operationOS</id>
    <url>https://maven.pkg.github.com/firefly-operationOS/flycanon</url>
  </repository>
</repositories>

What's Changed

Full Changelog: v26.6.18...v26.6.19