Skip to content

Releases: Sebastian197/korvun

v0.5.0

Choose a tag to compare

@github-actions github-actions released this 26 Jul 18:38

Korvun v0.5.0

The fifth release adds Korvun's third channel: a generic Webhook. Any system that
speaks JSON over HTTP becomes a mouth into Korvun — no provider account, no SDK.
No breaking changes: every existing config runs exactly as before, and go.mod is
untouched (stdlib only).

Highlights

Generic Webhook channel (ADR-0038)

The Stage-2 webhook adapter is now a first-class core channel: declare type: "webhook" in your config and Korvun opens an authenticated HTTP endpoint that turns
inbound JSON into a message, routes it through a brain, and POSTs the reply back to a
URL you choose. What it brings:

  • Mandatory, fail-closed Bearer auth. Every request must carry Authorization: Bearer <secret>, compared in constant time (SHA-256 + subtle.ConstantTimeCompare
    — the same mechanism as the admin gate, ADR-0028 §1). An empty/unresolved secret
    rejects every request; the body is never read on a 401, and the secret never
    appears in a log or error.
  • Conversation identity. A configurable conversation_id field groups messages
    into one conversation for brain memory; when a payload omits it, Korvun falls back
    to the sender id
    , and the reply echoes the conversation id back to your
    outbound URL.
  • Honest saturation. A momentarily full inbound buffer answers 503 (retry
    later)
    and counts the drop — it never blocks the HTTP goroutine on a slow
    brain.
  • Loopback by default, warned when exposed. The endpoint binds 127.0.0.1:8090;
    binding a non-loopback address emits a loud boot warning that the Bearer secret
    would cross the network in cleartext without a TLS-terminating reverse proxy in
    front (Korvun terminates no TLS itself).
  • Two env-only secrets. token_env (inbound, required) and an optional
    outbound_token_env (outbound Bearer to your receiver) — both are env-var names,
    never values (ADR-0010). A named outbound secret that does not resolve at boot is
    a loud, named error, never a silent unauthenticated outbound.
  • Edge validation. POST only (else 405), application/json (else 415), ≤ 1 MiB
    body (else 413), well-formed JSON with a sender and content (else 400).

Validated end to end on real hardware (2026-07-26, Intel iMac, macOS 13): a real
curl message into the webhook was routed through a local llama3.2:1b brain and the
reply — carrying the same conversation_id — arrived at a one-line test receiver in
~11s cold / ~1s warm; the unauthenticated request was correctly rejected with 401, and
the process shut down cleanly on SIGINT.

New guide — zero to round-trip

A new docs/WEBHOOK-SETUP.md walks the whole path: generate the
secret (openssl rand -hex 32), curl a message in, watch the brain's replies with a
one-line python3 test receiver, read what each rejection means (401/415/413/400,
and 503 = retry), and expose it safely behind a minimal reverse-proxy/TLS snippet. The
full schema lives in the new webhook section of
docs/CONFIGURATION.md, and configs/korvun.example.json ships
a webhook channel example.

Korvun Desktop carries it too

Korvun Desktop 0.5.0 embeds the webhook channel in the core from day one — it is
declarable by JSON config exactly like the headless binary. The visual form for it
arrives later with the Builder-canvas; today it is config-driven.

Compatibility

No breaking changes. The schema addition is strictly additive: existing
telegram/discord configs parse, validate, and behave byte-for-byte as before. Zero
new dependencies
— the channel is pure standard library (net/http, crypto/sha256,
crypto/subtle), so go.mod is unchanged.

Minor

  • V1 criteria updated on the roadmap; the Webhook piece marked complete
    (docs/ROAD-TO-BETA.md).
  • Docs: WEBHOOK-SETUP.md, the webhook block in CONFIGURATION.md, the example
    config, and the setup/config cross-links.

Artifacts

Two families in one release, exactly as v0.4.0. <ver> is the version without the
leading v (e.g. 0.5.0).

