Skip to content

Changelog

Notable changes to astar. Newest first.

Since 0.1.1beta there is a signed, notarized macOS astar.dmg on the releases page; everything else is still built from source. Versions stay on beta until the client has had a real sit-down-and-use-it pass on all three platforms.

From 0.1.10-beta onward the version is real SemVer — MAJOR.MINOR.PATCH-beta, with a hyphen. Everything up to and including 0.1.9beta glued the pre-release to the patch number, which sorts wrongly: 0.1.10beta is newer than 0.1.9beta and a string comparison says the opposite. Shipped versions are left as they were spelled.

0.1.16-beta — 2026-09-15

The macOS 27 release: the main window laid out again, and the frosted look reaches the top edge.

Changed

  • The title bar is part of the frosted window. The blurred material now runs from the top edge down, with the traffic lights and title sitting on it, instead of a separate strip above the content.

  • The network picker folds instead of clipping. Regular where it fits, small where that fits, and a popup menu below that — every network stays reachable at every window width. A fresh call window opens at 470 pt, wide enough for the full control on macOS 27; a window you have already sized stays the size you left it.

  • The Discord invite is on the front page and in the site's title bar, and the README no longer carries version numbers that can go stale.

Fixed

  • The title bar was completely transparent on macOS 27. A titled window with a clear background gets no title bar backdrop at all on 27 — the traffic lights and title floated on the bare desktop. The window keeps its stock background now; the blur never needed a clear one.

  • The window's minimum width cut both edges off every row on macOS 27. Its roomier segmented controls pushed the six-network picker past the 310 pt minimum, and the scrolling pane centred and clipped the overflow. See the folding picker above.

  • The jitter buffer sliders drew a dotted smear in a narrow window. Those were tick marks, seventeen per slider. The sliders still land on 10 ms steps; they just no longer draw them.

0.1.15-beta — 2026-09-12

Received AllStarLink audio gets a jitter buffer, and the "+" that adds a config or a mic profile is one visible button everywhere it belongs.

Added

  • The jitter buffer is a setting, on both clients. Quick settings → Speaker gains a Jitter buffer switch and the depth window it may adapt between — Min (40 ms) and Max (200 ms), Asterisk's own numbers. On by default, live mid-call, saved and exported with the rest of the audio settings. No config-version bump: a reader that predates the keys reads the defaults.

  • A call-quality line under the meters. On AllStarLink: jitter 12 ms · buffer 60 ms · lost 0 · late 0, with · underruns N appended only when there are some — that one is the alarm, not a statistic. Those figures are in the snapshot, the C header and both bindings too.

Changed

  • Adding a saved config is one obvious button, and the new config is there. The label wedged above the list is now a + on the Saved configs header. The config it makes arrives expanded, scrolled into view, with its name selected so you type over it — and the config you are running stays the one you are running.

  • A + starts a new mic profile everywhere one can start. Mic Profiles, Quick settings' mic row, a saved config's mic row and the analyzer's own header all carry it, and it opens a blank sheet with the keyboard already in the name field. "Open Mic Analyzer…" and both "Analyze…" links are gone: three names for one action.

Fixed

  • AllStarLink audio no longer stutters when the network does. Received voice went straight from the wire to the speaker, so a packet more than about 10 ms late played as a hole and a call that started choppy stayed choppy. The receive path now runs an adaptive buffer on the playback clock, absorbing late and reordered packets and interpolating the odd lost one. Off by a switch if you want the old path.

0.1.14-beta — 2026-09-10

One fix, reported on GitHub the day the public repo opened.

Fixed

  • The Keychain items are filed under com.astar.app, not the author's callsign. Keychain Access shows a password item by its service name, and astar's was com.aj7hr.astar — so what a new user saw first was somebody else's callsign. Both items, the AllStarLink account and the DMR passwords, now live under com.astar.app. Anything saved under the old name is moved on the next launch and the old item removed; nobody re-enters a password. (Fixes #1.)

  • The unit tests no longer touch the login Keychain. One test built a real session through the live factory and read the Keychain on every run, which raised a password prompt — and parked the whole suite when the screen was locked. It uses in-memory stores now.

0.1.13-beta — 2026-09-09

A microphone-setup release, mostly. The analyzer is a pane of the main window rather than a window of its own, it opens on the microphone your profile actually uses, and its threshold is now a level you can read straight off the canvas instead of an estimate drawn a few dB too high. Last heard grew from one name into a short history, the mic gains reach as far as the speaker's, and the AllStarLink account asks for nothing but a password.

