Releases: GigaDuckAI/conduck
Release list
Conduck 1.6.4 (build 17)
This update lets you choose which Apple voice speaks Conduck's replies.
- Choose your Apple voice: Apple's on-device Text-to-Speech on iPhone, iPad and Mac gains a Voice setting. It lists the voices installed for your device's language, grouped Premium, Enhanced and Standard, and plays a sample when you tap one. Automatic keeps the system default. The choice stays on that device, since each device has its own installed voices, and applies to replies in the device's language. CarPlay replies use it too.
- No silent replies: a chosen voice whose files are missing no longer leaves a reply silent. The reply is spoken again in the default voice and marked Built-in voice. Later replies use the default until the voice plays again or you choose another.
- Deleted voices: deleting the chosen voice in system settings returns Conduck to Automatic.
- Previews: Settings and Diagnostics voice previews interrupted by another sound no longer stay on Playing, and Diagnostics samples the voice a reply would use.
For contributors: a shorter README with an architecture diagram, the glossary moved to CONTRIBUTING.md, and StoreKit purchase tests that run on the iOS 27 simulator.
Changes since 1.6.3.
Built from commit ae9c874, tagged v1.6.4-17. The attached CycloneDX SBOM lists this release’s dependency revisions and licenses.
Conduck 1.6.3 (build 16)
This update fixes a cause of background termination and improves iCloud storage warnings.
- Background stability: removes a file lock that iOS could terminate Conduck for holding when the app moved into the background. Content sync still waits for other Conduck sessions to stop before confirming it is off.
- Accurate iCloud warnings: an iCloud storage warning now remains until the affected content successfully uploads. Returning to the app no longer incorrectly dismisses it; temporary account interruptions and successful downloads are not treated as proof of recovery. Conduck also recovers unresolved storage warnings from recent sync history.
Changes since 1.6.2.
Built from commit 55d5572, tagged v1.6.3-16. The attached CycloneDX SBOM lists this release’s dependency revisions and licenses.
Conduck 1.6.2 (build 15)
Conduck 1.6.2 (build 15) — the iPhone bar tidy-up. 7 commits since 1.6.1.
Install it: App Store — iPhone, iPad and Mac. On iOS this follows 1.6 directly; 1.6.1 was a Mac-only update.
Built from: commit 00f7191, tagged v1.6.2-15 — marketing version 1.6.2, build 15. That tag is the exact source the shipped binary was built from.
What changed
- iPhone: the chat bar keeps four glyphs — Conversations, New conversation, the gateway title (the bar's only dropdown) and one icon that flips between Chats and Work. The "Chats ⌄" section menu is gone. Copy conversation moves into each bubble's actions menu. iPad and Mac are unchanged
- Free plan: the "Choose active gateways" reminder in Settings shows only while a choice is still needed; an inactive gateway's editor keeps the link for revising a completed choice
What is fixed
- iPhone and iPad: the composer's trailing button no longer flickers send → mic → Stop on every send. The attachment-only send keeps its slot while attachments are staged, and the recording / transcribing status row has one fixed height, so the bar stops jumping
- Work opens to the same connect-your-AI screen as Chats when no gateway is configured, with a button into the guided setup (iPhone, iPad, Mac)
Developer-facing
- README gains a two-minute quick start (Ollama on the LAN, OpenRouter, the adapter path)
docs/qa/qa-mode.mdnames the CloudKit environment of Xcode-installed builds correctly (Development)
Building this release yourself
Requires Xcode 26.6 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. See TRADEMARKS.md for what you may call a build you distribute.
Software bill of materials
sbom-v1.6.2-15-00f7191.json is attached: CycloneDX 1.5, naming this release's direct dependencies with the exact revisions they were pinned to and their licences. Bundled licence texts are in THIRD_PARTY_NOTICES.md.
Conduck 1.6.1 (build 14)
Conduck 1.6.1 (build 14) — the Mac sync fix. 5 commits since 1.6.
Install it: App Store — a macOS update; the iOS app stays at 1.6, which already behaves this way.
Built from: commit 23d6ab2, tagged v1.6.1-14 — marketing version 1.6.1, build 14. That tag is the exact source the shipped binary was built from.
What is fixed
- The Mac app now carries the push entitlement macOS needs for iCloud sync. In 1.6 the Mac was signed without it, so a conversation or a Work capture made on iPhone, iPad or Apple Watch reached the Mac only at the next scheduled import or when the app was brought to the front. With the entitlement the Mac imports within about a second of a push arriving. Apple's push service can still hold a Mac's notifications for a while; that part is outside the app
- Mac → iPhone, iPad and Watch, and every direction between the iOS devices, were already immediate and are unchanged
Developer-facing
- Debug builds log each iCloud import, export and setup event, and a
-ConduckInitializeCloudKitSchemalaunch flag fills the CloudKit Development schema before a Production deploy (seedocs/qa/qa-mode.md) - Builds with Xcode 27: two protocols gained the isolation annotation the new compiler requires, and the Watch schemes drop an attribute Xcode 27 removes
Building this release yourself
Requires Xcode 26.6 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. See TRADEMARKS.md for what you may call a build you distribute.
Software bill of materials
sbom-v1.6.1-14-23d6ab2.json is attached: CycloneDX 1.5, naming this release's direct dependencies with the exact revisions they were pinned to and their licences. Bundled licence texts are in THIRD_PARTY_NOTICES.md.
Conduck 1.6 (build 13)
Conduck 1.6 (build 13) — the Work release. 125 commits since 1.5.
Install it: App Store — free plan for individuals, with an optional Conduck Pro subscription.
Built from: commit 24d6373, tagged v1.6-13 — marketing version 1.6, build 13. That tag is the exact source the shipped binary was built from.
Building this release yourself
Requires Xcode 26.6 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. A Community build has no subscription product configured, so it sells nothing; the free-plan limits still apply unless you change the source. No functional code is withheld from this repository — what is not here is the brand artwork, the signing identity, the App Store product 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.6-13-24d6373.json is attached: CycloneDX 1.5, naming this release's 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.6
Work — a private desk beside your chats
- Work is a new destination next to Chats on iPhone, iPad, Mac, Apple Watch and CarPlay. It is a board of cards — thoughts, files, screenshots, photos, links and spoken notes — that you collect first and brief your AI with later. Adding to Work sends nothing to your AI. Every capture surface says so on its receipt: "Added to Work. Nothing was sent."
- Captures arrive from the app's composer, drag and drop, paste, the share sheet, Shortcuts, a chat message's menu, the Mac menu bar, Apple Watch and CarPlay. A link card saves the address as text; Conduck never fetches the page in the background
- Cards open in place: images in a full-screen gallery with a counter, arrow keys and Share; files in Quick Look; links in the browser. Any card can be shared, with a note going out as text, a link as a URL, and an image or file as a disposable copy
- Three layouts — Tiles, List and a freeform Canvas that pans and zooms, with Fit and Reset zoom. Cards keep the order you leave them in, in every layout, and a capture that lands mid-drag slips in behind the card you are holding rather than interrupting you. VoiceOver gets Move Earlier / Move Later and the Canvas exposes Move up / down / left / right and Zoom in / out as accessible actions
- Search across the whole of Work — "Find an idea or file" — crosses project boundaries on purpose
- A screenshot and the voice note spoken with it appear as one card, "Screenshot with note", with a play control and per-part Open, Share and Reattach actions
- Every image card is normalised at the desk write, on every lane: a JPEG capped at 1568 px on the long edge — the same size a chat turn sends inline — with EXIF, GPS, TIFF, IPTC and XMP metadata stripped. GIFs, multi-frame images and already-small clean JPEGs pass through untouched. This says nothing about images you send in a chat, which are unchanged
- A first visit to Work shows a four-page introduction — a home for your next idea, catch it where you find it, bring related ideas together, give your AI the right context. It appears once per device, only when you deliberately switch from Chats to Work, and steps aside for anything you are in the middle of
Work — projects
- Hold one card over another to group them into a project. A project has a name, one of six colours, an optional brief (standing instructions for every conversation started from it), a preferred gateway, its own layout, its own composer draft and its own Canvas viewport. Projects can be pinned and previewed without leaving the board
- Home holds loose cards; All materials shows everything, including cards filed into projects. A card can live in more than one project — Add to another project, Move, Remove from this project, Move to Home — and a card's detail says "In N projects". Filing, moving and removing can be undone from a banner
- A capture made from inside an open project — composer, file picker, drop or microphone — lands in that project; the destination is frozen at the moment you submit, so a slow import does not follow you to wherever you navigated next. The share sheet, Shortcuts, the menu bar, Watch and CarPlay have no project context and still land on Home. The capture bar and drop overlays name where the material will go, and a batch that saved but could not be filed says so with a count
- Notes on any material — "Add notes…" — travel with it into a conversation. Text cards and voice transcripts are editable, with the original kept behind Preview original. A card shows "Used in N conversations" and opens the conversation it was used in
- Deleting a project is reviewed: keep its materials (those only in that project return to Home; those used elsewhere stay put; notes are kept) or delete the project and its materials everywhere. A project that changed underneath the review forces a re-review
Work — briefing your AI
- New conversation from a project opens a full review: your task, a checklist of materials ("N of M included"), the gateway, and an exact preview of the outgoing message before Send. What the gateway can take is stated up front — text, images and attached files; text and images with file transfer not connected; or a hosted model with no file workspace
- Conversations started from a project stay nested under it in Work, and materials from elsewhere in Work can be pulled in without moving them. Drafts persist per project and survive an interrupted send, with explicit handling when another window changed the same draft
- With a self-hosted agent and file exchange set up, files your AI returns appear as Result cards in the project, each linking back to its source conversation. A file still on the gateway says so and tells you how to bring it in. On the hosted OpenRouter lane there is no file workspace, and the brief says so
- A conversation that belongs to a project is marked wherever it is listed: the project's folder and name on a Chats row and in search; a line under the thread's navigation bar with Show in Work; the project name on the Watch row's date line; and "2 hr ago · Q3 launch" on the CarPlay Recent row, capped at 24 characters with no colour and never any message content reaching the car screen
- A project that cannot take a new turn says why. When a project is archived, or a free-plan library holds more active projects than the allowance and no choice has been made yet, the reason appears above the composer with a button into Work, every send path refuses with the same sentence, and the draft, staged files and any capture in flight are kept
Work — spoken notes
- A spoken Work note reaches the desk as its words alone. Every voice lane bound for Work — the in-app sheet, the Mac menu bar, a Shortcut, CarPlay, the Watch relay — parks the recording in a device-local retry lane, transcribes it, writes a words-only card and deletes the audio. Nothing reaches the desk or iCloud before the words exist; a failed transcription leaves the desk untouched and the recording waiting behind Try Again, with a confirmed Discard
- The audio goes only to the speech provider you chose, and only to be turned into words — never into a conversation, and never through a server of ours. Conduck has no intermediary servers
- Recordings are kept only when you add them yourself, through the attachment button in Work or a drop into the Work pane; those become playable cards with one-at-a-time playback. The share sheet, the Add Files Shortcut and Chat → Work refuse a recording and name the door
Work — sync
- With content sync on, the desk syncs through your own private iCloud, bytes included, up to 30 MB per card. A larger file stays on the device that captured it; a confirmation says so at capture time, the card reads "Available on this device" elsewhere, and a Reattach action is offered. A card still arriving reads "Waiting for iCloud…" and stays inert until its bytes are proven present
- Card payloads live in a second store under their own iCloud container. The Watch mounts only the conversations store and holds no card bytes, by construction
- A named iCloud problem — signed out, storage full, restricted — gets its own banner instead of a silently unsynced desk
Conduck Pro and the free plan
- Conduck introduces a free plan and an optional Conduck Pro auto-renewing monthly subscription, sold and managed entirely by Apple. There is no Conduck account and no licensing server; access is derived on-device from Apple-signed transactions
- The free plan is exactly two allowances: three active Work projects, and three configured gateways in total across OpenClaw, Hermes and custom connections. OpenRouter never uses a gateway slot and is always available. Pro removes both limits
- The gateway allowance changed shape. It used to cap custom gateways only; it now counts built-in and custom gateways together. If you already have more than three configured, Conduck asks you to choose which three stay active. The others are retained with their credentials — they simply cannot dispatch until you pick them or subscribe. Nothing is deleted
- Archiving a project frees a slot and changes nothing else: every material, conversation and byte stays. An archived project refuses new materials and new turns until restored. Going over the project allowance — when a subscription ends, for instance — opens a Choose projects sheet that archives only after...
Conduck 1.5 (build 11)
Conduck 1.5 (build 11) — App Store release, 28 August 2026.
The measurement release. 27 commits since 1.4.
Install it: App Store — free for individuals.
Built from: commit 34b91f5, tagged v1.5-11 — marketing version 1.5, build 11. 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.5-11-34b91f5.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.5
Usage — measuring your own setup, on your own devices
- Settings gains a Usage screen on iPhone, iPad and Mac: how many turns you sent, how many landed, how long a complete answer took, and whatever your gateway was willing to say about tokens. It answers a question the app previously could not — is this setup actually working, and which of my gateways is the slow one
- The measurement never leaves your devices. A record is written beside the conversation it describes, in the same local database and the same private iCloud mirror that already holds your threads, and there is nowhere else for it to go: Conduck has no server, so a dashboard that reported home would have had to invent one. Nothing in this release changes what leaves the device
- The records are content-free, and that is a release-blocking constraint rather than a preference: no prompt or reply text, no gateway address or host, no token, no gateway name, no provider error string, no HTTP status. What is kept is timings, an outcome, a stable local error code, and the handful of fields the gateway itself reported — the gateway as the same opaque reference a conversation already binds to, with the name you read resolved when the screen is drawn. "There is nothing to disclose because there is no server" holds only while what is stored could not embarrass you if it were disclosed anyway, and usage data is exactly where that erodes, one convenient field at a time
- Writing a record is best-effort and can never block, lose or duplicate a reply. That is carried into the copy: these are recorded attempts, never "totals"
- An activity chart with five measures — Turns stacked by outcome, Tokens, Models, Devices, Gateways — over 7, 30 or 90 days or all time, with weekly and monthly folds on the wider ranges and a per-period VoiceOver audio graph
- Reliability leads with the share of resolved attempts that succeeded, and opens onto delivered-first-try, recovered-by-retry, retry rate, attempts per completed turn and replies cut short. Failure reasons are grouped, and a reason opens the individual turns behind it with a link into each conversation — a rate tells you something is wrong, the incident list tells you which morning it happened
- Full-response time reports the average and the 90th percentile, and states what it includes: the network and any tools your agent ran, not model latency
- Reported tokens leads with your gateway's own total and the share of attempts it reported on; input, output, cached input, cache writes and reasoning output sit behind Details and read "Not reported" where the gateway stayed silent, because a gateway reporting nothing must never read as a gateway that used nothing. No cost figure anywhere, deliberately — the app does not hold your billing relationship, so there is no truthful source for one
- By device, by gateway and by model, every ranked row carrying its share of that scope's attempts, with a footer naming any mass that could not be attributed so visible shares summing short is never unexplained
- Heaviest threads, with the full ranked list behind See all. A ranking picks one basis — the gateway's own totals, or input plus output added up — applies it to every row, names it on screen, and says that threads without that measurement are not ranked
- Drill-downs per gateway and per device, each with its own range picker, largest turns, and an Image history card separating the turns you attached images to from the earlier images re-sent along with them
- Usage records outlive the conversations they describe, so tidying up your threads no longer puts a hole in the trend. That is disclosed in the two places the claim can be tested: beside the retained figures, and in the erase-everything confirmation, which is the one deletion that does take the records with it
- Clear usage history is account-wide and the only thing that removes a record. It advances a shared cutoff first and deletes rows locally afterwards in bounded, resumable passes, which is what holds the guarantee for a device that was offline during the clear: no amount of late syncing resurrects cleared history
- Device attribution is derived in a fixed order — originating surface, then the class stamped on the record, then the turn's source device — so a car session and a wrist capture are not folded into the phone that carried the request. An attempt the ledger could not place leaves the breakdown and stays inside every total and rate
- Every dispatching surface writes to the ledger — CarPlay, the Watch, the Converse intent, the shared inbox, the background uploader — because a build that measured some routes and not others would make the instrumented ones look like the whole of how the app is used, and no later release can repair a period recorded that way
- Two send-path properties hardened to support this, and worth more than the dashboard: the reply is written under an identifier minted at dispatch, so the same reply landing twice cannot produce a second copy; and a cancellation names the exact turn rather than the conversation holding it
macOS — deleting a conversation
- macOS had no delete path at all: the iOS swipe renders nothing there and the host suppresses the toolbar actions. Right-click a sidebar row for Delete, and Delete All sits in the window toolbar's sidebar band, on its leading side, hidden whenever the sidebar is collapsed
- Deleting the open thread resets the window to the new-chat state by the same path ⌘N takes, instead of leaving the composer mounted against a dead conversation
CarPlay
- A session that died while its audio engine was still starting could commit a running engine and a live input tap onto a dead session, holding the car's hands-free microphone until the device was rebooted. The commit re-checks the session and discards the engine instead
- A voice session that timed out on silence simply vanished, which on a car screen reads as a crash. Both windows now end by speaking — the ordinary sign-off when the capture pipeline is healthy, one line about the microphone when it is genuinely dead. Counters reset when the tap is reinstalled, a tap too young to have seen anything convicts nobody, and an all-zero but finite probability stream is a quiet cabin rather than a fault
- Speech is corroborated before it counts: two consecutive chunks at or above threshold, on raw per-chunk probabilities rather than the detector's hysteresis-held state. One loud 256 ms chunk of road noise used to be enough
- The silence windows are long on purpose (15 s before the first word, 20 s after a reply) — killing a live conversation is worse than holding the route while a driver thinks. A muted session is never signed off for not talking
- A microphone that fails to start shows a "Mic couldn't start" row instead of vanishing silently, gated on the voice modal still being up
- A reply heard in the car no longer stays marked unread. CarPlay was the one reply surface that never wrote the viewed marker, because the car has no thread view; it writes it now, gated on proof the reply was heard — audio began for that turn and the turn settled finished
Watch
- The launchpad no longer flashes a greyed Ask button and a "Recording…" caption while the capture screen is being pushed
Sync — a peer's delete lands on quiet devices
- Forgetting a custom gateway on one device left a stale row on the others: the live change notification only reaches a running process, and the one cold-launch catch-up was gated on a check that reads the ubiquity identity token, which tracks iCloud Drive rather than the key-value store. Every device now reconciles the synced roster from the local key-value cache at launch and on foreground activation, ungated — adopting only, never reading an absent key as a delete, never publishing the local roster upward
- Custom voice endpoints reconcile by the same rule, and carried an extra fault: their launch pass was iCloud-wins-then-push-up, so a device whose cache had not downloaded yet republished its stale roster and brought back endpoints a peer had deleted
- A deleted voice endpoint that was the active speech or speech-synthesis provider now falls both pointers back to Apple. Unlike a dangling gateway pointer, that one still resolved — the transcription path reads the endpoint's address without consulting the roster, so recorded audio and a bearer token would keep going to a server the user had deleted
Files
- A send from a dead spot charged the pre-dispatch folder check as "file server unreachable", so the retry se...
Conduck 1.4 (build 10)
Conduck 1.4 (build 10) — macOS App Store release, 22 August 2026.
The local-server release. 13 commits since 1.3.
Install it: App Store — free for individuals.
Built from: commit 0dab691, tagged v1.4-10 — marketing version 1.4, build 10. 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.4-10-0dab691.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.4
Local servers — plain HTTP where Apple permits it, and nowhere else
- A gateway, a custom speech endpoint or a file lane may now be
http://when the host is one only the local network can reach: a private-range IPv4 literal (10/8,172.16/12,192.168/16), loopback, link-local, an IPv6 unique-local address, or a.localname. Every other address still requireshttps://. This is what lets a bare Ollama on:11434, or a home Open WebUI box, work without putting a certificate in front of it first - The boundary is Apple's and it was measured, not assumed: App Transport Security permits exactly those hosts with no
Info.plistexception, and refuses every DNS hostname over plain HTTP even when that name resolves to a LAN address. Widening it further would mean disabling ATS for the whole app, which would weaken the OpenRouter, cloud-speech and file connections too — so it is not done - Where the platform behaviour was not measured, the classifier refuses unless the kernel confines the traffic anyway. Single-label names,
0.0.0.0/8,::andfec0::/10all take the strict lane, because an unencrypted request carries the gateway token with it and the public DNS root can answer a bare label - The address field states the trade plainly: the connection is unencrypted on that network, and it works only from that network — not in the car, and not from a Watch on cellular
- A certificate pin configured against a plain-HTTP endpoint is refused, never silently ignored
- A refused address names the remedy rather than the rule — use the server's IP address or its
.localname, or put it behindhttps:// - conduck-connect classifies host addresses by the same rule, so the wizard cannot mint a setup code the app will then reject on import
Watch — a draft adopts the conversation its own capture minted
- A draft thread pushed before its conversation exists could observe the live conversation pin only outside the window where it is non-nil, and wait forever; and any mint at all satisfied its guard, so a deferred drain replaying an older capture could hand a draft a conversation the user never asked for. Mints are stamped with the capture request that owns them, and a draft adopts only its own
- The in-app Ask refuses at the trigger on exactly the state the headless path refuses on, closing the gap where a deferred drain could take the machine between the check and the start
- Three adjacent ways to strand a draft are closed: restore no longer stomps a capture the user began meanwhile, a superseded claim leaves a discard echo, and a denied microphone surfaces instead of hiding behind a silent retry
Gateways
- The custom-gateway roster is capped at three. The cap is enforced when adding, so a roster already above it stays intact and fully editable
Project
- The changelog ships in the repository, so someone holding a release tag can read what that release contained
- Architecture documents state the decisions rather than restating the code beneath them; the security disclosure link resolves without a redirect
Verified: iOS 3987 tests / 0 failures · watchOS 217 / 0 · connector 242 checks / 0 · Release builds green on iOS and macOS · macOS test bundle compiles
Conduck 1.3 (build 9)
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
certFPis gone fromconduck-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-inauthScheme.*; 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
RemoteAgentDiagnosticson a line meant to ship — Release failed to compile on both platforms; it now uses an always-compiledos.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