2025 Sept 19 – Ephem Devlog 04
Ephem v2 has shipped! I'll take a step back from it for a little while and focus on other projects, learning other libraries, but in this devlog I'll talk about its new database front-end.
There are two disparate sources of inspiration for ephem's bidirectional database: Astrolog and mpd. I don't need to say too much about mpd, just that I'm copying the database in ~/.config/mpd that just lists local music files.
v1 has a data command that does the following:
data view: List every row of the SQLite3 tableephem.db.data load N: Runcastwith time/geodata in SQL IDN.data delete N: Delete chart by SQL ID.
All of this is intact in v2. The idea is for ephem to be perfectly usable with just these, but the inspiration for a more human-readable front-end comes from working with Astrolog for a year. It's a C++ program that's been maintained by one guy since 1991. I wrote a detailed tutorial for configuring it with the release of 7.8 in an attempt to evangelize astrologers away from GUIs.
Astrolog has no true database persistence, but it does have a "command switch" (vintage way to say a flag) -o that saves your input data to a plain text file containing the original command. This works, but requires memorizing cryptic positional arguments and coordinate formats. I tend to just cp an existing chart and edit the file in nvim, which lets me be really anal about coordinates in a way that rawdogging it in the shell doesn't allow. The openness of the -o flag means you can save charts in whatever directory you please. Mine is obviously a Git repo. To re-calculate charts from this data, you use a corresponding -i flag, astrolog -i <file-name>.
Storing pure time and geodata is smart because they're fixed. The chart you get in the end is the result of whatever astrological tradition you belong to and how it influences your choice of zodiac and house system, but those are just interpretative layers drawn over quantitative, astronomical data of longitudes between 0 and 360 degrees. If you need to edit the time or coordinates, that's a whole new chart. But astrolog -i doesn't technically store serialized data. Each file is just a long ass command that's still, ultimately, positional arguments whose meaning you have to extrapolate from context:
@AI780 ; Astrolog chart info.
-qb Sep 22 1957 12:20 10 142:25 -36:15
-zi "Nick Cave" "Warracknabeal, Victoria, Australia"
So I knew I wanted ephem's "database" to use YAML because it's very readable. There's no guessing what each argument means because each SQL column gets an explicit field:
# ~/.local/share/ephem/charts/nick-cave.yaml
name: Nick Cave
timestamp_utc: '1957-09-22T02:20:00+00:00'
timestamp_input: '1957-09-22T12:20:00+10:00'
latitude: -36.25
longitude: 142.416667
_metadata:
created: '2025-09-10T12:55:37.004823'
source: ephem_cli
tags: [famous, musician, adb, rodden-c]
ephem {cast,now} --save creates a new SQL row and a corresponding .yaml simultaneously. As an XDG nerd, I have ephem create its data files like
~/.local/share/ephem
|-- charts/
| `-- nick-cave.yaml
`-- ephem.db
But! What if you do my Astrolog-style workflow of making copies directly in charts/? Especially if you've edited charts generated by --save? That's where data sync comes in. It checks charts/ for anything missing from ephem.db and creates SQL rows for them according to the content of each .yaml file.
Since the three old data commands only interact with ephem.db, the charts/ folder is redundant in the positive, backup sense. This means when you run data delete N, the only way to truly delete the chart is by also running rm on its corresponding .yaml, otherwise data sync restores deleted SQL rows. If you never run data sync, however, this entire YAML layer means nothing to you.
This devlog was shorter, mostly because I wrote a separate post about writing the seven-part tutorial here and crossposted to DEV.to, which more generally covers documentation-driven development. The tl/dr; of that is: slow down and play dumb. Seriously. LARP as a brand new user and you'll catch all manner of things.
Until next time!
🐦⬛