Added

  • Last heard is a history: the three most recent stations, each with its age. M17, D-Star and System Fusion all keep one, and both clients show it — the macOS popover and the Iced client's status card. A single name answers "who is talking"; three with ages answer "who is on this net", which is the question you actually have when you join one. AllStarLink stays blank on purpose: a node number is who you dialled, not who is speaking.

  • The mic analyzer is a pane of the main window, not a second window. It opens in place, scrolls when the window is short, and Back returns to the pane that sent you there — from Quick Config or from a Setup — rather than leaving you to find your way home.

  • Analyze says what it found before you save it. One line under the button gives the broadband noise floor it measured and the frequencies it would notch — or that nothing cleared the threshold at all — so the profile you write is one you have already read.

Changed

  • The analyzer's threshold is an absolute level in dBFS, and the background noise has a line of its own. The slider used to read "Noise floor +N dB" and the dashed line was tagged "(est.)" because it genuinely was one: it came from the coarse display spectrum while the detector medianed a finer FFT, so it sat several dB high and notches landed visibly beneath it. The slider is now a threshold in dBFS (-100 to -20, default -60) drawn on the canvas's own axis, and the background line is drawn and labelled separately. Nothing is estimated any more: a peak above the orange line is a peak Analyze notches.

  • A microphone with nothing above the threshold saves as a pass-through profile. A clean mic used to come back with notches invented out of its noise floor. Now the profile records that there was nothing to remove, and says so.

  • Mic Level and TX Gain reach 400%, matching the speaker. Both were clamped at 200% on the mic lane — the capture gain and the final TX trim after the compressor — while the speaker side already had 400% of headroom for lifting a quiet station on a mixed net. A quiet mic, or a hot one that still wants more reach after compression, is the same case. The per-Setup "Vol" slider was left behind by that earlier change and now matches the main one at 100-400%.

  • For maintainers: a release is just release <version>. One command bumps the version in all five of its homes, refreshes the bundled reflector snapshot, runs every gate and builds the signed, notarized DMG. Publishing is a separate, deliberate second step — just publish. See docs/RELEASING.md.

Fixed

  • The mic analyzer opens on the microphone the profile is using, and switching devices actually switches. This is what "the UCI150 shows silence" was: the analyzer always monitored the system default, so a profile built for a USB radio interface was measured from the built-in mic — and picking the right device in the analyzer changed the label without changing the audio, because the engine treated a monitor that was already running as nothing to do. It now switches when the device differs, stays idempotent when it does not, and a switch that fails keeps the old device rather than half-forgetting it.

  • The AllStarLink account asks for a password only, and the token comes from AllStarLink's API. astar now mints the WebTransceiver token through the documented auth-wt-legacy endpoint with your callsign and account password; no node number is involved, and the field is gone from Settings for good. (0.1.12-beta had dropped it while still scraping the portal page, which does need a node, so the Test button read "rejected"; the field came back for a day and left again once the API path shipped.) The engine keeps the page scrape as a fallback for configs that still carry a node.

0.1.12-beta — 2026-09-07

A System Fusion release, mostly. Your over now carries your callsign, so the reflector and the radios on it know who is talking; the transmitted audio is no longer scrambled on the way out; last heard names the talker on every digital network; and the AllStarLink account asks for one thing less.

Added

  • Last heard: the popover names whoever keyed up on M17 and System Fusion, as it already did on D-Star. M17 carries the source callsign in every stream and astar used to throw it away; System Fusion's was decoded all along with nothing to display it. One line now answers for whichever digital network is live. AllStarLink stays blank on purpose: a node number is who you dialled, not who is speaking.

  • A System Fusion over says who is transmitting. An over opens with a real header frame at key-down, weaves your callsign through the data channel beside the voice, and ends with a terminator that carries the callsigns rather than five frames of silence. Before this the data channel went out zeroed, and a reflector dashboard showed the over with nobody's name on it.

Changed

  • The AllStarLink account asks for a password, not a node number. The portal mints a WebTransceiver token without one, so the node field was a hoop. The engine now sends the node only when a config carries one, and a node saved by an earlier build is kept, unused, rather than deleted.

  • The Python binding can no longer drift from the C ABI. Its struct mirrors are checked against the generated header in CI, the way the header itself is checked against the Rust.

Fixed

  • System Fusion transmit was permuted twice. The decode path has always mapped a received frame from the codec's bit order to the chip's; the encode path wrapped the chip's bytes as if they were already in codec order, so every transmitted frame was permuted a second time and 1 bit in 49 landed where a receiver expected it. Receive was clean, and so was D-Star, which has no permutation. Pinned bit for bit in a test and by a tone loopback on the dongle.

