Skip to content

Conduck 1.3 (build 9)

Choose a tag to compare

@peterkrueck peterkrueck released this 30 Aug 10:40
· 189 commits to main since this release

Conduck 1.3 (build 9) — macOS App Store release, 19 August 2026.

The file-lane, attention and trust release. ~240 commits since 1.2.

Install it: App Store — free for individuals.
Built from: commit 51fccc2, tagged v1.3-9 — marketing version 1.3, build 9. That tag is the exact source the shipped binary was built from.

Building this release yourself

Requires Xcode 26.5 or later. Open Conduck/Conduck.xcodeproj, build and run — no configuration needed.

What you get is Conduck Community: the same functionality under a neutral identity with placeholder artwork, minus CarPlay, which needs an Apple entitlement granted per developer team and cannot travel with source. No functional code is withheld from this repository — what is not here is the brand artwork, the signing identity, and that entitlement. See TRADEMARKS.md for what you may call a build you distribute.

Platform Minimum OS
iOS / iPadOS 26.5
macOS 26.5
watchOS 26.5

Software bill of materials

sbom-v1.3-9-51fccc2.json is attached: CycloneDX 1.5, naming this release's three direct dependencies with the exact revisions they were pinned to and their licences. Bundled licence texts are in THIRD_PARTY_NOTICES.md.

What is in 1.3

Files — the agent-file return lane rebuilt

  • Per-conversation output folders; every dispatch names its own and creates nothing (the AGENT creates it — a client-created folder locks the agent out on the two gateways most people use)
  • A reply's files come from the folder it was given, never parsed from its prose; an agent's refusal could previously mint four downloads, one from another conversation
  • Nothing downloads before a tap — up to 8 MB used to move on its own into a store that syncs to iCloud and the Watch
  • A hand-back is believed only when the server can also say no: probes read the body, and no "exists" verdict survives without a negative control on the same lane
  • Returned files keep their real name — the inbound gate was [A-Za-z0-9._-], so spaces, accents and every CJK name were listed, seen and discarded in silence
  • File-delivery capability is a property of each gateway; an upload-only server keeps its uploads, and only a structural 405/501 proves a server cannot list
  • A file that lands after the reply is no longer lost; a turn that got no folder says so when that is news; a refused name is reported as a census
  • Watch receives a returned file over the WatchConnectivity link (iCloud mirror measured seven minutes); no bytes, no credential
  • Clone carries its attachments and offers to resend the unanswered turn

Attention — the conversation list

  • Rows resolve to working / answered-unseen / failed / idle; a failure is reported only while it is still the last activity
  • Unread + failure acknowledgement are account facts, mirrored across devices and reaching the Watch; acknowledgement is keyed by delivery-attempt identity, so a retry re-arms it
  • Badges follow what the history spans, not what is configured; a forgotten custom keeps two characters and a colour so its archive does not go blank
  • A new chat starts on the gateway the last one used, via an App-Group pointer that never rides iCloud
  • macOS gains a reply notification, a quit-mid-turn confirmation and burst coalescing; the Watch writes its own sending status

Trust and security

  • A publicly-trusted certificate is now REQUIRED; a pin is an optional additional restriction on a chain the system already trusts. TOFU, the consent UI and every pin-as-authorisation path are deleted, and certFP is gone from conduck-setup:v1
  • Cross-host and scheme-downgrading redirects are refused rather than replayed with history, images, audio, file bytes and the auth token
  • Markdown image/emoji loading in replies is blocked outright; untrusted text is projected before it reaches a notification, headline, CarPlay row or VoiceOver label
  • Forgetting the last gateway now reaches the Watch, which kept a live route and token across reboots; a deleted voice endpoint takes its key with it
  • macOS sends ran on a session that structurally could not carry a pin, silently dropping a configured one that Test Connection honoured

Sync and multi-device correctness

  • The XCTest suite had been writing into the real App Group, iCloud KVS and synchronizable Keychain, syncing fixture gateways to every paired device; a storage seam plus a CI guard closes it
  • Gateway URL/model sync is hydrate-only, so a device offline during a peer's Forget no longer resurrects the gateway for everyone
  • Inbound mirrors added for remoteAgent.model.* and built-in authScheme.*; a built-in default pointer is always honoured, where healing the fallback used to move every message to another server

Performance

  • Reply-rendering scans that were quadratic are single passes; a 4 MB reply went from 16.4 MiB to 48 KiB of transient allocation
  • Claim ordering on a 16 MiB reply produced ~16.8M Substrings and half a gigabyte live — a crash CloudKit would have synced everywhere; now bounded and off the main actor

Setup, errors and diagnostics

  • Setup-code review screen: says where a code points, masked at rest, carries the file server's measured capabilities; readiness stops gating on what the next step supplies
  • Transport failures split by whether the request could have reached the server; Test Connection and a failed send finally agree
  • Free per-gateway recheck; Copy Diagnostics carries recent failed sends and a chat-proven record; a leftover gateway is named, marked and counted once
  • Out of credits and rate-limited keep Try again; a 403 no longer asserts the token is wrong; every error names the AI the user configured
  • The iOS row stops claiming the gateway is answering while the background session is still waiting for connectivity

macOS and iPad

  • MacPointerTargets: every mouse-reachable custom-drawn control is properly clickable; one settings rail, full-bleed rows, persistent back chrome
  • The sidebar fits its window (it was laid out 1399pt tall inside 949pt and centred); compose is pinned beside the sidebar toggle in every split state
  • The window asks whether ANY gateway can send, not whether the default one can; Esc targets the innermost editor instead of tearing down Settings
  • Drop a file anywhere on the conversation; iPad compose lives on whichever column's bar is on screen

Voice and Watch

  • Typed TTS playback outcomes route undecodable bytes, refused starts and mid-clip errors to the Apple fallback with transparency, where they used to end the turn in silence
  • Device-local TTS key readiness banner plus a bounded arrival monitor, since iCloud Keychain has no arrival event
  • An unreadable STT key is not an absent one — the recording outlives the refusal; a queued Watch capture the iPhone could not read is kept
  • Long errors are fully reachable on the wrist via a scrollable detail sheet

Project

  • Apache-2.0, SPDX headers on every tracked source file, in-app Open Source Licenses screen, DCO sign-off hook
  • spec.md + project-structure.md rewritten from 648 KB to 62 KB as decisions rather than description
  • CI source guards on Linux; the macOS TLS test bundle is compiled unconditionally

Release-gating fixes made in this build

  • ConverseIntent referenced DEBUG-only RemoteAgentDiagnostics on a line meant to ship — Release failed to compile on both platforms; it now uses an always-compiled os.Logger
  • Two test files referenced iOS-only symbols ungated (AppleSpeechRelayCoordinator, CarPlaySceneDelegate), breaking the macOS test-bundle compile and with it the live TLS trust suite

Verified: iOS 3925 tests / 0 failures · watchOS 206 / 0 · live TLS 16 / 0 · Release builds green on iOS and macOS · SBOM notices gate clean