Family Artifact Target
Headless korvun_<ver>_{linux,darwin}_{amd64,arm64}.tar.gz, korvun_<ver>_windows_{amd64,arm64}.zip server / CLI, six OS·arch
Headless checksums.txt + .sig + .pem, per-archive *.sbom.json signed manifest + SBOMs
Desktop korvun-desktop_<ver>_darwin_universal.dmg macOS universal app
Desktop korvun-desktop_<ver>_windows_amd64-installer.exe Windows NSIS installer
Desktop korvun-desktop_<ver>_linux_amd64.tar.gz Linux binary + .desktop
Desktop checksums-desktop.txt + .sig + .pem signed desktop manifest

Draft-until-complete: the release is born a draft and is published only once
both families and their signatures are present, so a broken desktop build can never
expose a half-populated public release (ADR-0035 §8; SP7 §1e).

Verifying this release

Both families are signed keyless with cosign
(Sigstore), each with its own manifest. Verify the manifest signature you need, then
check your download against it.

Headless:

cosign verify-blob checksums.txt \
  --signature checksums.txt.sig \
  --certificate checksums.txt.pem \
  --certificate-identity-regexp 'https://github.com/Sebastian197/korvun/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Desktop:

cosign verify-blob checksums-desktop.txt \
  --signature checksums-desktop.txt.sig \
  --certificate checksums-desktop.txt.pem \
  --certificate-identity-regexp 'https://github.com/Sebastian197/korvun/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Full install and verification walkthrough: docs/packaging/INSTALL.md.
For the webhook channel specifically: docs/WEBHOOK-SETUP.md.

v0.4.0

Choose a tag to compare

@github-actions github-actions released this 26 Jul 11:17

Korvun v0.4.0

The fourth release. Korvun ships as Korvun Desktop — the same in-process core
behind a native window — alongside the unchanged headless binary. No breaking
changes: every existing headless setup runs exactly as before.

Highlights

Korvun Desktop — the same core, in a native window (ADR-0035, ADR-0036)

The full Go gateway now runs in-process behind a native desktop window: one
binary, one version, one release. Double-click, no terminal. What the app adds
over the headless binary:

  • First-run onboarding. A fresh launch writes a valid starting config and
    walks you through the first channel and brain — no hand-edited JSON.
  • Secrets in the OS keychain. A three-step assistant stores every bot token in
    the system keychain (Keychain on macOS, Credential Manager on Windows, Secret
    Service on Linux); the config only ever holds the variable name, never a
    value — the env-only secret contract is preserved exactly.
  • The visual builder, embedded. The same no-code builder runs same-origin
    inside the window, so brains, models, and routes are editable without a browser.
  • Live Inicio / Actividad. The dashboard shows the gateway status, per-window
    message counters, channel health and brains, and an Activity feed where each
    routing decision is explained where it happens.

Built with Wails on the system WebView, so there is no bundled browser.
The headless binary is byte-for-byte unchanged and is still the way to run
Korvun on a server.

Validated end to end on real hardware (2026-07-26, Intel iMac, macOS 13): the
universal Korvun.app from CI — double-clicked, token from the keychain, zero
terminal — completed a full Telegram round-trip through a local llama3.2:1b
brain.

Unsigned builds — clear the first-launch warning once

There is no paid platform signing (no Apple notarization, no Windows
Authenticode — a deliberate, cost-free decision, ADR-0035 §7). Integrity and
transparency are fully covered by cosign + the Rekor tlog; platform identity is
not
, so each OS shows a first-launch warning you clear once:

  • macOS: System Settings → Privacy & Security → Open Anyway (or, on older
    macOS, right-click → Open → Open).
  • Windows: SmartScreen → More info → Run anyway.
  • Linux: no gate; needs a WebKitGTK runtime present.

Full per-OS walkthrough: docs/packaging/INSTALL.md.

Artifacts

Two families in one release. The headless six are unchanged; the desktop three are
new, built on native runners (cgo needs the host toolchain, so no ARM64 desktop
yet). <ver> is the version without the leading v (e.g. 0.4.0).

Family Artifact Target
Headless korvun_<ver>_{linux,darwin}_{amd64,arm64}.tar.gz, korvun_<ver>_windows_{amd64,arm64}.zip server / CLI, six OS·arch
Headless checksums.txt + .sig + .pem, per-archive *.sbom.json signed manifest + SBOMs
Desktop korvun-desktop_<ver>_darwin_universal.dmg macOS universal app
Desktop korvun-desktop_<ver>_windows_amd64-installer.exe Windows NSIS installer
Desktop korvun-desktop_<ver>_linux_amd64.tar.gz Linux binary + .desktop
Desktop checksums-desktop.txt + .sig + .pem signed desktop manifest