0.1.11-beta — 2026-09-07

System Fusion is the third digital network astar speaks: link a reflector, hear it, and key back into it with a ThumbDV. The node daemon now runs wideband by default, refuses a peer it cannot decode instead of failing silently, and finally writes a log. And every digital network shares one audio lane, so the meters, the spectrum and your microphone settings mean the same thing whichever network is live.

Added

  • System Fusion (YSF): link a reflector, hear it, and transmit, with the ThumbDV in DN mode. YSF sits beside AllStarLink, M17 and D-Star in the network switcher and gets everything the others get — its own audio profile, level meters, spectrum, last-heard, a timeline that records your own overs, and a live link that reports as connected rather than looking like a failed one.

One dongle means one direction at a time. While you are keyed, received voice is not decoded — there is a single AMBE-3000 behind the ThumbDV, and D-Star has always made the same trade. Callsigns cost no vocoder, so last-heard stays truthful while you talk; a busy reflector simply goes quiet for the length of your over.

Receive is verified on live reflectors; transmit so far only against a parrot on the bench. D-Star and M17 transmit are the ones verified on live reflectors.

  • ysf-listen and ysf-parrot, for the bench. just ysf-listen <host> <callsign> links a reflector and plays it — or captures it with --wav — which is the hardware checkpoint in one command. just ysf-parrot <port> runs a System Fusion parrot on your own machine, the twin of just m17-parrot: key into it from astar and hear yourself, with nothing on the air. Frames are relayed verbatim, so it hides no framing bug.

  • DMR in the bundled reflector directory. The 2026-09-07 snapshot carries 3,415 reflectors across seven networks, now including hamcall-db's DMR masters — 185 servers, named and counted. astar has no DMR client yet, so they are listed rather than dialable.

  • The node daemon has a voice. astar-server depended on tracing and never installed a subscriber, so 35 log sites in the engine dispatched to nothing and a hub could run for days emitting one line. It now installs one — info by default, RUST_LOG overrides, timestamps and no ANSI because this lands in journald — and codec negotiation prints a line per inbound call naming the caller, what it can carry, what it asked for and what was accepted.

Changed

  • astar-server prefers signed 16-bit linear by default and rejects a peer with no usable codec instead of accepting one it cannot decode; µ-law-only nodes are still accepted, and the reject carries Asterisk's own CAUSE and CAUSECODE. In the other direction, a peer that answers with a format the station never offered is hung up on rather than transmitted to: a ulaw_only node no longer ends up sending wideband because the far end asked for it.

  • One audio lane: M17, D-Star and System Fusion now share the station's single audio router; level meters and spectrum are computed once at the microphone and the speaker for every network.

  • The docs say a licence is required before first contact. The page someone follows from download to first QSO listed a Mac, an account and a headset and stopped there, while every step on it ends with a real transmitter keying on a real band. The DVstick 30 is also documented as known-working rather than buy-at-your-own-risk: it enumerates as the same FT230X the dongle scan looks for, and it is what astar is developed against day to day.

Fixed

  • The beat on System Fusion receive. YSF delivers five 20 ms frames at once every 100 ms, and handing each burst straight to the output bus left it starved for the remaining 60 — roughly two audible gaps a second, worse the longer somebody talked. Decoded audio is now released one frame per 20 ms behind a small cushion, the same arrangement D-Star uses, at the same cost of about 60 ms of latency.

  • Garbled System Fusion transmit. The encoder dropped every microphone frame past the fourth in a pass, which is dropped speech, and the last frames of an over were lost or arrived during the next one as somebody else's audio. Captured frames are now queued the way received ones already were, and the encoder is drained before the over closes.

  • A rejected inbound call — bad CALLTOKEN, failed auth, or no common codec — no longer leaves a call number and a max_calls slot held forever.

  • The app dials as a slin16 station again whichever network it used first. Digital voice now rides a 16 kHz station through an exact 8↔16 kHz bridge instead of pinning the engine to 8 kHz.

  • A node that answers calls keeps its own codec policy. Turning the inbound listener on pinned the station to µ-law at 8 kHz whatever it had been configured for, and on an engine already running at 16 kHz the mismatch meant the node answered nothing at all.

  • A stated FORMAT is honoured as a request, not treated as a hint. A node that lists 16-bit linear for completeness but asks for µ-law was answered with slin16 and dropped the call silently — the worst shape a negotiation failure can take. Nor is a wideband codec asserted over a peer that sent no CAPABILITY at all: its stated format is the only thing it actually told us.

  • Registration fails over between a registrar's addresses. A registrar hostname is commonly several hosts and they do not all answer a given source address, so pinning one is a bet that gets re-lost whenever the far end changes — silently, with REGREQs going out forever and nothing coming back. The retry ladder now advances one candidate per attempt and stays on whichever address answered.

  • VOX pre-roll and speech onset are no longer lost on D-Star/YSF key-down, and YSF key-ups now appear in the timeline.

  • A live D-Star or System Fusion session draws its spectrum. The graphs dispatched to AllStarLink and M17 only, so the two dongle networks showed empty bars.

  • The self-hosted M17 parrot (just m17-parrot) replays at exactly 40 ms per packet; it drifted 4 % slow and was audible as a beat after a few seconds.

