2026-10-22 · HISTORICAL RELEASE
Skotiq 8.0.0
The Skotiq name, a redesigned Tonight screen, remote clients and a new Darkroom.
Released October 22, 2026.
Version 8.0 renames Nightshade to Skotiq and redesigns the Tonight screen. You can now control the host from a second computer and create a color image from your filter masters in Darkroom.
It also carries a large batch of fixes made while running the app on a telescope through October — meridian flips, recovery after problems, the updater, and a long list of driver-level corrections.
The name
Nightshade is now Skotiq, after scotopic vision — the rod-based night vision the app is built around. The old name belonged to someone else's product.
What this means in practice:
- On Windows the program is
skotiq.exe; a fresh install lands in%LOCALAPPDATA%\Programs\Skotiq. The portable zip still runs from wherever you extract it. - On Linux the binary and data folders use the new name.
- The application IDs are
com.skotiq.desktopandcom.skotiq.mobile; the mDNS service advertises as_skotiq._tcp; environment variables and config keys areSKOTIQ_*. If you run the headless host under systemd or a script that setsNIGHTSHADE_*, update it. - Your data moves itself. The first time the new build runs it moves an existing install's data — settings, equipment profiles, sequences, targets, history — across automatically.
- Android is a fresh install.
com.skotiq.mobileis a different app as far as the phone is concerned: install the new APK alongside, re-pair (a minute from the host's Remote access screen), then remove the old app. There is no in-place upgrade path. - The icon, the mark (the "Trails" S drawn as a telescope's slewed path), the splash and the default accent are new. The seeded accent color is migrated to the brand violet by database schema v62 — if you picked a custom accent your choice is kept; if you kept the old default it becomes the new one.
The full rename note is docs/release/rebrand-skotiq.md.
Tonight is now the night-control screen
The dashboard has been rebuilt around what you need while a run is going. One screen carries the target, the plan, the frames as they land, the night's log, the devices, the conditions and the recovery state.
- A header strip shows the plan's progress, the current clock in the night's timeline (now / dark / meridian / dawn) and the run's state — including a restored run that is waiting for you to press Start.
- The center column is the frame stage: the latest frame, what it measured, the exposure currently in flight, and the action bar (Snapshot, Loop, Autofocus, Solve & sync, Center). Below it, charts for guiding and focus/temperature that have proper scales, units and legends, and the night's event log.
- The left column is the target and the plan: the altitude plot with degree and clock labels, per-filter progress, and the step list with its own clock times.
- The right column is tabbed — Overview, Camera, Focus, Mount, Guide, Solve — so six panels' worth of information fits without scrolling.
- "Before you start" is a real checklist with live values: cooler state and set-point, filter and slot count, focuser position, park state, guider, solver, free disk, weather and the dawn rule.
- Manual actions go through a controller that knows a run is in progress: Center ends on its outcome, Snapshot and Loop start from the profile's gain and offset, and Stars/Annotate work on the frame on screen.
- When weather or recovery has the run held, the banner explains what is deciding and offers "Sky is clear, resume" when that is the honest option. A forecast is a forecast — it warns or holds the run, it no longer presents itself as a critical alert.
- When two windows are open (the host and a linked client, say), each says which action the other is running instead of confusing you.
- The "Coming up" list is now the actual events the run knows about rather than placeholders.
- On phones the whole thing keeps full-size touch targets; on windows too short for the rail, the rail compacts instead of clipping.
A second computer is a real client now
Point the desktop app at the host (--remote-host) and it is a control room,
not a viewer. The host remains in charge of the hardware; the client follows
and can act.
- A client connecting mid-night opens on the host's event log — the night's story so far, not an empty screen.
- The host shares its runtime results with linked clients, so a client's frame view shows what the host is capturing, including frames the client itself triggered (without dragging raw pixels across the wire) — and the host's image view shows a linked client's captures.
- A mirrored frame takes the host's plate solve rather than solving twice.
- The client reads and writes the host's settings — not a local copy that would drift.
- A client's snapshots and loops save their scratch frames on the host, in the host's layout, and its light frames land under the host's output folder; calibrated copies and flats get host paths in the host's style.
- Run notifications from the host reach a linked client.
- Closing a linked client no longer parks the host's mount. A client can leave the host's interrupted run alone instead of "helpfully" resolving it.
- The client stopped echoing the host's site back to the host, and its report that it went idle actually reaches the host.
- The every-30-seconds re-hydrate no longer blanks every device card or re-downloads the host's last frame, and no longer paints a disconnected device with stale state or reconnects a focuser the host just dropped.
- Security hardening while we were in there: a refused ticket upgrade no longer marks the paired token dead, the event socket refuses session handoffs and preview/chat/annotation posts the token is not allowed to make, a request that outlives its wait is closed rather than left attached, and a pairing database that never answers no longer holds every request open.
- A PHD2 that is slow to answer is no longer reported as disconnected.
The Darkroom drafts your color image
When a sequence finishes, the dawn pass now drafts each target's color composite as its primary result — L, R, G and B masters combined into a color draft you can open and keep working on.
channel_combineflattens each master before the channels meet, then combines them. The draft follows the working order PixInsight uses — channel combination, star-based white balance on well-measured stars, background neutralization on true sky, then a color-preserving stretch measured at full resolution — rather than stretching a luminance stack and tinting it.scnrremoves the green cast andchroma_denoisesmooths background color.- On a mono master the steps that need color data say so instead of pretending to apply.
- Every pass — the dawn combine, an integration, a manual run — shows live in the Darkroom while it works and leaves a readable record afterwards, with every stage's measurements and timings logged to disk. Picking the reference frame is its own stage so you can see which frame the others were matched to.
- An affine refinement in registration is kept only when it earns its extra terms; the background fit degree is judged against every candidate, not only the next one.
- Color pixels are written through fixed-size chunks instead of a giant allocation.
Mount control
- Home is its own command. Every mount driver can now home the mount
without parking it — the command verifies the home actually happened before
reporting success. It is on the API (
POST /api/mount/home), beside Park in Imaging and Equipment, and as a sequencer instruction. - Slews tell the truth. A slew is only reported complete once the mount has
actually arrived: lagging
Slewingflags are waited out, arrival is checked on the sky in the mount's own frame so slews near the pole are not failed as misses, and a target slew leaves the mount tracking. Native serial mounts reconnect after a heartbeat loss, and the mount carries the polled side of pier into its state. - Meridian flips got a pass. A flip takes its hour angle against the target's RA of date, re-slews to the mount's position in J2000, verifies the flip by coordinates in the mount's own frame (or on the sky near the pole when there is no pier-side telemetry), re-checks it is still due when a queued flip's turn comes, and a flip that can still fire holds the next frame instead of crashing into it. The exposure gate no longer waits on a flip the trigger was never going to fire. You can also ask the sequencer to stop tracking before the meridian and flip after it.
- Driver level: LX200-family gotos stop reading as slewing once the mount arrives, never print "sixty seconds", and a sync the mount refused fails rather than syncing to the last goto. Sky-Watcher and iOptron get the same slewing and sixty-second fixes. INDI gotos and focuser moves return when the driver answers and report a refusal as an error, and a reconnect that runs out of attempts or is cancelled no longer strands the server. ZWO overlapping discoveries share one scan, and the cooler reports the set-point the camera actually holds.
Keeping a run alive (and ending it properly)
This is the part of the release that cost the most nights to learn. The theme: transient problems notify and the run keeps imaging; operator stops are respected; parking is opt-in, not a surprise.
- A failed download or filter-wheel move is retried (default 3, settable in Settings → Sequencer) instead of ending the run. A spent retry budget is a notification, not a stop.
- A cooler that cannot quite reach its set-point notifies and the run images at the temperature it reached — it does not wait forever.
- Every failed autofocus notifies and the run continues on the previous focus position; it never parks. A trigger autofocus that leaves the guider dead holds the run first, and no light exposure starts until guiding recovers.
- A lost guide star now holds the run with the mount tracking and resumes when stars return; a star never re-acquired leaves the run imaging unguided rather than ending the night.
- Quality problems (grading rejects) notify and the run keeps imaging unless you ask otherwise — the reject-streak limit pauses the run once per streak, and "Stop the run for quality problems" is a setting that defaults off. Saved sequences' old quality-stop steps are converted to notices, once.
- The run's own mount moves (dithers, flips, recentering) stop the guider first and never read as a lost star.
- Recovery is less surprising: Resume cannot unfreeze a recovery and a pause outlives one; a recovery give-up tells you tracking was left off; weather and dawn are still watched while a recovery ladder runs; an operator Stop during a recovery never parks or reports a give-up; automatic safing never parks a mount when nothing is running; and a stopped or turned-away trigger autofocus never parks the rig.
- Weather behaves like a hold: a forecast warns or holds the run until the sky clears instead of ending it, switching weather safety off releases a held run at once, and park-before-dawn measures the lead time to the coming dawn (and refuses to fire with no observing site set).
- Checkpoints: a fresh start inherits nothing from an old checkpoint or the
previous run, restoring a checkpoint loads the run and waits for Start, every
checkpoint Resume actually restores the run, and a restored run continues in
the night's reopened session.
POST /api/sequencer/startcontinues a restored checkpoint from a headless client too. - Each target's frames save in their own folder, numbered on from what is already on disk.
- The run's guiding triggers only arm for guiding the run itself started, and a trigger firing dropped under a hold no longer spends its cooldown.
- A Smart Exposure plan's dither cadence counts across visits and owns the run's dithering; every dither is counted, once.
Frames and measurement
- Star detection in frames now detects against a local noise map and measures whole stars — the same way a PSF fit measures size and shape — so grading judges frames on measured FWHM/eccentricity rather than a detection mean. A defocused frame reports its true median HFR even past 20 px, and a frame that lost most of its filter's stars is rejected.
- Autofocus: the default star selection is the brightest 10 stars (existing installs are migrated), a failed run returns the optics to their origin, a starless verification frame leaves the landing unverified instead of blaming the focuser, the far wings of a sweep are measured at their real size, and a run's autofocus draws live in the Focus tab and keeps its result. Backlash is now operator-tunable in Settings.
- FITS record frame pointing in J2000 rather than the mount's of-date
read-back; a mirrored frame's
.wcsreports the rotation ASTAP reports. - A plate solver reaped by the Dart VM no longer aborts the app, and solving the frame on screen happens in the background and finds its stars.
- Target names resolve through SIMBAD exactly, never by substring; an Astrobin subject resolves only to the object it names; the planetarium resolves typed names by exact designation first.
- The scheduler precesses J2000 targets before computing altitude, transit and set times.
Signed updates
The update system is now real end-to-end, and it fails closed.
- Builds find updates on GitHub Releases and install them on Linux and Android; the paired phone gets the actual release notes rather than a manifest placeholder, and verified APKs are handed to the Android package installer.
- Every target publishes its own signed manifest (
manifest-<platform>.json), checked by CI against the app's compiled-in public key before publish, and the same Dart tool packages and signs Windows updates as Linux and Android. - Apply-time safety: the updater refuses unsigned or foreign-signed releases by name before downloading, refuses an apply the install cannot write (on Windows too), rolls back a build that dies on startup — including rolling back the updater binary itself — and never leaves the app closed. It runs as the user, never queues a reboot rename, and bounds its waits.
- The release workflow retains the existing update-signing identity through the rename. Windows executable signing is separate and is not configured.
For operators and the curious
- The imaging laptop's own data got a pass too: camera warm-up from the panel never leaves the cooler running at a set-point it invented, and Warm Camera in a sequence never switches on a cooler that is off (it logs a reading it could not take instead).
- Framing was rebuilt: the side column is one panel with the compact altitude chart, Enter frames the object the search names, the curve never shows the previous target, and altitude says once that it needs an observing site.
- Polar alignment keeps its readouts and run card on screen at small sizes, tracks the axis through the camera's full attitude against the pole of date, and takes adjustment frames binned 2x2 solved near the previous frame, which is much faster.
- Equipment: a profile device saved by position connects the device it names; the side panel is pinned to the top with Save under the optical-train form.
- Reports tell the truth: a failed run names the fault that ended it (a meridian flip failure names the flip), a failure with no known reason records no cause rather than inventing one, the session report reads runs in time order, and Last Night names a failed run's cause rather than its teardown.
- Notifications: a device error toasts even when no DeviceService is listening; one notification per reject streak and none per frame; a critical phone battery notifies you and never pauses the run.
- Desktop shell: the window is one slate of glass, the first window fits the screen it opens on, KWin no longer draws a second frame around the Linux window, closing the window works after the shell is gone, and the setup wizard's header is the window's own title bar.
- Simulators: the simulated mount slews at a hardware rate and can lag its Slewing flag, the simulated focuser can cool through the night, and the simulated camera can replay a recorded night — which is how the recovery work above was tested end-to-end without burning clear sky.
What has actually been tested
The imaging chain in this release was exercised on the owner's rig — a Pegasus NYX-101 mount, a ZWO ASI1600MM-Cool camera, a ZWO EAF focuser, an eight-slot EFW and PHD2 guiding, on Windows — across two complete nights of imaging in the nights of October 20–22, 2026, per the owner. On the machine's own session records: the saved "NGC0891 Plan" shows 12 runs including the nights before this release was cut, the October 21–22 sessions returned 47 and 52 frames with 1.4–1.5 h of accepted integration at a median 2.4–2.7 px HFR, a 90-frame end-of-night darks+bias run completed at dawn, and the morning-after equipment sweep reports all five devices connected with a health score of 100. An L-filter draft master of NGC 891 — the target of those nights — exists in the Darkroom.
Honest edges: those runs exercised the imaging path hard, but they do not prove every device or every platform, and the deployed build on the rig was exercised during development; subsequent integration changes are covered by automated checks. There is still no recorded full dusk-to-dawn unattended night under the release baseline itself, no second-device test across a firewall, no macOS or iOS build, no Windows executable code signing. Update manifests use the existing signing identity, retained through the rename.
Other limitations
- SFTP still has no password authentication; key authentication works.
- The curves operation in the Darkroom renders but cannot be edited yet.
- Denoise on very large color masters uses a lot of memory at its peak.
- Synthetic-flat / dust-mote correction is research-in-progress on a separate branch — it is not in this release and is not a flats replacement.
Calibration and master delivery
- End-of-night dark and bias capture can use the rig's configured dark filter slot. Captured calibration frames enter the dark library, and native master builders keep processing memory bounded.
- Calibration-only sequences keep light-frame actions such as dither, autofocus and meridian flips out of calibration exposures.
- Color FITS and XISF files use the correct planar channel layout. Registration can align images from different filters.
- Native master accumulation supports multi-night groups and delivery of aligned per-filter masters and a linear RGB FITS file.
Architecture and maintainability
- The Rust trigger monitor separates device polling, trigger evaluation, policy and action dispatch. Run mode, guiding state and tracking loss have explicit owners.
- Dart sequencer events are decoded once into typed events. Run lifecycle transitions, frame recording, statistics persistence, timers, runtime settings and session diagnostics have focused components.
- Integration preserves checkpoint restore-before-start behavior, advisory weather handling and dark-library registration across these changes.
Upgrading
Read the rename note first — docs/release/rebrand-skotiq.md. The short
version: Windows and Linux move your data across on first run; Android is a
fresh install you re-pair. If your autofocus star count mattered, check it —
the default moved from "every star" to the brightest 10, and existing installs
migrate to the new default. Database schema is v62 (migrates the seeded
accent); no manual migration is needed.
Release verification
The release process checks the combined Dart and Rust code, migration behavior, platform packaging and signed update manifests. See the release workflow for platform build results.
- Static analysis, format, clippy — run via
melos run analyze/ CI gates - Project checks: placeholder detection, fail-closed policy, behavioral audit, API contract, platform capability, version consistency, bridge boundary audit
- Update-manifest verification is wired into the release workflow itself
(
verify_release_manifests.dartruns against the app key before publish) - Platform release bundles are built by the release workflow; attached assets identify their source commit.
The complete commit inventory since the last published release is included in the release change list, including integration and release preparation.
Calibration integration also refuses missing gain/offset metadata rather than treating it as zero, and reports incomplete master-build results as errors.