Draft-until-complete: the release is born a draft and is published only once
both families and their signatures are present, so a broken desktop build can
never expose a half-populated public release (ADR-0035 §8; SP7 §1e).

Compatibility

No breaking changes. The headless binary, its config schema, and the env-only
secret contract are unchanged. Korvun Desktop is a new way to run the same
core, not a change to it.

Verifying this release

Both families are signed keyless with cosign
(Sigstore) on the same free chain, each with its own manifest. Verify the manifest
signature you need, then check your download against it.

Headless:

cosign verify-blob checksums.txt \
  --signature checksums.txt.sig \
  --certificate checksums.txt.pem \
  --certificate-identity-regexp 'https://github.com/Sebastian197/korvun/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Desktop:

cosign verify-blob checksums-desktop.txt \
  --signature checksums-desktop.txt.sig \
  --certificate checksums-desktop.txt.pem \
  --certificate-identity-regexp 'https://github.com/Sebastian197/korvun/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Full install and verification walkthrough: docs/packaging/INSTALL.md.

v0.3.0

Choose a tag to compare

@github-actions github-actions released this 19 Jul 07:39

Korvun v0.3.0

The third release. Korvun speaks Discord: a complete third channel — Gateway
WebSocket in, REST out — validated end to end on real hardware. No breaking
changes: existing Telegram and Webhook setups run unchanged.

Highlights

The Discord channel, hardware-validated (ADR-0033)

Korvun now serves Discord alongside Telegram and the generic Webhook channel. It
is a new adapter behind the same channel.Channel seam — the router, brains, and
policies are untouched — and it was validated end to end on real hardware
(2026-07-19, iMac Intel, macOS 13): a human message in a guild channel was routed
through a brain to a local model, and the reply came back in the same
channel, within the same minute
.

What the channel does:

  • Receiving over the Gateway (WebSocket), with a resume/reconnect supervisor.
    Free-form Discord messages only arrive over the Gateway, so the adapter keeps a
    supervised WebSocket session: it survives connection drops, resumes the
    session where it left off (no missed-event window on a clean resume), backs off
    exponentially between attempts (no reconnect storms), and treats Discord's
    fatal close codes as named terminal errors — no blind retry against an
    unrecoverable close (e.g. an invalid token or a missing intent).
  • Sending over plain REST, with mentions blocked by default. Replies are
    posted with allowed_mentions set to none, so a model's output can never
    ping
    @everyone, @here, a role, or a user — whatever the model writes.
    Long replies are split rune-safely at Discord's 2000-character limit, and a
    429 maps to Korvun's house rate-limit error grammar.
  • A complete anti-loop family. Messages from the bot itself, from other
    bots, and from webhooks are dropped by design at the channel edge — the bot
    cannot answer itself and two bots cannot ping-pong.
  • A step-by-step bot setup guidedocs/DISCORD-SETUP.md:
    Developer Portal, token (environment-only, never in the config file), the
    easy-to-miss Message Content intent switch, the OAuth2 invite, and a
    troubleshooting section grown from the real validation run.
  • A new metrickorvun_channel_reconnects_total{channel} counts Gateway
    reconnects, so a flapping connection is visible on /metrics.

A fourth dependency, deliberately (ADR-0034)

The Gateway needs a WebSocket client, and the Go standard library does not ship
one. v0.3.0 adds the project's fourth direct dependency,
coder/websocket v1.8.15 — pure Go, zero transitive dependencies, so the
cross-compile matrix (six OS/arch targets, CGO_ENABLED=0) is intact. The
decision, the alternatives, and the four-axis dependency test are recorded in
ADR-0034.

Compatibility

No breaking changes. If you use Telegram or the Webhook channel, v0.3.0
changes nothing for you. Discord is an additive config block — a new entry in
channels ("type": "discord", "mode": "gateway", "token_env": "...") plus a
route; see docs/CONFIGURATION.md and the setup guide.