0.1.10-beta — 2026-08-30

Noise reduction that works while you are talking — new, and off until you turn it on. Plus failures that say what went wrong, and every dependency brought current.

Added

  • Noise reduction that can clean up under your voice. astar's noise reduction has always been a gate: it quietens the gaps between words, and by its nature can do nothing about a fan, traffic or a noisy room while you are actually speaking. There is now a second option that can — a small neural network (RNNoise, via the pure-Rust nnnoiseless) running on the microphone at the device's own rate, before anything else touches it.

It is off by default, and it has not been judged on real air yet. Tick "Noise reduction" in Settings to try it. Whether it helps on your microphone — and especially whether it survives a low-bitrate vocoder like Codec 2 or AMBE, which allocate bits by spectral structure and may not thank you for it — is an open question this release does not answer. That is why the default is off, and why it stays off until somebody has sat and listened.

It needs a capture device running at 48 kHz, which most USB radio interfaces are. A device that cannot offer 48 kHz keeps the old hum filter and gate instead of being fed audio the network was never trained on, and a line underneath the toggle tells you which of the two is running — or which would run, when you are not in a call and there is nothing to measure.

A Strength slider appears alongside it, from full down to bypass. Turning it down leaves more of your original audio in the mix, which is the dial to reach for if it sounds over-processed.

The hum filter stays in the chain either way: a measured notch removes a cheap microphone's whine deterministically, and a general-purpose network has no particular reason to treat a steady in-band tone as noise. The gate stands down only while the network is running, and comes back the moment it is not.

The cost is about 35.7 µs of CPU per 10 ms of audio — 0.357% of one core, measured on Apple silicon and not yet anywhere else — and up to roughly 20 ms of extra delay on transmit, which is under one voice frame and does not delay keying. The design, including what has and has not been measured, is written up in docs/design/noise-suppression.md.

There is also an ASTAR_MIC_DENOISE environment variable (neural, legacy, or off) for anyone who wants to A/B the two chains directly. It chooses which chain the checkbox turns on; it does not turn anything on by itself.

  • A published release list, at /api/v1/releases.json, built with the docs from the app's own MARKETING_VERSION so it cannot describe a version that was never built. Every release carries both the display version and a strict-SemVer semver, so a client written against either one keeps working across the spelling change below.

  • A Discord server, linked from the site header, the front page and the README.

Changed

  • Versions are real SemVer from here on, this one included, and the app and the Rust workspace now spell a release identically — they had been carrying two different strings for the same version because Cargo demands the hyphen. just ci fails if any of the five places that record a version disagree. Released versions are not retrofitted.

  • astar asks capture devices for 48 kHz. It used to take whatever a device called its default. 48 kHz is what the new noise reduction requires, and it is the better rate regardless: 48 → 8 kHz is a clean 6:1 decimation where 44.1 → 8 kHz is 5.5125:1. A device that does not offer it keeps its own default and simply does not get the neural chain.

  • Every dependency a major version behind was brought forward: cpal 0.15 → 0.18, rubato 0.16 → 5.0, rand 0.8 → 0.10, base64 0.22 → 0.23, libloading 0.8 → 0.9, md-5 0.10 → 0.11, and toml 0.8 → 1.1 in the Iced client, alongside 52 packages moved to their latest compatible versions. Device names are unchanged across the cpal upgrade, so saved input and output selections still resolve; cpal 0.18 also finds output devices 0.15 did not enumerate.

Fixed

  • Failures say what actually went wrong. A dial that failed used to read something like "astarstation error -7: audio error" — a number and a category, neither of which tells you what to do about it. The engine knew more all along and had nowhere to put it; now it does. D-Star failures name the real reason instead of listing the three likeliest causes, and everything else shows the engine's own sentence rather than an error code.

