Last week I wrote about cataloguing everything my Seestar S50 has captured: 65 targets, about 77 hours of data, and a list of next steps that I described as “ideas at this stage rather than anything built”.
That didn’t last long. Two of those ideas, proper stacking on the PC and publishing to my astronomy site, were built the same weekend and went live on 8 and 9 November. Since then two finished images have gone from a pile of 10-second frames on the NAS to published posts on vividgrey.co.uk, and the only thing I did by hand was press Publish.
First, was it worth it?
Before building anything, I had Claude Code do a proof of concept on the obvious candidate, the Whirlpool Galaxy (M 51), which is almost a quarter of everything I’ve captured. The question was simple: does stacking many nights together in Siril beat the Seestar’s own best single-night stack?
- A two-night test first. Two nights in May 2025 stacked in under two minutes. The detail was about the same as the Seestar’s stack from one of those nights, but Siril’s rejection removed a satellite trail that the Seestar had kept.
- Then everything. 6,254 sub-frames went in and 4,628 were stacked, about 12.9 hours of light. 792 frames failed to align and 834 were thrown out by a filter that rejects stars that aren’t round.
- The comparison. Against the Seestar’s best stack (1,362 frames, about 3.8 hours), the spiral arms are better defined, the faint plume of material around its companion galaxy NGC 5195 shows up, and there are more faint stars. The Seestar’s version has a slightly darker background, to be fair to it.
The verdict was “worth automating”, so we did.
The PC half: AstroProcessor
Siril would run on the Raspberry Pi, but the Pi is already busy with everything else, so the heavy lifting happens on my Windows PC. AstroProcessor is a Python script (standard library only) that Task Scheduler runs every Tuesday and Friday at 20:00. It started as Friday only; I added Tuesday the next day so that images arrive more often.
Each run processes exactly one target:
- It picks the target. It reads the Astronomy notes in my Obsidian vault and looks for deep-sky objects (not stars, planets, the Moon, the Sun or comets) that haven’t been processed yet and have at least an hour of frames. The one with the most integration wins. If a target was shot through more than one filter, only the filter with the most data is used.
- It copies the frames locally. Working directly from the NAS is too slow, and copying turned out to be the real bottleneck: in the proof of concept, copying M 51’s frames took 94 minutes and Siril itself only took 11.
- It stacks them. Siril’s command-line version runs a script based on the official Seestar preprocessing script: debayering, two-pass registration, the roundness filter and a rejection stack that throws out outliers such as satellite trails and aircraft.
- It finishes the image. A small crop to remove the ragged edges, background extraction, plate solving (working out exactly where in the sky the image points), and then colour calibration using Siril’s SPCC, which compares star colours against the Gaia catalogue with a profile for the Seestar’s sensor. Then a stretch, and a JPEG.
- It records everything. Alongside the JPEG it writes a JSON file with every capture and processing detail, and updates the target’s note in the vault with when it was processed, how many frames were used and how many hours they add up to.
The online catalogue servers Siril normally uses kept timing out, so the Gaia catalogues now live on the PC (22.4 GB of them) and everything runs offline. And in one of the first tests, colour calibration quietly fell back to none at all: the way Python is installed on that PC meant Siril couldn’t see its own saved settings. Every script now sets the catalogue locations itself, and the run falls back to a simpler calibration, then to none, rather than failing outright.
The Pi half: AstroPublisher
Every morning at 07:30, AstroPublisher on the Raspberry Pi looks for anything the PC has left in a “ready” folder on the NAS. Unlike a lot of my automations, there’s no AI involved at this stage. It’s a plain Python job that builds everything from the JSON file and the description in the target’s vault note. For each image it:
- Uploads it to Flickr, public, into a Seestar S50 album, with a title, description and tags.
- Creates a draft post on vividgrey.co.uk with the image (linked to Flickr) as both the main picture and the featured image, a short description of the object, a capture details table (frames captured, aligned and stacked, total integration, nights, exposure, gain, filter, sensor temperature, image scale, calibration and the Siril version) and a list of the processing steps.
- Updates my notes. The target’s note gets the Flickr and draft links, and the Daily note gets a line saying what was processed plus a checkbox reminding me to review and publish the draft. If I leave it, the reminder comes back every seven days.
- Notices when I’ve published. Once the post is live, the next run marks the target’s note as published, with the date and URL.
It also keeps an eye on the PC. If the Tuesday or Friday run produced nothing, the Wednesday or Saturday Daily note says so, and asks whether the PC was switched on. That has already happened once: this Friday’s run produced no image, and Saturday’s note told me.
The guardrails
This is the same pattern as the drafts on this blog, and the rules are deliberately narrow:
- Drafts only. The WordPress client can create a post with its status hard-coded to draft, upload new media and add missing categories and tags. It can’t publish, edit or delete anything, and its self-test checks the code for any other kind of write.
- No accidental secrets. It refuses any content containing one of my stored credentials, or anything shaped like a key or token, and it refuses duplicate titles.
- Flickr is add-only. The uploader only uploads new photos and never changes an existing one. Every upload is recorded by a fingerprint of the file, so the same image can’t go up twice.
- The raw data is read-only. The Pi sees the telescope’s files through a read-only mount. The only folder it can write to is the hand-off folder.
The first run’s bug
The very first live run is a good example of why those rules matter. AstroProcessor stacked M 51 overnight, from 22:35 on 8 November to 03:27 the next morning, and AstroPublisher was started by hand straight afterwards.
It failed at the Flickr step. The new uploader had created its record of uploaded photos as an empty file, and then crashed trying to read that empty file. The problem was that this happened after the upload. The photo was on Flickr, public, but not recorded and not in the album, so simply running it again would have uploaded it a second time.
The fix was small: an empty or missing record now counts as “nothing uploaded yet”, and the self-test covers that case. The photo that had already gone up was added to the record by hand so the retry reused it, and the retry a minute later went through cleanly.
The first two images

M 51, the Whirlpool Galaxy, was the first: 4,628 frames, 12 hours 52 minutes of integration, colour-calibrated against 115 stars. I published it on vividgrey on 9 November.

NGC 281, the Pacman Nebula, came from the first Tuesday run on 10 November: 2,002 of 2,564 frames from five nights between October and December 2025, 5 hours 34 minutes in total, calibrated against 1,239 stars. It was published on 12 November.
When AstroProcessor was first set up it found 16 candidates waiting, so there is plenty in the queue.
What I’ve learned
- Prove it before you build it. A proof of concept on a single target answered the only question that mattered, and made all the design decisions easier.
- Split the work where it belongs. The PC does the heavy processing; the Pi, which is always on, does the publishing and the reminding. They only talk through a folder on the NAS.
- Not everything needs an AI at run time. Claude Code built both halves, but once the decisions were made, plain scripts were the right tool. The AI’s judgement was spent once, up front.
- Make crashes safe, not just rare. The first-run bug was harmless because the job records each step and resumes where it stopped, and because the fix made the risky step safe to repeat.
- Keep a human on the Publish button. I’m happy for the pipeline to choose the target and accept the processing automatically, but nothing goes public on either site until I’ve looked at it.
Quality scoring of individual frames and a proper observing log are still on the ideas list. For now, though, the pile is finally turning into pictures.
A note on how this post was written: it was drafted by Claude Code from the AstroProcessor and AstroPublisher repos, their code history and my vault notes on the pipeline, and written into WordPress as a draft through the API. Claude chose the photos from my Flickr account. I reviewed and edited it before publishing.