Verifying this release

Releases are signed keyless with cosign (Sigstore)
and ship an SBOM. Verify the checksums signature, then check your archive against the
verified checksums.txt:

cosign verify-blob checksums.txt \
  --signature checksums.txt.sig \
  --certificate checksums.txt.pem \
  --certificate-identity-regexp 'https://github.com/Sebastian197/korvun/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Full install and verification walkthrough: docs/packaging/INSTALL.md.


Full commit changelog: v0.2.0...v0.3.0

v0.2.0

Choose a tag to compare

@github-actions github-actions released this 18 Jul 14:57

Korvun v0.2.0

The second release. It closes the cold-start failure that could drop the very first
message, ships the full command-line surface, and is the first release whose binary
reports its real version. No breaking changes — every v0.1.0 invocation still works.

Highlights

Cold-start is fixed (ADR-0031)

On v0.1.0, a first-time model load slower than Korvun's fixed ~5s provider timeout
would abort: Ollama cancelled the load, and the user's first message failed. v0.2.0
resolves it — production error handling landed:

  • Boot warmup — local models are warmed at startup, best-effort (a warmup failure
    logs and does not block boot).
  • Generous per-attempt timeout — configurable per model, defaulting generous so a
    slow cold load is not guillotined.
  • Retry with differentiated fallback — transient post-load failures retry with
    backoff; a genuine timeout is not retried (retrying a mid-load model just re-aborts
    it). If every provider is down, the reply is an honest fallback, not a crash.

Verified on the same hardware that first surfaced the bug (iMac Intel, macOS 13): the
first cold request completed in ~6s with no timeout, where v0.1.0 failed.

A first-class CLI (ADR-0032)

korvun now has real subcommands instead of a single flag-driven binary:

korvun serve --config korvun.json            # load config, wire, serve
korvun config check --preflight korvun.json  # validate offline (+ online checks)
korvun status                                # live wiring of a running instance
korvun version
korvun help
  • config check validates a config offline (structure, enums, timeouts — no network,
    no secrets); --preflight additionally resolves secrets, runs the privacy selector,
    and reaches the channel/providers.
  • status is a thin read-only client of the admin API (/healthz + /api/brains +
    /api/channels) — no token, no new server code.
  • Output is styled on an interactive terminal and stays machine-clean otherwise:
    NO_COLOR, --plain, and --no-color all turn styling off, and colored output
    degrades to 256-indexed so it renders correctly everywhere (Apple Terminal included).

Example config shipped in the archive

Every release archive now bundles korvun.example.json — a minimal, valid starting
config you can validate with korvun config check korvun.example.json and adapt. It
was not in the v0.1.0 archive.

The binary reports its real version

v0.2.0 is the first release whose binary reports its actual version. The release
build's version ldflags were retargeted to the package where the version variable now
lives, so korvun version (and --version) print korvun v0.2.0 (<revision>)
instead of dev.

Compatibility

No breaking changes. The pre-CLI invocation korvun -config <path> still works —
a retrocompat shim routes it to serve unchanged — so existing docs, scripts, and the
systemd unit keep working. korvun serve --config <path> is the new canonical form.

Verifying this release

Releases are signed keyless with cosign (Sigstore)
and ship an SBOM. Verify the checksums signature, then check your archive against the
verified checksums.txt:

cosign verify-blob checksums.txt \
  --signature checksums.txt.sig \
  --certificate checksums.txt.pem \
  --certificate-identity-regexp 'https://github.com/Sebastian197/korvun/.*' \
  --certificate-oidc-issuer https://token.actions.githubusercontent.com

Full install and verification walkthrough: docs/packaging/INSTALL.md.


Full commit changelog: v0.1.0...v0.2.0

v0.1.0

Choose a tag to compare

@github-actions github-actions released this 04 Jul 10:40

Changelog