A microphone or speaker that will not open is the deliberate exception: it says simply "Couldn't open audio device, is it busy or unplugged?", because every cause behind that code has the same two remedies and naming which one it was would give you nothing more to act on.

Failures are also orange now rather than red, matching every other warning in the app. A dial that did not go through is something for you to fix, not a fault in astar.

  • Switching networks clears the dial field. A node number typed for AllStar is not an M17 or D-Star target and never was, but it used to stay in the box after the switch, looking like one. Picking a favorite, a recent or a reflector still fills the field as before — those set the target and the network together.

  • Two security advisories in the WireGuard transport's dependencies, both inherited from boringtun 0.6: a timing-variability finding in curve25519-dalek (RUSTSEC-2024-0344) and a panic in ring's AES with overflow checks on (RUSTSEC-2025-0009). boringtun 0.7 clears both, and the dependency audit is now clean.

  • The docs site republishes on a changelog-only edit. Its path filter never matched CHANGELOG.md — the file the site renders is a symlink to it — so a release that touched nothing else would not have rebuilt the page announcing it.

0.1.9beta — 2026-08-29

Who you are, at the top of Settings — and the first bricks of DMR.

Added

  • The start of DMR: crates/astar-dmr. DMR is not one network — it is a family of independently run ones that share a protocol, and a talkgroup number names nothing on its own (TG 91 exists on several of them and is a different room on each). So the first thing built is the address, not the wire: TGIF, FreeDMR, DMR+, SystemX, AmComm, VKDMR, FreeSTAR and ADN are grouped together as "Independent networks", and BrandMeister stands apart behind a consent gate that is shut until the operator opens it. Nothing dials DMR yet.

  • A DMR radio ID field, in its own section below the AllStarLink account. DMR does not put a callsign on the air — it addresses radios by a number registered at radioid.net against a verified licence. That is a different credential from a callsign, so it gets its own field rather than being bolted onto one that means something else. Exported configs carry it under the same "Callsign and radio ID" checkbox, so a file you hand to someone else still leaves your identity behind. Nothing dials DMR yet, and the field says so.