Features

  • 2f8d7cb feat(agents): Stage 8 tool-use AgentBrain with bounded loop and safe Tool seam
  • 5837e09 feat(app): wire Config into a ready router (catalog, selector, getMe boot, lifecycle) (ADR-0017 §0)
  • e400f61 feat(brain): orchestrator + WithModelID decorator + demo-brain (ADR-0014)
  • 4e9afc1 feat(bus): event bus + additive router event hook (ADR-0023, Stage 14 Phase 1a)
  • 65e0d6e feat(channel): add Channel interface, Manifest, and Registry
  • d5f574b feat(channel): add generic webhook adapter
  • 4ae51ed feat(cmd): thin korvun main wiring config + app + signal lifecycle (ADR-0017 §0)
  • 9b98a5e feat(config): JSON deployment descriptor parse + validate (ADR-0017 §1)
  • ac88478 feat(controlapi): Stage 13 read-only control API (ADR-0022)
  • d158918 feat(conversation): ConversationStore interface + in-memory impl + Brain injection (ADR-0018)
  • 18debff feat(conversation): durable SQLite conversation store (Stage 9 ADR-B)
  • 3ad59bf feat(envelope): add Keyboard, Callback, CallbackAck (Phase 2E.4)
  • 02e666c feat(envelope): add PartType.Location (Phase 2E.3)
  • b5b711c feat(envelope): add PartType.Reaction and OperationKind.OpSetReaction (Phase 2E.7)
  • b16d59a feat(envelope): add base domain types
  • 5af6a98 feat(envelope): add identity generation and builder
  • 371a4d4 feat(envelope): add validation and JSON serialization
  • 7be2f08 feat(envelope): introduce Operation, migrate CallbackAck (Phase 2E.6)
  • 1c4eb2c feat(liveview): SSE live-view + embedded UI; wake the event bus (ADR-0024, Stage 14 Phase 1b)
  • 3d6a815 feat(model): add cloud-shaped sentinels for Phase 4.2 (ADR-0010 commit A)
  • 2862476 feat(model): types + Model interface + ValidateRequest (Phase 4.1 commit 1)
  • 3892b5c feat(observability): add Metrics seam + Prometheus impl (ADR-0020 step 2)
  • 0e80292 feat(observability): admin HTTP server with /metrics + /healthz (ADR-0020 step 3)
  • 2937a43 feat(observability): standardize slog funnel fields (ADR-0020 step 1)
  • 0d4e79f feat(observability): wire metrics to the existing funnels (ADR-0020 step 4)
  • 9aabdb5 feat(packaging): hardened systemd unit + signature-verify docs (ADR-0026)
  • 901a022 feat(policy): consensus reducer + demo-policy (ADR-0013)
  • 6f56795 feat(policy): pre-dispatch privacy selector — per-Brain SelectModels (ADR-0015)
  • 62f4c24 feat(policy): priority reducer + Decision/Policy types (ADR-0012)
  • a8075f9 feat(release): packaging + release pipeline (GoReleaser, --version) (ADR-0025, Stage 15)
  • 6a4814b feat(release): sign checksums with keyless cosign + SLSA provenance (ADR-0026)
  • 0d69683 feat(router): implement Phase 3.1 routing core
  • bc01d29 feat(router): implement Phase 3.2 concurrency and resilience
  • 350d8c8 feat(router): inbound pump draining Channel.Receive into DispatchInbound (ADR-0017 §2)
  • 5fae774 feat(telegram): Adapter struct, functional options, New validation (Phase 2E.8 sub-A)
  • c0b7f2f feat(telegram): Send dispatch over the botClient interface (Phase 2E.8 sub-B)
  • 9413e4f feat(telegram): Start/Stop lifecycle, HTTP server, SetWebhook/DeleteWebhook (Phase 2E.8 sub-E)
  • b6730cc feat(telegram): add outbound keyboard markup and callback ack (Phase 2E.4)
  • 33cefd1 feat(telegram): dispatchUpdate with conversion and bounded backpressure (Phase 2E.8 sub-C)
  • 112a630 feat(telegram): edit/delete operations + inbound edited_message (Phase 2E.6)
  • 3f3293a feat(telegram): hand-rolled webhook handler with constant-time secret check (Phase 2E.8 sub-D)
  • 4554827 feat(telegram): implement Channel adapter for inbound and outbound
  • 594f7de feat(telegram): map Location inbound/outbound to Envelope (Phase 2E.3)
  • 3f76e50 feat(telegram): map inbound MessageReaction to Envelope (Phase 2E.7)
  • ad583e1 feat(telegram): map inbound callback_query to Envelope (Phase 2E.4)
  • 581d0d5 feat(telegram): map inbound media to Envelope (Phase 2E.1)
  • a241bc5 feat(telegram): map outbound OpSetReaction to SetMessageReactionParams (Phase 2E.7)
  • 57c2cf5 feat(telegram): map outbound media to Telegram Send*Params (Phase 2E.2)
  • 027e981 feat(telegram): parse bot_command entities into Meta (Phase 2E.5)
  • be5a48d feat: merge Stage 1 — canonical Envelope

Bug fixes

  • afaf4f8 fix(agents): /review hardening — empty-reply fallback, fenced tool line, calc bounds
  • 0714475 fix(conversation): atomic AppendTurns for contiguous turn groups (ADR-0018 review)
  • 7078289 fix(conversation): persist final turn through graceful shutdown (ADR-B review)
  • 51b86cb fix(observability): dropped-source registration returns error, never panics
  • e69502e fix(sqlite): build a valid file: DSN for Windows drive-letter paths
  • de6c45b fix(telegram): close the close(inbound) race with in-flight dispatchUpdate (Phase 2E.8 review fix)

Others

  • 5640e1c Add Apache License 2.0 to the project
  • 41f5ca1 Add copyright notice for 2026
  • f9c709e Initial commit
  • ab04ee3 Merge branch 'chore/repo-hygiene': professional repo presentation
  • 5e9baff Merge branch 'feat/2e8-webhook-lifecycle' — close Stage 02-EXT
  • 34d699d Merge branch 'feat/agents': Stage 8 tool-use agents (ADR-0021)
  • 464f8c2 Merge branch 'feat/bus': event bus + router hook (ADR-0023, Stage 14 Phase 1a)
  • 057ee73 Merge branch 'feat/conversation-store': conversation store (Stage 9 ADR-A)
  • cee4a20 Merge branch 'feat/observability': Stage 12 observability (ADR-0020)
  • 7703ebc Merge branch 'feat/router-inbound-pump': router inbound pump (ADR-0017 §2)
  • 65549cf Merge branch 'feat/sqlite-store': durable SQLite conversation store (Stage 9 ADR-B)
  • 4f36447 Merge branch 'feat/sse-liveview': SSE live-view + UI, bus woken (ADR-0024, Stage 14 Phase 1b)
  • 5c6d448 Merge branch 'fix/sqlite-dsn-windows-path': valid file: DSN for Windows drive-letter paths
  • 904bf68 Merge feat/4.3-fanout: close Stage 4 (Models)
  • 24769ba Revise README.md for Korvun project details
  • 6192fba ci(release): add workflow_dispatch snapshot dry-run to exercise signing/OIDC (ADR-0026)
  • f3d9907 ci(release): attest provenance on real releases only (private-repo limitation)
  • cdebe0b ci(release): least-privilege token permissions (Scorecard Token-Permissions)
  • 01f28bf ci: add CodeQL SAST analysis
  • c893638 ci: add CodeQL static analysis for Go (Scorecard SAST)
  • e979b83 ci: add Dependabot config for gomod and github-actions
  • c64e797 ci: add SBOM generation job (SPDX JSON)
  • cabe345 ci: add cross-compile job for {linux,windows,darwin}×{amd64,arm64}
  • 15ac37b ci: disable Scorecard triggers until repo is public — Stage 16
  • 2463bbe ci: enforce real coverage gate (≥85% core, ≥90% critical packages)
  • 548909d ci: fix cross-platform CI failures (coverage guard, CRLF, CodeQL perms)
  • 8a7becf ci: re-enable scorecard on public repo
  • f3d6763 docs(adr): add ADR-0001 for Telegram client dependency
  • d5cf121 docs(adr): add ADR-0003 — router design (correlation + backpressure)
  • d9f8c60 docs(adr): correct ADR-0008 polling design — Bot.GetUpdates is internal-only in v1.21.0
  • de859ae docs(bus): harden contract per concurrency /review (F1/F2/F3)
  • 4d35541 docs(model/fanout): clarify concurrent-reuse and distinct-instance contracts (P2 + I9)
  • b234200...
Read more