Changed

  • Settings fields have standing labels. Callsign, DMR Radio ID, Node number and Password each carry a label in their own column instead of relying on placeholder text. A placeholder is not a label: it disappears exactly when the field has content, which is the moment you most want to know what you are looking at. The Operator and Account sections share one label width, so the pane reads as one form rather than two stacked by accident. The password keeps a placeholder for the one thing a label cannot say — "Re-enter to change", because an empty box there means unchanged, not blank.

  • Your callsign is the first thing in Settings. It used to sit at the bottom of the AllStarLink account panel under an "M17" heading, which said two wrong things at once: that it belonged to M17, and that it was part of an AllStarLink account. It is neither. M17 sends it in every frame, D-Star puts it in every header, YSF carries it in every data packet — and AllStarLink is the one network that never transmits it, because there you dial as a node number. It is now an "Operator" section above everything else, and the AllStarLink account panel below it no longer has a callsign box at all. Your allstarlink.org login is your callsign; a second field for the same fact was only ever a way to get the two out of step. The account panel says which callsign it signs in as, and changing it above updates the saved account without asking anyone to retype a password. Clearing the account leaves your callsign alone — that is who you are, not an account detail.

  • The reflector directory is a pane of the window, not a sheet. The magnifying glass beside the dial field now swaps the window over to the reflector list the same way the gear swaps it to Settings, and the same Back chevron — and the same ⌘[ — brings you home. Picking a module is still the second step, with its own Back to the list. Nothing about a directory you are browsing is modal, and a sheet floating over a popover was one layer of chrome more than the job needed.

0.1.8beta — 2026-08-28

The big one: astar can find a reflector it doesn't already know, and it can talk to D-Star.

Added

  • A reflector directory. 3,188 reflectors across D-Star, M17, YSF, NXDN, P25 and URF, searchable inside the app — no account, no API token, no network round-trip when you dial. A magnifying glass beside the dial field opens a search sheet; pick a reflector, pick a module, and the dial field fills in. It never connects for you: dialling stays a deliberate second action.

The list ships inside the app, so a first launch with no network still has a complete directory, and refreshes itself at most once a week — the cadence is published by the data, not hard-coded, so it can change without an astar release. Settings gains a Reflector directory section with the counts, when it last synced, when it next will, and a Sync Now button.

  • Dial a reflector by name. Type XLX836 A or M17-002 A instead of an address. The directory gets first refusal on the text and the address parsers only see what it doesn't recognise — so a reflector name can never be mistaken for a hostname and quietly resolved to something else.

  • D-Star. A D-Star entry in the network switcher, reflector-and-module dialling against those 943 D-Star reflectors, and the callsign of whoever is talking shown under the connected-node line along with any slow-data message.

D-Star voice is AMBE and astar ships no software vocoder, so the entry appears only while a ThumbDV dongle is attached. That is the honest gate: an entry that always failed to connect would be worse than no entry. (The probe runs once at launch, so a dongle plugged in afterwards needs a restart.)

  • Module pickers that ask rather than guess. On D-Star the module is the room, and the registries publish no list of active ones — so astar offers the letters and says plainly that it cannot tell which are live. It never fills one in for you. Where a reflector does publish its modules (M17, URF), those are what you are offered. The module you last used on a reflector is remembered and shown marked on your return — a recollection you can see and change, not a default applied behind your back.

Fixed

  • XRF002 dialled the wrong reflector. Some XLX reflectors carry an XRF-form alias that is also the real name of a different, standalone reflector — 44 names collided this way, and typing one reached whichever entry the directory happened to index first. XRF002 reached a reflector in China rather than the one in the US that actually bears the name. Names that mean two reflectors are no longer published as aliases; the reflector keeps its own name, and the wire callsign it needs is unaffected.

  • The volume control had no effect on D-Star. D-Star was never wired into the audio-preference fan-out, so it played at full scale while every other network sat at whatever you had set — which is why it came out louder than the rest. Output gain and RX levelling now reach a D-Star session, both when you connect and when you change them mid-QSO.

  • D-Star transmissions addressed the destination reflector. The RPT1/RPT2 header fields now carry the reflector being called, derived from its published hostname or taken from the directory when it is only reachable by IP — rather than going out blank.

Changed

  • One callsign, not one per network. M17 sends it in every frame and D-Star puts it in every header, and it is the same callsign — so it is one field, and the prompt names whichever network you are on. Nothing to re-enter; what you had is what it uses.

  • Reflectors are searchable under every name they answer to. One XLX box is XLX836, XRF836, REF836 and DCS836 at once, and any of those now finds it.

  • The documentation site was rewritten to be technical rather than promotional, astar-server got its own page saying plainly that it is a work in progress, and the changelog you are reading is now published there too.

0.1.7beta — 2026-08-22

One fix, in the status row at the top of the popover.

Fixed

  • The round-trip time no longer shows a wrong number when the window is narrow. Compacting the window horizontally squeezed the ms readout until it broke one character per line into a vertical strip, and — after a first attempt at protecting it — until it clipped to a single digit. A latency figure clipped to its first digit is not a cosmetic defect: 9, 93 and 935 ms describe three very different calls, and nothing on screen showed it was truncated.

The readout is now drawn at its full width or not at all, and the space it would have taken goes back to the connected-node name, which regains characters at narrow widths. It reappears by itself when the window is widened. On a narrow window with a long favorite name it stays hidden — a supplementary readout that is absent is honest; one that is truncated is not.

Also fixed on the way: the connected-node name wrapped to a second line instead of eliding, which grew the card and pushed the level graphs down, and Connected itself could pick up an ellipsis while the row visibly still had room.

0.1.6beta — 2026-08-22

A small one, entirely about the two things a new user meets first: the app menu and the About panel.

Fixed

  • astar → Settings… no longer opens an empty window. It opened SwiftUI's placeholder settings scene rather than astar's own settings. 0.1.1beta shipped a fix for this that never took effect: it replaced the main menu at launch, and SwiftUI reinstalls its own menu afterwards and wins. The item is now removed at the source instead. Settings is where it has always actually been — the gear in the popover footer.

Changed

  • The About panel says who wrote astar and where to find it. It now carries Copyright © 2026 Rob Ludwick. AGPL-3.0-only. and links to the documentation, the source on GitHub, and AJ7HR on QRZ. AGPL-3.0-only asks that the source be reachable from the program, not merely published somewhere, and until now nothing in the app pointed at it.

Both come from the app bundle rather than from code, so the panel reads the same however it was opened.

0.1.5beta — 2026-08-22

Your setup stops being trapped on one Mac. Configs, favorites and settings can be exported to a file and imported back — in whole or in part — so a second Mac, a rebuild, or handing a working rig to another operator is no longer a matter of re-entering everything by hand.

Added

  • Export and import your configuration (Settings → Backup). Export writes a plain-text .astarconfig file; both ends are section-by-section, so one format serves a personal backup and something you share. The sections are saved configs (with their mic profiles), the node directory, audio and serial settings, callsign, and window state.

Callsign is its own tick box, because it is the field that decides whether a file identifies you. Leave it off and an export is a rig anyone can use.

Import adds and updates; it never deletes, and re-importing the same file is a no-op rather than a way to end up with everything twice. Node entries match on node number rather than id, so the same node is never stored twice and your own label and ★ survive an import. This is what makes it possible to take somebody's node list without adopting their microphone and serial wiring.

Your AllStarLink account is never exported. It stays in the Keychain, there is no option to include it, and an import leaves existing credentials untouched. A test encodes a full archive and greps it for the password to keep that true.

  • A config version, stamped into both an exported file and the preferences domain, so a future release can translate an old config rather than reject it. It marks translation, not change: adding fields or sections leaves it alone, and a version 1 file will keep importing. A real 0.1.4beta export is kept in the test suite to hold that promise to something.

  • A favorite's node number is editable in place (Settings → Favorites). Repointing a favorite used to mean deleting it and adding it again, which threw away its label, its ★ and its per-node talk-timer override.

Fixed

  • Two audio devices with the same name no longer both appear selected. An ICOM IC-7300 and an AllScan UCI150 both enumerate as "USB Audio Device", and astar identifies devices by name — so of two same-named devices exactly one is reachable, and offering both was offering a choice that does not exist. The picker now lists one entry per distinct name, marks an ambiguous selection with an orange name, a red outline and a warning triangle, and explains what to do about it: renaming a device in Audio MIDI Setup is stored against that device and fixes it for good.

The underlying repair — identifying devices by their stable CoreAudio UID instead of their name — is tracked as astar-uid. Until then, a saved device name still binds to whichever same-named device the system enumerates first.

Documentation

0.1.4beta — 2026-08-18

M17 now works on a Mac that has never seen Homebrew. That was the whole point of this release: 0.1.3beta offered an M17 network picker that could not actually open a codec, because the Codec 2 library it needed was something you had to install yourself.

Added

  • Codec 2 is linked into the shipped app, so M17 works out of the box. astar still prefers a system libcodec2 if you have one and only falls back to the linked copy, so nothing changes for anyone who installed it via Homebrew. Verified as a controlled experiment on a Mac with Homebrew's codec2 uninstalled: the runtime-only build reports M17 unavailable, the shipped build reports it available.

This is the only LGPL code in astar, it is unmodified, and it is deliberately never part of a default build — see LICENSE-EXCEPTIONS.md for the Codec 2 notices and the written offer, and ci/guard-codec2-licensing.sh, which fails the build if it ever leaks into a default feature set.

  • An App Store distribution exception under AGPL-3.0 §7, scoped to Rob Ludwick's own copyright and removable exactly as §7 allows. astar stays AGPL-3.0-only; the exception exists so the same source can eventually ship through the App Store, whose terms conflict with the bare AGPL. It grants no rights over Codec 2, which is not Rob's to relicense — and nothing here stops you modifying Codec 2 and rebuilding astar, which the notices say in as many words.

  • A first-run walkthrough in the docs — install, account, audio levels, the four ways to key up, first contact. Written from the questions an outside tester actually asked over a week rather than from what seemed obvious from the inside.

Fixed

  • The CodeQL workflow could hang for 25 minutes on its own apt-get step against an unreachable Ubuntu mirror. The step is now bounded and retried, and reports what happened instead of stalling the run.

0.1.3beta — 2026-08-17

Everything here is about the first ten minutes with astar. 0.1.2beta fixed Settings being unreachable; this fixes Settings being findable but silent — you could open it and still not learn that an AllStarLink account is the thing standing between you and a call.

Added

  • Settings opens by default when no AllStarLink account is configured. Without one the dial field is disabled, so the call UI is a form that cannot be typed into. astar now lands on Settings instead, from every route into the window — the menu-bar asterisk, the Dock icon, and Cmd-,. It stops the moment an account is saved.

  • A first launch with no account raises the window on Settings — once. astar is a menu-bar app, so a new user otherwise sees an asterisk and nothing else. It happens a single time: M17 needs no portal login, so running astar without an AllStarLink account is perfectly legitimate and is not nagged at.

  • The account password is outlined in red when it is empty with nothing saved, or when the portal rejected the last token test, with the reason underneath.

An empty box on an account that is saved stays unmarked. astar never pre-fills the password — it lives in the Keychain and the field reads "re-enter to change" — so flagging that would tell you your working credentials are broken.

  • Settings now says what a missing account costs you: AllStarLink is unavailable without one, because dialling a node signs in to your allstarlink.org account and there is no guest access. M17 is unaffected.

Fixed

  • CodeQL had never completed a single run. cpal's Linux backend builds against ALSA and the hosted runner ships no ALSA headers, so the build died before analysis started. Invisible from a Mac, where cpal uses CoreAudio.

0.1.2beta — 2026-08-17

Both fixes here came out of the first outside report against the 0.1.1beta DMG, from a tester who had never built astar from source — so he met the app exactly as a new user does, and hit two walls in a row.

Fixed

  • Settings opened an empty window. astar spent its life as an LSUIElement accessory, which has no application menu. The Dock icon added in 0.1.1beta promotes the app to a regular one, and that handed it a menu bar whose Settings… item was still wired to the placeholder empty scene the app used to satisfy SwiftUI's "an App must have a Scene" requirement. Choosing it opened a window with nothing in it. astar now builds its menu explicitly, and Cmd-, opens the real settings pane — the same one the popover's own settings button shows, not a second copy.

  • A fresh install invented a config for hardware you may not own. With no saved configs, astar seeded one named after the AllScan UCI150 and put it on a serial hardware profile, whether or not that interface had ever been plugged in. Meanwhile the entry that described plain system audio was filtered out of the settings list and never appeared at all.

Added

  • A built-in System Default config: your Mac's current input and output, no serial PTT. It is always present, can't be deleted, sits at the top of Saved configs, and is what a fresh install starts on and stars as its launch default.

Existing setups are left alone. If you already have saved configs but never set a launch default, astar still applies nothing at startup — making System Default win there would reset your devices and switch off your serial PTT on every launch.

  • A real menu bar. About astar with links to the documentation and to AJ7HR on QRZ; Settings… on Cmd-,; a standard Edit menu, so Cmd-C / Cmd-V / Cmd-A work in the account, node, and config fields; Window; and a Help menu linking the documentation site, the issue tracker, and QRZ.

  • Report an Issue… in the Help menu, pointing at the public repository's issue tracker. Nothing in the app used to say where a bug should go.

0.1.1beta — 2026-08-14

Added

  • A Dock icon for the macOS app, on by default, with a Show in Dock toggle in the status item's right-click menu. astar has had a real main window for a while; it now has the Dock presence and Cmd-Tab entry a windowed app is expected to have. Turning it off returns it to menu-bar-only, and that choice sticks across launches.

The app still launches as an LSUIElement accessory and promotes itself afterwards, so anyone who turns the icon off never sees it flash on at startup.

  • Clicking the Dock icon opens the astar window. It shows the window, it never hides it — a second click on a Dock icon is not a close button.

  • M17 in every default client build. The macOS and Iced clients ship the M17 network without a feature flag.

Fixed

  • The Show in Dock toggle applied only after a restart. Under @NSApplicationDelegateAdaptor, NSApp.delegate is SwiftUI's own wrapper delegate rather than the app's, so the status item's as? AppDelegate cast silently produced nil and the apply step never ran. The activation-policy change now lives on a stateless type both callers own outright.

Changed

  • CI moved to a private development repository with a self-hosted runner; the public repository is the release target and carries no runner. Both workflow files exist in both repositories and are guarded on github.repository, so each is inert in the wrong one.

  • Documentation is published to GitHub Pages on merge to main in the public repository.

Documentation

  • Stopped claiming the macOS app has "no Dock icon and no main window". The main window has existed for some time; the Dock icon now exists too. Corrected in the README, the site front page, the macOS page, and the build guide.

  • Brought the site in line with the README on D-Star, and stopped .github/README.md shadowing the front page.

0.1.0beta — 2026-08-11

First tagged version, and the point at which astar became one repository: the client and the iaxclient-rs engine were merged into a single AGPL-3.0-only cargo workspace with one git history.

What that version contains:

  • astar-lib — the engine. IAX2, M17, and D-Star protocol work, codecs, audio, PTT, the station facade, and a C ABI.
  • The macOS client — a SwiftUI menu-bar app over that engine.
  • The Iced client — the Windows and Linux front-end, sharing the same core.
  • astar-server — the headless node daemon.

No binaries were published, then or since. just dmg produces a local, unsigned disk image; building from source is the only install path.