<?xml version="1.0" encoding="utf-8"?><feed xmlns="http://www.w3.org/2005/Atom" ><generator uri="https://jekyllrb.com/" version="4.4.1">Jekyll</generator><link href="https://gibsonic.org/feed.xml" rel="self" type="application/atom+xml" /><link href="https://gibsonic.org/" rel="alternate" type="text/html" /><updated>2026-09-20T16:01:20+00:00</updated><id>https://gibsonic.org/feed.xml</id><title type="html">Perry Gibson 🍐</title><subtitle>Personal blog of Perry Gibson © 2026.</subtitle><author><name>Perry Gibson 🍐</name></author><entry><title type="html">It Wasn’t Supposed to Work: From the AI Winter to AI Agents with Robert Hooker</title><link href="https://gibsonic.org/blog/2026/09/20/robert_hooker/" rel="alternate" type="text/html" title="It Wasn’t Supposed to Work: From the AI Winter to AI Agents with Robert Hooker" /><published>2026-09-20T10:20:08+00:00</published><updated>2026-09-20T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2026/09/20/robert_hooker</id><content type="html" xml:base="https://gibsonic.org/blog/2026/09/20/robert_hooker/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2026-09-hooker.png" width="1024" /></p>

<p>I was sitting in a coffee shop earlier today, when the waitress asked where I
was from. A fella over at the next table caught the accent, and we got talking.
Somewhere in the next few minutes he mentioned he’d worked in an AI lab during
the AI winter of the late 80s, and I thought, since this random conversation
seems to be happening anyway, let’s capture it. I asked if he’d be comfortable
making it an interview format with transcription, so we agreed to sit down
properly.</p>

<p>Robert Hooker has been working in IT since 1989, starting at Northwestern
University’s Institute for the Learning Sciences and ending up in London, some
thirty-odd years later, running the internal AI adoption programme at a social
care charity. He says he’s watched this happen before.</p>

<!--more-->

<hr />

<p><strong>So tell us a wee bit about yourself and how you got started.</strong></p>

<p><em>My name is Robert Hooker. I’m a senior person in cloud computing. I have been
working in the field of IT since late 1989. I first worked in the United States
at Northwestern University’s Institute for the Learning Sciences. This was
during the AI winter, so the Institute was actually an AI lab.</em></p>

<p><em>The researcher who ran it was
<a href="https://en.wikipedia.org/wiki/Roger_Schank">Roger Schank</a>, a famous early AI
researcher, who I gather sadly features in the Epstein files. He was one of the
people who introduced the concept of “scripts” in early AI. An interesting
field, in a relatively failed branch of AI back then.</em></p>

<aside style="border-left: 3px solid #bbb; margin: 1.5em 0; padding: 0.4em 1em; font-size: 0.92em; color: #444;">
For the record: Schank (1946-2023) founded the Institute for the
Learning Sciences in 1989 on a $30m grant from Andersen Consulting. He was a
Florida neighbour of Jeffrey Epstein and attended an AI conference Epstein
sponsored on his island in 2002, six years before Epstein's 2008 conviction for
sex offences, and publicly supported him afterwards. His name appears in the
files released in 2026. See
<a href="https://en.wikipedia.org/wiki/Roger_Schank#Personal_life_and_death">Wikipedia</a>,
which cites <a href="https://slate.com/technology/2019/08/jeffrey-epstein-science-eugenics-sexual-abuse-researchers.html">Slate</a> (2019), in which Schank himself describes that meeting, and the
<a href="https://www.post-gazette.com/news/education/2026/03/01/carnegie-mellon-roger-schank-epstein-emails/stories/202602260118">Pittsburgh Post-Gazette</a> (2026).
</aside>

<p><em>We were still in what I call the Minsky winter, when Marvin Minsky thought he
had proven that neural nets would never work. So people weren’t working on them,
and they were trying to teach computers how to think in Lisp and getting
nowhere.</em></p>

<p><strong>Just to check, the Minsky proof, that was the XOR problem?</strong></p>

<p><em>Yeah, of course.</em></p>

<figure style="max-width: 32%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/a/ae/Marvin_Minsky_%28cropped%29.jpg" alt="Marvin Minsky" style="width: 100%;" />
  <figcaption>Marvin Minsky. With Seymour Papert, his 1969 book <a href="https://en.wikipedia.org/wiki/Perceptrons_(book)">Perceptrons</a> showed a single-layer perceptron couldn't compute XOR, which was widely (if unfairly) read as a death certificate for neural nets. Via <a href="https://commons.wikimedia.org/wiki/File:Marvin_Minsky_(cropped).jpg">Wikimedia Commons</a></figcaption>
</figure>

<p><em>And so I was being trained that machine learning was just really stupid, but a
lot of our people were very interested in it. It was a nightmare.</em></p>

<p><em>I do have a published academic paper, from a conference, Hooker and Slator, on
a model of AI decision-making. It didn’t say AI, of course, because we were in
the AI winter. But it was about how agents make decisions in an economic role,
by the agents simulating pursuits.</em></p>

<p><em>And that was where I introduced Brian Slator, who went on to North Dakota State
University to do the rest of his career research there.</em></p>

<aside style="border-left: 3px solid #bbb; margin: 1.5em 0; padding: 0.4em 1em; font-size: 0.92em; color: #444;">
The paper is
<a href="https://www.semanticscholar.org/paper/A-Model-of-Consumer-Decision-Making-for-a-Mud-Based-Hooker/062dbff9c40c8ae03261f7c2e43843a4470283e4">A Model of Consumer Decision Making for a Mud Based Game</a>
(Hooker &amp; Slator, 1996), presented at the Simulation-Based Learning Technology
Workshop at ITS'96 in Montréal. The agents lived in a
<a href="https://en.wikipedia.org/wiki/Multi-user_dungeon">MUD</a>, a networked
multiplayer text world built to teach microeconomics, and the problem was getting
a simulated shopper to behave plausibly enough that students kept playing for
weeks.
<a href="https://www.ndsu.edu/computer-science/people">Slator</a> stayed on that
track for the rest of his career, building multi-user educational games for
teaching programming, geosciences, economics, and cell biology. He spent nearly 26
years at NDSU and headed its computer science department from 2007 to 2017. He
died in May 2020.
</aside>

<p><em>But I didn’t stick around in academia. In the mid-90s I went to the private
sector, going from web design, to SharePoint, to cloud, to Microsoft 365, and
now Copilot. The guiding principle, which I’d recommend to all the young people
in IT: if you can’t beat them, join them.</em></p>

<figure style="max-width: 45%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/d/de/Symbolics-3600-on.jpg" alt="A Symbolics 3600 Lisp machine" style="width: 100%;" />
  <figcaption>A Symbolics 3600 Lisp machine. Specialised hardware for a paradigm that was about to fall out of fashion. The collapse of the Lisp machine market in the late 80s is often given as the start of the AI winter proper. Via <a href="https://commons.wikimedia.org/wiki/File:Symbolics-3600-on.jpg">Wikimedia Commons</a></figcaption>
</figure>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"For us older guys, this wasn't supposed to have worked. And it just blew our minds."
</blockquote>

<p><strong>Have you come across the idea of
<a href="http://www.incompleteideas.net/IncIdeas/BitterLesson.html">Sutton’s Bitter Lesson</a>?
I work in the neural network space, and the idea addresses the frustrating trend
that you throw more and more compute at the problem and it just somehow works
better.</strong></p>

<p><em>Oh yeah, that principle. Which wasn’t supposed to work. That’s what was
amazing.</em></p>

<p><em>I gave an interview about 16 years ago on a podcast called
<a href="https://thefutureandyou.libsyn.com/june_9_2010_episode">The Future And You</a>,
and he asked me about predictions. And I did not say that. Some voice
recognition, maybe, but the way I hedged it was: “I’ve been surprised before.”</em></p>

<aside style="border-left: 3px solid #bbb; margin: 1.5em 0; padding: 0.4em 1em; font-size: 0.92em; color: #444;">
The episode is still up. Robert was a recurring guest on Stephen Euin Cobb's
<a href="https://thefutureandyou.libsyn.com/">The Future And You</a> across 2009
and 2010, and the AI one is
<a href="https://thefutureandyou.libsyn.com/june_9_2010_episode">9 June 2010</a>,
billed as "artificial intelligence; how and when conversational AI may appear in
our lives; the semantic web as an AI platform; AI for Internet search; the money
to be made in AI; simulating AI with a brute force program which is not
intelligent at all; Wolfram Alpha". Sixteen years and three months before we sat
down. The same listing also promises the story of "why he was once presumed dead
for three days", which I did not know to ask about.
</aside>

<p><em>When you work with a small neural net, there’s an optimal number of layers,
there’s an optimal amount of training. But when you have a massive set of these
weighted neurons, for us older guys, this wasn’t supposed to have worked. And it
just blew our minds.</em></p>

<p><em>It took a while convincing. It took me several months of playing with OpenAI to
be convinced that it actually was working. And here’s the thing. If you go to it
determined to show it doesn’t work, it’s very easy. It’s very, very compliant in
not working for you.</em></p>

<p><strong>I suppose you get the answer you went looking for.</strong></p>

<hr />

<h2 id="an-interlude-in-edinburgh">An interlude in Edinburgh</h2>

<p><strong>The reason we got talking in the first place was you’d mentioned being in
Edinburgh for the 2014 referendum. What was that like, being in the buzz of
it?</strong></p>

<p><em>Oh, it was a lot of fun. My wife and I, my late wife, if I can make a plug for
her, her name was Gail Orenstein. Just Google “female drone journalist”, she
shows up. She died five years ago, which is unfortunate, but she was a very
well-respected journalist. It was always a lot of fun with her.</em></p>

<p><em>I was working remote at the time, so I could go and spend a whole week in
Edinburgh while working. And to be honest, this wasn’t like the Brexit
referendum. It wasn’t ugly, it wasn’t bitter, at least in Edinburgh. There were
some fisticuffs that we saw, and some crazy things being yelled back and forth,
but for the most part I saw it as an amazing celebration of Scottish identity,
tempered with Scottish practicality.</em></p>

<figure style="max-width: 60%; margin: 0 auto 1.5em;">
  <img src="/assets/pics/2026-09-orenstein-calais.jpg" alt="Police stand among burning shelters in the Calais refugee camp" style="width: 100%;" />
  <figcaption>Calais, 2016, from Gail Orenstein's own portfolio. She travelled to 84 countries over her career, covering conflict and humanitarian stories, and was the first woman to fly a drone in Kurdistan during the Mosul offensive. © Gail Orenstein, used with permission from Robert.</figcaption>
</figure>

<p><strong>Ha, mind you, the fisticuffs might just have been a typical night out in
Edinburgh.</strong></p>

<p><em>Or even lighter than a typical night out in Edinburgh.</em></p>

<p><em>I also do art, and I found it artistically very inspiring. Edinburgh is just
inspiring to begin with, but then to see all this going on as well. I was doing
illustrations where I brought Edinburgh alive by merging the statues with the
people. My drawings included the birds on their heads taking shifts, because
that’s what you actually see.</em></p>

<p><em>And one of the great joys of being a journalist is that you’re an observer. The
thing that really struck me, comparing it to the Brexit nightmare, was a wedding
photograph where the bride was Yes and the father was No Thanks. It was a great
photograph. Brexit was never like that. Brexit was just ugly.</em></p>

<p><strong>Aye, definitely a more alienating experience, at least from how I saw it.</strong></p>

<hr />

<h2 id="the-dot-com-bubble-and-who-held-their-nerve">The dot-com bubble, and who held their nerve</h2>

<p><strong>You mentioned being around for the dot-com bubble. What was that like?</strong></p>

<p><em>In the late 90s it was great. A lot of my friends were working as contractors
in IT, and deployment was still pretty limited and very development-focused. Two
things got the IT community involved.</em></p>

<p><em>One, it was the first time something was being delivered where you didn’t have
to install anything on the end machines. The same bit of work could go on an
Apple. People forget how revolutionary that is.</em></p>

<p><em>Secondly, it was the introduction of lightweight languages that weren’t C or
C++. You could run websites on PHP, which was a bit poor, but it was very
revolutionary at the time. Then ASP came out, and that took off too. Java Server
Pages were too heavy-handed and didn’t take off. And then JavaScript, and you
could separate what was happening on the client.</em></p>

<p><em>So suddenly there was an easy level of entry if you were a technical person.
And suddenly there was demand for graphic art skills, which there hadn’t been
before. All of our friends in the late 90s were suddenly making a lot of money.
That’s when I moved to England with my wife, because she was a photojournalist
and wanted to be in England for obvious reasons.</em></p>

<p><em>But the investment was way over the line. And when that dried up, for a few
years you couldn’t get any work. It was really, really hard. The bomb hit in
2000, and by late 2002 it was as much because of 9/11 as it was because of the
internet. The financial system just stopped funding. But within three years it
was back up and running.</em></p>

<p><strong>So what’s the lesson you’d draw for what could be called the contemporary AI
bubble?</strong></p>

<p><em>The people who didn’t panic and stuck with the internet during the dot-com
bomb, when all the brains were saying it was bad, the Bezoses and the
Zuckerbergs, they’re the richest people on the planet right now. So better to be
closer to the people who held their nerve, if you have a choice. I’ve been there
before.</em></p>

<p><strong>There’s probably a good few AI Pets.com knocking about right now. But Amazon
came out the other side looking not bad at all.</strong></p>

<p><em>Maybe. But there is a difference. Back in the day you could create a website on
a single server plugged into the internet. You could pay under $1,000 for the
server, run e-commerce on it, deliver solutions on a pressed CD. It’s not like
that now. You’ve got big players who are really well-heeled. Amazon, Microsoft,
Google, and Meta all have revenue streams. Those are the big players in AI.</em></p>

<p><em>I famously missed the social media wave, by the way. I had a nephew who
attended Harvard at that time, and he comes in and says “a friend of mine is
creating a social network”, and I said, “Microsoft and Yahoo are dominant.”</em></p>

<p><strong>Auch, geezo. That’s a story to tell at least.</strong></p>

<hr />

<h2 id="what-hes-doing-now">What he’s doing now</h2>

<p><strong>So what is it you’re doing now?</strong></p>

<p><em>Right now, my wife passed away five years ago, so I kind of slowed down. But
I’m working for a not-for-profit called
<a href="https://www.dimensions-uk.org/">Dimensions</a>, which just won an award for being
the best workplace in social care and not-for-profit in the UK. We’re the UK’s
biggest not-for-profit provider of support for adults with learning disabilities
and autistic people, but we don’t even have 3% of the market. So even though
we’re the biggest, and we grow like crazy, we’re not quite sure where to go in
the future.</em></p>

<aside style="border-left: 3px solid #bbb; margin: 1.5em 0; padding: 0.4em 1em; font-size: 0.92em; color: #444;">
The award is the
<a href="https://www.greatplacetowork.co.uk/">Great Place to Work</a> Institute's
UK's Best Workplaces list, where Dimensions placed
<a href="https://www.dimensions-uk.org/news-item/a-great-place-to-work-for-eight-years-running/">18th in the Super Large (1,000+ employees) category in 2026</a>,
accredited for the eighth year running and, as they put it, "the highest-ranking
not-for-profit social care organisation". They also sit
<a href="https://www.dimensions-uk.org/news-item/were-on-the-2026-uks-best-workplaces-for-wellbeing-list/">24th on the same body's Best Workplaces for Wellbeing list</a>,
up from 43rd in 2024.
</aside>

<p><em>I was hired about four or five years ago to work with cloud computing and
architecture. But then AI got introduced, and so what I’ve been doing for most
of the last two years is overseeing our internal AI adoption project.</em></p>

<p><strong>And how’s that going?</strong></p>

<p><em>Very interesting, but also very challenging, especially with security teams.
They want some kind of framework to make sure their AI is compliant. And I keep
telling them: these frameworks don’t work as of yet.</em></p>

<p><em>I was at a conference by one of the vendors, and I kept asking, “look, I’m
building these AI agents. I’ve been told by security that they’re concerned,
without them telling me exactly why. So how do I structure my project?” And all
they say is “buy this product.” No. That’s not going to fix it.</em></p>

<p><em>I know from being an architect, you have your business requirements statement,
and a process that takes you from there to something you can test. That isn’t
here in AI as of yet. The big problem with an agent business requirement is that
people don’t know to ask for a chatbot that has cognitive skills in a certain
area. So we get people to understand LLMs, then get them to understand what
agents can do. And then suddenly the use cases come out of the roof.</em></p>

<p><strong>What are the concerns, especially given you’re working with quite sensitive
data?</strong></p>

<p><em>First of all, I’m doing it very differently from a lot of the big businesses.
I’ve talked to friends of mine who are concerned, in large part because the
companies are coming in and deploying it as if it’s an old factory where you put
in new machinery, kick the staff out and put security guards in front of it.
That isn’t how we’re doing it, and I don’t think that’s going to work.</em></p>

<p><em>Because we’re a not-for-profit, almost everybody working with us could make
more money somewhere else and they choose to stay anyway. So we have a
motivation factor that isn’t just the money. That gives us an opportunity,
because they actually trust us.</em></p>

<p><em>So we’re getting people who are overwhelmed, constantly having to file this
report and that report, keeping the news updates going, updating the web page
and the intranet page, underpaid and we can’t hire new people. And I’m saying:
alright, here’s Copilot, this is what it can do, ask me about it. And then we
get them to discover the uses.</em></p>

<p><strong>So it’s grassroots? You’re trusting your colleagues’ expertise and seeing
where you can cut, so they can focus on what actually matters?</strong></p>

<p><em>Yeah. They’re focusing, and I’m out there to support them with the technology.</em></p>

<p><strong>And the compliance side of that?</strong></p>

<p><em>We’re constantly getting more and more regulations about how to work. We have
to have a person whose only job is to tell us what’s GDPR compliant and what
isn’t. So we have to spend money and effort on it, and keep going on it. It’s
kind of a pain, but we do it.</em></p>

<p><em>Mind you, the punishment for not bothering is really just your reputation. If
you’re determined to keep yours, you do it properly. So it ends up being a kind
of self-imposed punishment for the people who decide to do it the right way.</em></p>

<p><em>And the thing is, you can also use GDPR to annoy people. You just go on an AI
and it can write a GDPR request, and you can inundate somebody you’re mad at
with them. Although I’ve spoken to the people who handle ours, and they don’t
think they’re getting many of those. Ours are mostly sincere, very often because
somebody’s moved house and they just want to make sure their record is
complete.</em></p>

<p><strong>So the future of agents is folk flooding their competitors with GDPR requests
using agents, and then those agents responding to all of it.</strong></p>

<p><em>They’ve been doing that with lawsuits forever.</em></p>

<p><strong>Aye, lawsuits, patent trolling. It’s cheaper to annoy.</strong></p>

<p><em>You don’t have to be a rich person to make somebody’s life miserable.</em></p>

<hr />

<h2 id="why-the-code-monkey-is-going-away">Why the code monkey is going away</h2>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"You have to become an expert in every agent you write."
</blockquote>

<p><strong>Has building agents changed how you’d approach a project?</strong></p>

<p><em>One of the things you learn very quickly with agents is that the old
traditional “give me the requirements, I’ll write the use cases, and I’ll code
it” does not work in cognitive computing. You have to become an expert in every
agent you write. If it’s a finance agent, you have to become an expert in
finance.</em></p>

<p><em>There was a project manager who wanted an agent, and at first I thought I’d
just point it at all their templates and processes. And it was okay. But to get
it to work appropriately, what I had to do was write proper ontologies into the
RAG to explain how the work actually worked, and run it through, and run it
through.</em></p>

<p><em>I end up having to learn, which I enjoy, but I think in the future a good
programmer in AI isn’t going to be a code monkey. Code monkey is going to be a
career that goes down. It’s going to be somebody who works in a certain field
and is really good at cognitive descriptions of that field. Somebody who can
understand what cognitive skills are necessary to do a particular job.</em></p>

<p><em>Which pushes AI more into psychology, sociology, and literature. I have an
undergraduate degree in cognitive science, and that’s been much more useful than
anything else in the current work. Particularly behavioural theory.</em></p>

<p><strong>Go on, what carries over?</strong></p>

<p><em>One rule of cognitive theory is that it’s not enough to say no. If you’re
correcting a behaviour that’s wrong, it’s very hard to just tell someone to stop
doing it. You have to tell them the proper behaviour instead.</em></p>

<p><em>So when you do a RAG design and your instructions are just “don’t do this,
don’t do that”, it’s not going to be as effective as one that says “do this
rather than that.” That’s solid psychology.</em></p>

<p><em>Computer programmers think if-then, if-then. And it didn’t matter if it was
negative or not. Nobody worries about that. But human beings don’t work that
way. What works for humans is “not this, rather this.”</em></p>

<p><strong>Aye, rather than the strict logic of C, you’re almost shaping a surface for it
to slide towards what you want.</strong></p>

<p><em>I don’t know what’s going on in the industry side of it, but I do know from
behavioural cognitive studies that this has been established for almost two
centuries now as the right way to go.</em></p>

<p><strong>That resonates. Two years ago 80% of my job was writing code; now maybe it’s
5%. A lot of it is managing agents, and another part is just talking to
people.</strong></p>

<p><em>Mine was the same. About five years ago 80% of my job was writing documents
that nobody would read. Now I do none of that. Now I’m talking to people.</em></p>

<hr />

<h2 id="hallucination-or-imagination">Hallucination, or imagination</h2>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"In probably 10 years they'll rename hallucination to 'imagination'. Because that's really what it is."
</blockquote>

<p><strong>What about the risks?</strong></p>

<p><em>The back-end ones we’ve covered. The big risk on the front end is, of course,
hallucination. And you can lecture all you want, but people are going to have to
learn from their own negative experience. Unfortunately, if you go on social
media, people think that one negative experience proves the whole thing doesn’t
work.</em></p>

<p><em>But this is one of the things I’ve learned. I’ve had some agents where I put in
such guardrails that they wouldn’t hallucinate. The problem was that they
couldn’t generate new thinking either.</em></p>

<p><strong>Right, you make it so safe it can’t say anything useful.</strong></p>

<p><em>I just thought hallucination was bad. But look, you’re a human being. I may ask
you a question about something you’ve never dealt with before, and you may
imagine some solution. You’re going to have to test it, but you might come up
with something.</em></p>

<p><em>So you need to look at the domain. Is this something that needs a precise legal
answer? Turn hallucination down. Other things, like drafting job adverts or
public announcements, those things need to hallucinate some.</em></p>

<p><em>In probably 10 years they’ll rename hallucination to “imagination”. Because
that’s really what it is. And people will just take it for granted: don’t let
the thing’s imagination get away with it. You’ve got to contain its imagination.
I think it’s a better term.</em></p>

<p><strong>Any other experiences that have made a difference?</strong></p>

<p><em>The biggest one is getting people to not write prompts, but to write prompts
that write prompts. Write a prompt to write a prompt, then review that, then run
the prompt. That’s the best way to go. The AI speaks AI better than you.</em></p>

<hr />

<p><strong>Cheers Robert, one of the more fruitful random coffee shop conversations I’ve
had.</strong></p>

<p>He had a sketchbook with him, and got me to photograph a couple of pages before
I left. Not the Edinburgh statues he’d described (from over a decade ago), but
pen studies of insects, flowers, shells, and shapes coming apart.</p>

<figure style="max-width: 78%; margin: 0 auto 1.5em;">
  <img src="/assets/pics/2026-09-hooker-sketchbook-1.jpg" alt="Sketchbook page of pen drawings of insects, flowers, and geometric forms" style="width: 100%;" />
  <figcaption>Pen studies from Robert's sketchbook. The note in the bottom right reads "simple representation becoming more complex".</figcaption>
</figure>

<figure style="max-width: 78%; margin: 0 auto 1.5em;">
  <img src="/assets/pics/2026-09-hooker-sketchbook-2.jpg" alt="Open sketchbook spread with flowing abstract pen drawings" style="width: 100%;" />
  <figcaption>Another spread, in the coffee shop where we'd been talking.</figcaption>
</figure>

<p>We chatted a bit more off the record after that, and then I finished my coffee
and carried on with my day.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="ai" /><category term="interviews" /><category term="history" /><category term="cloud" /><category term="agents" /><summary type="html"><![CDATA[I was sitting in a coffee shop earlier today, when the waitress asked where I was from. A fella over at the next table caught the accent, and we got talking. Somewhere in the next few minutes he mentioned he’d worked in an AI lab during the AI winter of the late 80s, and I thought, since this random conversation seems to be happening anyway, let’s capture it. I asked if he’d be comfortable making it an interview format with transcription, so we agreed to sit down properly. Robert Hooker has been working in IT since 1989, starting at Northwestern University’s Institute for the Learning Sciences and ending up in London, some thirty-odd years later, running the internal AI adoption programme at a social care charity. He says he’s watched this happen before.]]></summary></entry><entry><title type="html">Scheduling Folk</title><link href="https://gibsonic.org/blog/2026/04/12/folk_scheduling/" rel="alternate" type="text/html" title="Scheduling Folk" /><published>2026-04-12T08:00:00+00:00</published><updated>2026-04-12T08:00:00+00:00</updated><id>https://gibsonic.org/blog/2026/04/12/folk_scheduling</id><content type="html" xml:base="https://gibsonic.org/blog/2026/04/12/folk_scheduling/"><![CDATA[<p>Keeping in touch with people is something I care about, but there’s plenty of
folk that I care about that I wouldn’t stay in contact with the regularity that
I want <em>without</em> proper scheduling. Unless it’s more than once a week, the habit
just doesn’t form, and life gets in the way.</p>

<p>A few years ago, I started treating it like a systems problem and built a
scheduling layer around it. Motivated by a recent chat with some interested
parties, this post briefly documents that system, how it broke, and where I’ve
landed.</p>

<!--more-->

<h2 id="some-philosophy">Some philosophy</h2>

<p>I dinnae want to turn this post into a pontification on humans as social
creatures, and compare and contrast (possibly outmoded) models of evolutionary
psychology vs contemporary and future-facing aesthetics of the woven nets of
relationships that we want to build. Buy me a coffee and yap on that one-on-one.</p>

<p>However, keeping up with folk is something I like to do, and I believe in the
power of my own agency: that I can decide the things I want to do, and have some
understanding of why I want to do it.</p>

<p>Once I’ve exercised the agency of choice, I’m keen to minimise the number of
low-agency steps required to achieve that. This is why I like having keyboard
shortcuts for common tasks: intent, action, and result should all be closely
linked.</p>

<p>Given that, exercising the agency of “I want to maintain this relationship with
someone that I’m not constantly thinking about” (e.g., not a partner or
immediate family member) can be thought of as a systems problem, intersecting
with the social dynamics of it all. Understanding what stage a relationship is
at, if you or the other person just isn’t feeling it and you should back off,
and what you should be talking about is all something I want to be using my own
judgement for.</p>

<p>Or put simply, I want to be the one actually living my relationships, any
tooling around it should just make that easier.</p>

<p>We <em>can</em> automate the other parts, but that seems a bit grim. Born, push a
button to do all the things in your life, die.</p>

<p>In typical tech person fashion, let’s quickly make the evil thing, because it
<em>can</em> be done. I beg you <strong>not</strong> to use the following script:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">anthropic</span>
<span class="kn">from</span> <span class="n">people</span> <span class="kn">import</span> <span class="n">Person</span><span class="p">,</span> <span class="n">is_due</span>


<span class="k">def</span> <span class="nf">build_prompt</span><span class="p">(</span><span class="n">person</span><span class="p">:</span> <span class="n">Person</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="n">history_block</span> <span class="o">=</span> <span class="sh">"</span><span class="se">\n</span><span class="sh">"</span><span class="p">.</span><span class="nf">join</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">- </span><span class="si">{</span><span class="n">m</span><span class="si">}</span><span class="sh">"</span> <span class="k">for</span> <span class="n">m</span> <span class="ow">in</span> <span class="n">person</span><span class="p">.</span><span class="n">message_history</span><span class="p">[</span><span class="o">-</span><span class="mi">3</span><span class="p">:])</span> <span class="ow">or</span> <span class="sh">"</span><span class="s">None</span><span class="sh">"</span>
    <span class="k">return</span> <span class="sa">f</span><span class="sh">"""</span><span class="s">
You are helping someone maintain their relationships. Draft a short, warm, natural message to send to:

Name: </span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">name</span><span class="si">}</span><span class="s">
Relationship: </span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">relationship</span><span class="si">}</span><span class="s">
Contact frequency goal: </span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">frequency</span><span class="si">}</span><span class="s">
Last contacted: </span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">last_contacted</span><span class="si">}</span><span class="s">
Recent message history:
</span><span class="si">{</span><span class="n">history_block</span><span class="si">}</span><span class="s">

Keep it brief (2–4 sentences). Don</span><span class="sh">'</span><span class="s">t be generic or sycophantic. Match the tone to the relationship.
Make it genuine, witty, and not weird.  The feeling of living in an alienated dystopia where even the
connections between friends has melted away to tokenisation should *not* come across.
</span><span class="sh">"""</span><span class="p">.</span><span class="nf">strip</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">generate_message</span><span class="p">(</span><span class="n">client</span><span class="p">:</span> <span class="n">anthropic</span><span class="p">.</span><span class="n">Anthropic</span><span class="p">,</span> <span class="n">person</span><span class="p">:</span> <span class="n">Person</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span>
    <span class="n">response</span> <span class="o">=</span> <span class="n">client</span><span class="p">.</span><span class="n">messages</span><span class="p">.</span><span class="nf">create</span><span class="p">(</span>
        <span class="n">model</span><span class="o">=</span><span class="sh">"</span><span class="s">claude-opus-4-5</span><span class="sh">"</span><span class="p">,</span>
        <span class="n">max_tokens</span><span class="o">=</span><span class="mi">256</span><span class="p">,</span>
        <span class="n">messages</span><span class="o">=</span><span class="p">[{</span><span class="sh">"</span><span class="s">role</span><span class="sh">"</span><span class="p">:</span> <span class="sh">"</span><span class="s">user</span><span class="sh">"</span><span class="p">,</span> <span class="sh">"</span><span class="s">content</span><span class="sh">"</span><span class="p">:</span> <span class="nf">build_prompt</span><span class="p">(</span><span class="n">person</span><span class="p">)}],</span>
    <span class="p">)</span>
    <span class="k">return</span> <span class="n">response</span><span class="p">.</span><span class="n">content</span><span class="p">[</span><span class="mi">0</span><span class="p">].</span><span class="n">text</span><span class="p">.</span><span class="nf">strip</span><span class="p">()</span>


<span class="k">def</span> <span class="nf">run</span><span class="p">(</span><span class="n">people</span><span class="p">:</span> <span class="nb">list</span><span class="p">[</span><span class="n">Person</span><span class="p">])</span> <span class="o">-&gt;</span> <span class="bp">None</span><span class="p">:</span>
    <span class="n">client</span> <span class="o">=</span> <span class="n">anthropic</span><span class="p">.</span><span class="nc">Anthropic</span><span class="p">()</span>

    <span class="k">for</span> <span class="n">person</span> <span class="ow">in</span> <span class="n">people</span><span class="p">:</span>
        <span class="k">if</span> <span class="ow">not</span> <span class="nf">is_due</span><span class="p">(</span><span class="n">person</span><span class="p">):</span>
            <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">⏭ Skipping </span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">name</span><span class="si">}</span><span class="s"> — not due yet</span><span class="se">\n</span><span class="sh">"</span><span class="p">)</span>
            <span class="k">continue</span>

        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s">✉ Generating message for </span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">name</span><span class="si">}</span><span class="s"> (</span><span class="si">{</span><span class="n">person</span><span class="p">.</span><span class="n">relationship</span><span class="si">}</span><span class="s">)</span><span class="sh">"</span><span class="p">)</span>
        <span class="n">msg</span> <span class="o">=</span> <span class="nf">generate_message</span><span class="p">(</span><span class="n">client</span><span class="p">,</span> <span class="n">person</span><span class="p">)</span>
        <span class="nf">print</span><span class="p">(</span><span class="sa">f</span><span class="sh">"</span><span class="s"> → </span><span class="si">{</span><span class="n">msg</span><span class="si">}</span><span class="se">\n</span><span class="sh">"</span><span class="p">)</span>
</code></pre></div></div>

<h2 id="the-original-system-emacs-org-mode">The original system: Emacs org-mode</h2>

<p>My first serious attempt was back in late undergrad, and used
<a href="https://orgmode.org/">org-mode</a> in Emacs.</p>

<p>Emacs is a family of text editors that traces its roots back to the 1970s,
originally developed at MIT. The GNU Emacs branch, maintained by Richard
Stallman — of the Free Software Foundation and GNU Project fame — has been the
dominant strain since the 1980s and remains actively developed today. It’s less
a text editor than a Lisp runtime that happens to be very good at editing text.</p>

<p><a href="https://commons.wikimedia.org/wiki/File:Richard_Stallman_2005_(chrys).jpg"><img src="https://upload.wikimedia.org/wikipedia/commons/4/46/Richard_Stallman_2005_%28chrys%29.jpg" alt="Richard Stallman at FOSDEM 2005" /></a>
<em>Stallman at FOSDEM 2005. Photo by chrys,
<a href="https://creativecommons.org/licenses/by/2.0/">CC BY 2.0</a>.</em></p>

<p>Org-mode has a built-in scheduling syntax that lets you attach dates and
recurrence patterns to any heading. The agenda view then collects everything due
today across all your files — a kind of personal dashboard.</p>

<p>A contact entry might look like this:</p>

<pre><code class="language-org">* Vangelis Ogunkunle
  SCHEDULED: &lt;2026-01-15 Thu +4w&gt;
  :PROPERTIES:
  :CATEGORY: folk
  :END:
</code></pre>

<p>The <code class="language-plaintext highlighter-rouge">+4w</code> suffix is a repeat interval: once you mark the task done, it
reschedules itself four weeks forward. You can also use <code class="language-plaintext highlighter-rouge">++</code> (shift by interval
from today, not from the original date) or <code class="language-plaintext highlighter-rouge">.+</code> (shift from today, but only
forward) depending on how strict you want to be about drift:</p>

<pre><code class="language-org">SCHEDULED: &lt;2026-01-15 Thu ++4w&gt;   ; always lands on a fixed cadence
SCHEDULED: &lt;2026-01-15 Thu .+4w&gt;   ; 4 weeks from whenever you actually did it, my preferred approach for this
</code></pre>

<p>Running my shortcut for <code class="language-plaintext highlighter-rouge">M-x org-agenda</code> and pressing <code class="language-plaintext highlighter-rouge">a</code> gave me a daily/weekly
view of everyone I was due to speak to. It was great. The system lived in a
single <code class="language-plaintext highlighter-rouge">folk.org</code> file, was version-controlled with the rest of my config, and
required zero internet access.</p>

<p>I would take a look at my agenda, see who I felt like messaging that day, and
adjust the schedule frequency if I felt it needed to be made more or less
frequent.</p>

<p>A typical day might look something like:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>Sunday     12 April 2024
================================================================================
 Folk
  folk:                      Lorna Rauf
  folk:                      Aunt Redacted
  folk:                      Akshil Wierzbicki

 General Tasks
  agenda:                    Watch Welder talk
  agenda:                    libclang exploration
  agenda:                    ALIFE conference review
</code></pre></div></div>

<p>Crucially, I’m not obliged to message a person on that day, they will roll over
until I actually check them off.</p>

<p>The <a href="https://orgmode.org/manual/Agenda-Views.html">agenda view</a> is just one
piece of it — org-mode and Emacs more broadly are very configurable through
their
<a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Easy-Customization.html">built-in customisation system</a>
and
<a href="https://www.gnu.org/software/emacs/manual/html_node/emacs/Init-File.html">init file</a>.
Want custom agenda commands that filter by tag, show only people you haven’t
contacted in over a month, or group by city? All doable. The price of admission
is a willingness to spend time in the parenthesis mines of Lisp.</p>

<h2 id="how-it-fell-apart">How it fell apart</h2>

<p>I moved to London in 2024, and suddenly found myself with a tube commute, and a
corpo laptop. I didn’t feel comfortable putting my social web on something that
could ostensibly come out in discovery or the whims of company IT.</p>

<p>I also found I wasn’t using my personal laptop daily, I was out and about doing
stuff in my off-hours. As a result, I found a few months in “hey, I’ve not been
maintaining some of the relationships that I care about, why is that?”.</p>

<p>I realised that my system was reliant on daily use of my personal laptop, and
the time that I was free to message and catch up with people was on an
underground train, on mobile, with minimal internet connection.</p>

<p>Alas, Emacs as I use it is not well suited to the mobile experience, so I needed
a stop-gap solution.</p>

<h2 id="google-calendar-tasks-a-workable-compromise">Google Calendar Tasks: a workable compromise</h2>

<p>Google Tasks (built into Google Calendar, and also as a standalone app) turned
out to be a reasonable middle ground. It syncs to my phone, works offline on the
underground, and supports due dates with recurrence. I’ve given social tasks
their own colour, to make them distinct from other tasks and calendar events.</p>

<p>The workflow is simple: each person gets a task, set to repeat on whatever
cadence makes sense. When I’m on the tube, I can take a look at my Google
calendar for the day, and see who’s up.</p>

<p><img src="/assets/folk-scheduling/google-calendar-day-view.jpg" alt="Google Calendar day view showing folk tasks highlighted in yellow among other events" />
<em>Day view — folk tasks show up in yellow alongside regular calendar events.</em></p>

<p>Adding a new contact task is just a tap on the + button, then selecting “Task”:</p>

<p><img src="/assets/folk-scheduling/google-calendar-new-task-menu.jpg" alt="Google Calendar new item menu showing options including Task" />
<em>The new item menu — Task sits alongside Event and other options.</em></p>

<p>Each task gets a repeat interval, set at creation:</p>

<p><img src="/assets/folk-scheduling/google-calendar-task-recurrence.jpg" alt="Google Calendar task creation screen showing &quot;Message bofa&quot; repeating every 6 weeks" />
<em>Setting a 6-week repeat on a contact task.</em></p>

<p>It doesn’t have org-mode’s expressive repeat syntax, and the wide scope of
additional configuration I’d like to have. But it’s good enough, and critically,
it’s always with me.</p>

<h2 id="the-future-getting-back-to-org-mode">The future: getting back to org-mode</h2>

<p>The org-mode approach is still the one I’d prefer. The plain-text format, the
expressive scheduling syntax, increased privacy, the dork creds, and the
composability with the rest of my Emacs workflow are hard to replicate. The
question is just whether I can get it onto my phone reliably enough to replace
Google Tasks for the commute use case.</p>

<p>In an era of agentic coding, sure it will be way easier, however the question is
how arsed I can be, given this approach seems to be “good enough” for how my
life is going right now.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="emacs" /><category term="orgmode" /><category term="folk" /><summary type="html"><![CDATA[Keeping in touch with people is something I care about, but there’s plenty of folk that I care about that I wouldn’t stay in contact with the regularity that I want without proper scheduling. Unless it’s more than once a week, the habit just doesn’t form, and life gets in the way. A few years ago, I started treating it like a systems problem and built a scheduling layer around it. Motivated by a recent chat with some interested parties, this post briefly documents that system, how it broke, and where I’ve landed.]]></summary></entry><entry><title type="html">Token Cyborgs</title><link href="https://gibsonic.org/blog/2026/03/10/token_cyborgs/" rel="alternate" type="text/html" title="Token Cyborgs" /><published>2026-03-10T08:00:08+00:00</published><updated>2026-03-10T08:00:08+00:00</updated><id>https://gibsonic.org/blog/2026/03/10/token_cyborgs</id><content type="html" xml:base="https://gibsonic.org/blog/2026/03/10/token_cyborgs/"><![CDATA[<p>The token cyborg mediates some or all of their everyday experience through AI
models.</p>

<!--more-->

<p>The legible artefacts of notes and software tools accrue in their home
directories, most of which has not been fully read by their eyes. But they trust
that it sufficiently represents their will, and it may have its use down the
line.</p>

<p>They may pass the audio of their meetings or conversations through models, for
summarisation or analysis. The motivated will have live interaction, consulting
their models for potential insights or questions to ask. With practice, the
pauses and darting eyes are difficult to spot.</p>

<p>The personal agency of the token cyborg will vary. Some wear their models like
exo-skeletons, strengthening their own resolve, and amplifying their will.
Others are worn by the models, productive half hours passing with nary a
conscious thought.</p>

<p>The token cyborg hungers for larger context windows, longer reasoning chains,
higher throughput, lower latency. In an hour they may crunch through more
floating-point ops than the whole human race did until around the time of the
Chernobyl disaster.</p>

<p>Self-hosted, or heavily subsidised TaaS, the token cyborg shifts their
infrastructure often. How much of themselves exists in a data lake to be picked
over? As their trust in their tools grow, they expose more of themselves. An
email API key here, a family group chat there. Context is power.</p>

<p>Desires and goals now form as prompts, quick references for the context to fetch
— trust that the intent is evident. An implicit knowledge of models’ pitfalls,
caveats and requirements sprinkled in at the end of requests. Make it efficient,
don’t make mistakes, don’t hallucinate. Make it sound charming.</p>

<p>A WiFi-less flight is to have one’s arms bound.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="ai" /><category term="tokens" /><category term="llms" /><summary type="html"><![CDATA[The token cyborg mediates some or all of their everyday experience through AI models.]]></summary></entry><entry><title type="html">Women in Policing: Health, Justice, and Organisational Culture — A Wee Chat with Dr Dr Mahnoz Illias</title><link href="https://gibsonic.org/blog/2026/02/14/mahnoz_police/" rel="alternate" type="text/html" title="Women in Policing: Health, Justice, and Organisational Culture — A Wee Chat with Dr Dr Mahnoz Illias" /><published>2026-02-14T10:20:08+00:00</published><updated>2026-02-14T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2026/02/14/mahnoz_police</id><content type="html" xml:base="https://gibsonic.org/blog/2026/02/14/mahnoz_police/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2026-01-mahnoz.png" width="1024" /></p>

<p>Dr Dr Mahnoz Illias completed her PhD at the University of Glasgow in 2025. Aye,
she really is a double doctor 😎, originally earning a medical degree in
Bangladesh, before completing an MSc in Global Mental Health at the University
of Glasgow, supported by the Commonwealth Scholarship Commission. Her PhD
research examined policing as a gendered organisation and the impact on the
health and well-being of female police staff and officers in the UK. Here, I had
a wee chat with her about her research and perspectives.</p>

<!--more-->

<hr />

<p><strong>Awright Dr Dr Mahnoz?</strong></p>

<p>Hello there Dr Perry Josef Gee Gibson.</p>

<p><strong>What was your research topic about?</strong></p>

<p>I looked at the gendered toll of policing on the health and well-being of female
police officers in the UK.</p>

<p><strong>Who were you working with for that?</strong></p>

<p>I was working with my supervisors and the wider team that I engaged with. My
primary supervisor was based at the School of Health and Wellbeing at the
University of Glasgow, and my second supervisor was at the Adam Smith Business
School.</p>

<p>It was quite an interdisciplinary project. I was based within these two schools,
but a lot of the work I did was actually closer to the field of criminology
rather than either public health or business/organisation studies.</p>

<p>Outside of the school, I worked closely with the
<a href="https://www.scottishwdf.com/">Scottish Women’s Development Forum</a> of Police
Scotland. They’re a group who represent women within Police Scotland — all the
women staff and officers. It’s a voluntary organisation because, although police
forces keep saying they’re “trying their best to accommodate the welfare of
their employees”, but claim they “do not have the funds” for formal support. So
volunteers step forward to fill the gap. I also worked with broader groups like
the <a href="https://www.sipr.ac.uk/">Scottish Institute for Policing Research</a> and the
Academic Team of Police Scotland.</p>

<p><strong>What was the connection with the Adam Smith Business School; I don’t
immediately see the connection to the research area?</strong></p>

<p>It was mainly about the organisation — the culture, structure, and norms, and
how they impact health and well-being. Although in public health we do study
this (and public health itself is very interdisciplinary), it’s mainly the
people in “organisation studies” who study how organisations are functioning.
They’re located at the business school, so that’s where the Adam Smith Business
School comes into my research journey.</p>

<figure style="max-width: 40%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/4/43/Adam_Smith_The_Muir_portrait.jpg/1280px-Adam_Smith_The_Muir_portrait.jpg" alt="Portrait of Adam Smith" style="width: 100%;" />
  <figcaption>Adam Smith, Scottish "father of economics", for whom the school is named. His book <a href="https://en.wikipedia.org/wiki/The_Wealth_of_Nations">The Wealth of Nations</a> is worth a read if you want to learn about the price of socks made in the Highlands. Via <a href="https://commons.wikimedia.org/wiki/File:Adam_Smith_The_Muir_portrait.jpg">Wikimedia Commons</a></figcaption>
</figure>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"Social support, especially workplace social support, plays a huge role in our lives, which we often overlook."
</blockquote>

<p><strong>You were originally a medical doctor, then you did a
<a href="https://www.gla.ac.uk/postgraduate/taught/globalmentalhealth/">Master’s in Global Mental Health</a>.
How was that perspective shift—looking at mental health not just as an
individual matter, but as a large-scale policy question?</strong></p>

<p>It was different. When we talk about health or mental health, what I’ve found is
that people often think it has to be related to institutional medicine, or
hospitals, or doctors dealing with it. But in our day-to-day life, we can see
how each individual has a health experience that is much less formal. Our eating
choices, our social interactions, our work environment—all of these impact our
health.</p>

<p>We also share a lot of experience from the people around us, which impacts us
both mentally and physically. Acknowledging this in the workplace is important —
in the past, these issues were often presented as individual problems. But I
believe we’re coming to recognise it as a shared responsibility. Every
interaction—including this conversation—happens in a shared space. Both of us
bring our accumulated knowledge and experiences to it.</p>

<p>I also feel that when we talk about health, we normally try to narrow it down to
medical reports or such things, but there is something way beyond that. Health
is not just a medical issue—it’s a social issue, it’s a <em>justice</em> issue. These
things came up again and again in my research.</p>

<p><strong>Taking the perspective that not everything can and should be medicalised?</strong></p>

<p>Yes, when I finished medical school in Bangladesh, my idea about mental health
was quite narrow. When I talked about mental health, I used to think it had to
be something major—schizophrenia, bipolar disorder, or something that needs
regular medication and to be dealt with on a regular basis.</p>

<p>Outside of that, our understanding from our education was that “depression is
there”, and people just have to deal with it until they need medication. What
I’ve come to understand is that mental health isn’t separate from physical
health—they’re intertwined, happening at the same time. It’s not a separate
entity; it’s part of who we are. That means we should be aware of it in our
everyday lives, rather than just in crisis.</p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://i.pinimg.com/736x/71/44/cc/7144cc2524816581585902eef30eb345.jpg" alt="Depression meme" style="width: 100%;" />
  <figcaption>Depression: sometimes it's like that.</figcaption>
</figure>

<p><strong>Was your research focused on Scotland, or did it explore the wider UK?</strong></p>

<p>It was actually throughout the UK. However, as the project received half of its
funding from the
<a href="https://www.sipr.ac.uk/">Scottish Institute for Policing Research</a>—and I’m
grateful to them and <a href="https://www.ukri.org/councils/mrc/">MRC UK</a> for their
support—I had more connection with organisations based in Scotland. But I did a
mixed-method study. I had to analyse two large national cohorts of police
officers, which covered information from all police officers and staff across
the UK—it wasn’t confined to Scotland, and I did not confine my results to
Scotland either.</p>

<p>When I did my primary data collection, most of the participants were from
Scotland—probably two-thirds—and the rest were from across the UK.</p>

<p><strong>In brief, what were the main findings of your thesis?</strong></p>

<p>I would say the main findings were that the health and well-being of female
police officers cannot be understood as a single piece of work. Rather, I would
describe it as a puzzle. By doing research on all these different parts, I got a
closer picture of the entire puzzle, but it’s still not solved. It was more like
a mosaic, with pieces fitting into each other rather than isolated factors—the
social aspect of health working one way, the mental health aspect another way,
the physical aspect there. They’re all intertwined.</p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ef/Gaudi_lizard_%286031486006%29.jpg/1920px-Gaudi_lizard_%286031486006%29.jpg" alt="Gaudí mosaic lizard" style="width: 100%;" />
  <figcaption>The mosaic of problems that women face. Via <a href="https://commons.wikimedia.org/wiki/File:Gaudi_lizard_(6031486006).jpg">Wikimedia Commons</a></figcaption>
</figure>

<p>All of these health and wellbeing issues—stemming from the cultural and
structural issues—often, as I said earlier, we try to describe them as medical
problems. But health is not just a medical problem. It is a justice issue as
well. What facilities you’re getting within your organisation, what you’re given
or not given, can be seen from a justice point of view. At the root of
everything, there is actually organisational injustice, which is controlling how
it impacts overall health.</p>

<p>Lastly, I found that social support, especially workplace social support, plays
a huge role in our lives, which we often overlook.</p>

<p><strong>These seem like interconnected problems. How much can be attributed to being a
woman, versus just “being a polis<sup id="fnref:1"><a href="#fn:1" class="footnote" rel="footnote" role="doc-noteref">1</a></sup> is stressful”?</strong></p>

<p>Every organisation or institution within a society, including families, is a
reflection of the existing society itself. When I was talking to those police
officers, one of my inclusion criteria was they would need to have at least ten
years of experience working as a police officer—to reflect back on how the
culture changed over time, how policies changed, how that impacted them.</p>

<p>All of them came into policing knowing there would be a certain level of
operational stress. They knew what policing was—definitely there were some
surprises like every other job, but gradually in day-to-day life, the relational
aspects became more prominent.</p>

<p>There’s a scholar with a famous theory called “Gendered Organisations”—her name
is <a href="https://en.wikipedia.org/wiki/Joan_Acker">Joan Acker</a>. She explains it very
nicely. She says that a “job” itself is an abstract idea; for its embodiment,
you need a <em>person</em> to be there.</p>

<p>And that person, when they enter the role, they bring all of their gendered
ideas about women with them—what they learned throughout their life about the
limitations of women, what they can do, what they cannot do. They came with
their perceptions and kept spreading those ideas. As society has changed, those
ideas have also changed. But still, though we keep saying that men and women are
equal in our society, that’s not quite the case. Policing remains a gendered
organisation, and this has real impacts on the health and well-being of female
police staff and officers.</p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"Health is not just a medical issue—it's a social issue, it's a justice issue."
</blockquote>

<p><strong>Is it your impression that police in the UK have more of a “boys’ club”
problem than other places? Or is it more in-line with the issues in wider
society?</strong></p>

<p>They definitely had their own boys’ club issues. They had cultures where women
wouldn’t be invited to the informal parties or after-work gatherings, or they’d
always assume that if you have children, you must need childcare.</p>

<p><strong>Are there any articles folk could check out if they were interested?</strong></p>

<p>I have two articles out so far, and two others are under review.</p>

<p>My meta-ethnographic review, which looked at the interplay between
organisational injustice and the health and well-being of female police officers
and staff across the globe, was published in BMC Public Health [1].</p>

<p>Another piece of work compared the impact of workplace social support on the
mental health of parents, both men and women, published in the journal
“Policing” [2].</p>

<p><em>[1] M. Illias, K. Riach, and E. Demou, ‘Understanding the interplay between
organisational injustice and the health and wellbeing of female police officers:
a meta-ethnography’, BMC Public Health, vol. 24, Sep. 2024, doi:
<a href="https://pubmed.ncbi.nlm.nih.gov/39342226/">10.1186/s12889-024-20152-1</a>.</em></p>

<p><em>[2] M. Illias et al., ‘Exploring gender differences in policing: the role of
workplace social support on the mental health and wellbeing of parents in
policing’, Policing, vol. 19, Jan. 2025, doi:
<a href="https://academic.oup.com/policing/article/doi/10.1093/police/paaf037/8316114?login=false">10.1093/police/paaf037</a>.</em></p>

<p><strong>Were there any technical tools in your work that you were using, and any
frustrations with them?</strong></p>

<p>Definitely. One of the datasets I was using was the
“<a href="https://police-health.org.uk/">Airwave Health Monitoring Study</a>”. Since it was
quite sensitive, to access that data, I had to get access to a “safe haven”, or
what they formally call a <em>Trusted Research Environment</em>. The operators had
maintenance windows (thus, I couldn’t always access it when I needed to), and
sometimes because it’s a big dataset hosted somewhere else, there were technical
issues. Many days I was frustrated because you’re in the mood to analyse and
then you cannot access the data.</p>

<p>When I began my PhD, I didn’t know how to code in
<a href="https://en.wikipedia.org/wiki/R_(programming_language)">R</a> (a programming
language for statistical analysis), but I needed to for its flexibility and the
amount of data analysis I had to perform. Learning that was also a challenge. I
used to freeze at the thought of having to engage in coding work—the word
“coding” was very frightening. But after my analysis of the first database, I
got quite confident, and it didn’t take me much time to do my second analysis.</p>

<figure style="max-width: 80%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/e/ed/RStudio_IDE_screenshot.png/1920px-RStudio_IDE_screenshot.png" alt="RStudio IDE screenshot" style="width: 100%;" />
  <figcaption>The RStudio IDE — a good system, but I cannae get behind 1-based indices. Via <a href="https://commons.wikimedia.org/wiki/File:RStudio_IDE_screenshot.png">Wikimedia Commons</a></figcaption>
</figure>

<p><strong>Do you think you would have benefited from having access to more technical
support?</strong></p>

<p>I had people in my unit who I could reach out to, but in a PhD you can’t control
which part of work you’re going to do at what time of day. If it was a friend, I
could reach out anytime. But if it’s a colleague, it’s a formal relationship. As
a new person within the unit, I was also hesitant to reach out to them. Whenever
I had issues, I could reach out to people, but these were colleagues who had
volunteered to help me—there weren’t any designated people you could always go
to. Having someone like that would have definitely benefited me or people like
me who have just started coding.</p>

<p><strong>What was your experience navigating the research space in the UK as a
Bangladeshi woman?</strong></p>

<p>I didn’t face any issues particularly from a gender perspective. But compared to
my MSc, I felt a bit isolated. I don’t know whether that was the nature of the
PhD, or something was wrong with me, or I wasn’t ready—it was just after COVID
as well, so people were quite isolated at that time. Maybe all those factors
worked together.</p>

<p>I was still hanging out with my old friends outside that space, but compared to
that, I did not have that many close friends within my own department. They were
very lovely people, very cooperative, but somehow I didn’t have that connection
with them.</p>

<p>But there was another space—the Scottish Institute for Policing Research—where I
met a lot of people from different fields: criminology, cybersecurity, forensic
backgrounds. I made good friends with them. I don’t know what the reason was
behind this, but that’s how it was.</p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"Coming from Bangladesh, I expected the UK to be a 'utopia'... But when I looked beyond the surface, it was very shocking."
</blockquote>

<p><strong>For any organisation in general—you’ve looked a lot into organisational
structures. Is there any general advice you’d give to leaders or individuals
about how to help manage the issues you’ve seen in your work?</strong></p>

<p>One of the things was that Police Scotland is a single force, but in England
they have around 43 forces. Across different stations or forces, they each were
tackling different issues well, and others less well. But those were ad hoc
initiatives, with success stories not being shared with each other.</p>

<p>I know there’s decentralisation of policing and those ideas in criminology, and
there are certain reasons for that. But I felt they should have a common
platform where they can share positive initiatives that are actually helping
people deal with the issues they face in their day-to-day life.</p>

<p>If they can find a way to share those and adopt the effective programmes that
are working for people, that would be really beneficial for the entire
organisation or the entire police force across the UK.</p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/thumb/c/c5/United_Kingdom_police_areas_map.svg/960px-United_Kingdom_police_areas_map.svg.png" alt="Map of UK police areas" style="width: 100%;" />
  <figcaption>Police areas of the United Kingdom. <a href="https://commons.wikimedia.org/wiki/File:United_Kingdom_police_areas_map.svg">CC BY-SA 3.0</a></figcaption>
</figure>

<p><strong>You mentioned the PhD ended up being more about criminology. Could you briefly
explain what you meant by that?</strong></p>

<p>I would say it’s criminology because every time I was going to conferences and
knowledge exchange programmes, I was mostly interacting with people from
criminology or forensic psychology backgrounds. They’re the ones coming to work
on what’s happening with policing, how policing can be better, rather than
someone from a health background.</p>

<p>In that sense, I didn’t have much in common with other people in terms of
background. But they were very welcoming, so it wasn’t an issue.</p>

<p>Also, a major portion of writing up my final thesis involved understanding the
policing structure within the UK—what policies are out there, under what law
police organisations in the UK came into being. Those are things more from
criminology rather than my health perspective. They were new ideas for me.</p>

<p><strong>Anything else you want to highlight?</strong></p>

<p>Another interesting finding: when I started my project, I was initially
expecting the focus to be about physical health. Many police officers are
exposed to more danger than a typical office job, and if we’re talking about
women—our physiology is generally different from men, and this has some impact
on our musculoskeletal health. Perhaps my research would take me into questions
around musculoskeletal problems they’re facing, and how the workplace could
change to support that.</p>

<p>However, when I started to look into it, what came up more consistently was
<em>mental health</em> issues. I was very surprised that no matter which part of the
world the articles I was researching were coming from, they had similar issues:
regardless of the culture—whether it was from the Global South or Global North.
It was surprising for me because, coming from Bangladesh, I expected the UK to
be a “utopia” where everything was perfect, or at least significantly better,
women would be getting their rights properly, they didn’t have to fight for it,
they were living their lives very comfortably.</p>

<p>But when I looked beyond the surface, it was very shocking and frustrating for
me to deal with those accounts on a daily basis, and that these issues exist in
the UK as much as they do in other parts of the world. It also helped me realise
how seemingly gender-neutral policies are not as neutral as they seem.</p>

<p><strong>Thank you Dr Dr Mahnoz</strong></p>

<p>Thank you Dr Perry Josef Gee Gibson.</p>

<div class="footnotes" role="doc-endnotes">
  <ol>
    <li id="fn:1">
      <p>“Polis” is a Scots term for police. <a href="#fnref:1" class="reversefootnote" role="doc-backlink">&#8617;</a></p>
    </li>
  </ol>
</div>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="police" /><category term="interviews" /><category term="mental-health" /><summary type="html"><![CDATA[Dr Dr Mahnoz Illias completed her PhD at the University of Glasgow in 2025. Aye, she really is a double doctor 😎, originally earning a medical degree in Bangladesh, before completing an MSc in Global Mental Health at the University of Glasgow, supported by the Commonwealth Scholarship Commission. Her PhD research examined policing as a gendered organisation and the impact on the health and well-being of female police staff and officers in the UK. Here, I had a wee chat with her about her research and perspectives.]]></summary></entry><entry><title type="html">Invited talk at CODAI, HiPEAC 2026</title><link href="https://gibsonic.org/blog/2026/02/08/hipeac_codai_talk/" rel="alternate" type="text/html" title="Invited talk at CODAI, HiPEAC 2026" /><published>2026-02-08T10:20:08+00:00</published><updated>2026-02-08T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2026/02/08/hipeac_codai_talk</id><content type="html" xml:base="https://gibsonic.org/blog/2026/02/08/hipeac_codai_talk/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2026-02-hipeac.png" width="1024" /></p>

<p>I was delighted to be invited to both give a talk, and participate in the panel
discussion at the <a href="https://www.codai-workshop.com/home">CODAI workshop</a>
(Workshop on Compilers, Deployment, and Tooling for AI) at HiPEAC 2026 (Kraków,
Poland).</p>

<p>My talk, titled “The Compiler Before the Horse: Design Space Exploration at
Fractile,” focused on how investing in compiler development early in our
hardware design process has been essential for effective design space
exploration and for making well-informed architectural decisions.</p>

<!--more-->

<p>The stream was recorded, and is available from the
<a href="https://www.codai-workshop.com/2026-recording">CODAI website</a>.</p>

<p>I tried to keep the tone light, and may have overdone it with my extended
metaphor. Beating a dead horse, if you will.</p>

<p>In an age of easy, high-quality generative images, I had some fun old-school
editing together my own images.</p>

<figure style="width:66%; margin: 1em auto; text-align: center;">
  <img src="https://gibsonic.org/assets/pics/2026-01-one_trick_pony.png" alt="Not a one trick pony" style="width:100%; height:auto;" />
  <figcaption>not a one trick pony!</figcaption>
</figure>

<p>The first part of the talk mirrored a lot of the themes in my <a href="/blog/2025/03/03/c4ml_vegas/">C4ML talk in
Vegas</a> in 2025, namely that we found a lot
of success developing quick and dirty prototypes of the compiler using the MLIR
Python bindings. We even got an end-to-end compilation and functional simulation
of Llama2-7B, which was a great validation of our team, our design, and our
high-level architecture.</p>

<p>I then discussed how the organisation has changed, and how as we approach
tape-out, we have been nailing down the minutiae of our programming model, and
how that interacts with our architecture.</p>

<p>The message I was trying to sell was that the compiler team, and staff at
Fractile in general, have been empowered to make functional software early, to
better understand the shape of our design space, and use that to inform our
conversations with architects.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="talks" /><category term="compilers" /><category term="hipeac" /><summary type="html"><![CDATA[I was delighted to be invited to both give a talk, and participate in the panel discussion at the CODAI workshop (Workshop on Compilers, Deployment, and Tooling for AI) at HiPEAC 2026 (Kraków, Poland). My talk, titled “The Compiler Before the Horse: Design Space Exploration at Fractile,” focused on how investing in compiler development early in our hardware design process has been essential for effective design space exploration and for making well-informed architectural decisions.]]></summary></entry><entry><title type="html">You Can Do It Too: Inside Scotland’s Post-Punk Press with Glenn Gibson</title><link href="https://gibsonic.org/blog/2026/02/03/post_punk_press_glenn_gibson/" rel="alternate" type="text/html" title="You Can Do It Too: Inside Scotland’s Post-Punk Press with Glenn Gibson" /><published>2026-02-03T10:20:08+00:00</published><updated>2026-02-03T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2026/02/03/post_punk_press_glenn_gibson</id><content type="html" xml:base="https://gibsonic.org/blog/2026/02/03/post_punk_press_glenn_gibson/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2026-02-glenn.png" width="1024" /></p>

<p>In this post, I chat with a former New Musical Express (NME) writer Glenn Gibson
(aka, my da) about his experiences breaking into music journalism in the
1970s-80s, the evolution of music publications, the development of Scotland’s
music scene during the punk and post-punk era, and various other bits and
pieces.</p>

<!--more-->

<hr />

<p><strong>You’ve got interesting stories about the music industry—I thought it’d be good
to capture some of them. How did you get into music writing?</strong></p>

<p><em>It was the New Musical Express, which was well-established when I started.</em>
<em>It’s a music paper dating back to the 50s, and they were credited with
originating the UK pop charts. But it was very much tied</em> <em>into the music
business. They just had pop stuff and so forth. And at some</em> <em>point, during the
early 1970s, they got a new editor who totally</em> <em>revamped it.</em></p>

<p><em>Starting in the 60s there was the underground press which was usually
independent. And the NME started employing people who wrote for those
publications.</em></p>

<p><strong>So rather than just being a mouthpiece for what was coming out from the big
labels, it was able to give space for some more up-and-coming and challenging
artists?</strong></p>

<p><em>Yes, rather than just covering what was in the charts. With the counterculture
and all of the post-war developments, music was developing fast.</em></p>

<p><em>It went from rock and roll, to the Beatles, and the beat boom, and moved on to
prog rock, glam rock, and punk. Around 1976/77 they wanted music publications
that would reflect that — written by people who were close to the movement, who
were really part of that.</em></p>

<p><em>They were probably copying what was happening in America because in the 60s,
Rolling Stone magazine started. Rolling Stone is now well-established, I believe
it’s quite a corporate thing now. But it started as a counterculture underground
thing.</em></p>

<p><strong>They employed the likes of Hunter S. Thompson for articles?</strong></p>

<p><em>Yes, some real mavericks. One person they employed was Cameron Crowe, who went
on to become a film director. A film he wrote, ‘Almost Famous,’ was
semi-autobiographical.</em></p>

<p><strong>Auch aye, I think we watched that together a few years back.</strong></p>

<figure style="max-width: 30%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/en/d/dd/Almost_famous_poster1.jpg" alt="Almost Famous film poster" style="width: 100%;" />
  <figcaption>Almost Famous (2000), written/directed by Cameron Crowe. Via <a href="https://en.wikipedia.org/wiki/File:Almost_famous_poster1.jpg">Wikipedia</a></figcaption>
</figure>

<p><em>He was just somebody who was a big music fan. He sent them articles he’d
written, and they liked them. I don’t think they found out until later that he
was 15. They were sending him off to interview big-time stars and he became
really successful. “Almost Famous” is arguably one of the best music business
films ever made. I would say that and
“<a href="https://en.wikipedia.org/wiki/24_Hour_Party_People">24 Hour Party People</a>”
(2002).</em></p>

<p><em>And Cameron Crowe has actually just published his autobiography,
<a href="https://www.goodreads.com/book/show/224004354-the-uncool">“The Uncool” (2025)</a>,
because part of “Almost Famous” was that he was never cool.</em></p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"That's when I started getting published—and paid."
</blockquote>

<p><em>Anyway, that’s the kind of thing that the NME were trying to copy, and it
worked. They got a big audience and it became very cool, internationally as
well. It was very well liked in America too. They seemed open to taking on
people from around the country, so I went to see Ivor Cutler, the Scottish
humorist, singer, songwriter, and poet, and I wrote something about it and sent
it to them. They published it.</em></p>

<p><strong>Oh, crackin’</strong></p>

<figure style="max-width: 30%; margin: 0 auto 1.5em;">
  <div style="overflow: hidden;">
    <img src="https://upload.wikimedia.org/wikipedia/commons/4/4d/Ivor_Cutler_1973.jpg" alt="Ivor Cutler in 1973" style="width: 100%; margin-top: -25%;" />
  </div>
  <figcaption>Ivor Cutler in 1973, photo by Alan Messer. <a href="https://commons.wikimedia.org/wiki/File:Ivor_Cutler_1973.jpg">CC BY-SA 3.0</a></figcaption>
</figure>

<p><em>They came back and said “would you like to do more?” I sent them quite a few
things, and they didn’t publish any of them. But then the person in charge of
the live review section changed and a new guy came in and he said, “Don’t do
that anymore. What you should do is phone me every week and say what’s coming up
and we will then commission you to write things.” That’s when I started getting
published — and paid.</em></p>

<p><em>That being said, I still had a day job as well. Looking back, I don’t know how
I managed it.</em></p>

<p><strong>I guess not having weans helps.</strong></p>

<p><em>I think the extreme would be working all day and then going to Edinburgh and
not getting back home from Edinburgh until five in the morning. And then getting
up to go to work. Out constantly at gigs and interviews, and also needing the
time to write up.</em></p>

<p><strong>Aye, I can imagine that took a good chunk of time. Did the acts you were sent
to cover align with your tastes, or were you seeing a load of pish? Once they
started commissioning, were they picking what you covered, or did you still have
a say?</strong></p>

<p><em>Well, a mixture, because I wasn’t doing exclusively what was happening in
Scotland. I was being sent to review other bands who were touring who could be
American, but as well as covering what was happening in Scotland because what
was happening in Scotland was developing, and gaining national attention.</em></p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"One thing punk did was give people the message: 'you can do it too.'"
</blockquote>

<p><strong>Starting to develop its own scene?</strong></p>

<p><em>Yes. Simple Minds were one of the first ones. I went to see them playing in
bars. I think they had already signed a contract with a record company at this
point, so they were starting to move beyond that, but there were a lot of other
ones coming up behind them.</em></p>

<p><strong>There are probably quite a lot of bands that folk would be surprised to hear
came out of the Scottish scene because the accent or dialect doesn’t necessarily
come across.</strong></p>

<p><em>Well, the music business was always very centred in London. This was after
punk. One thing punk did was give people the message: “you can do it too.” And
what they were playing was relatively simple. That simplicity had origins in
early rock and roll. The British beat groups of the 1960s were actually quite
‘punk’ in their way—like The Who, The Animals, and Them. With “Them”, the singer
was Van Morrison who is still very successful.</em></p>

<p><em>It was fairly simple, thus it’s something that people who were just teaching
themselves how to play guitar or bass or drums could play. It was a reaction to
progressive rock, which can be very complicated and long and was all about
musicianship. That was a backlash against that. The impact of it was quite
startling.</em></p>

<p><strong>I guess there was starting to be more access to recording and distribution
equipment during that time?</strong></p>

<p><em>There were local recording studios, but access to recording didn’t change much
during that period. With computers and software it became much easier to record
from home, but you couldn’t do that then really, unless you bought quite
expensive tape recorders, which could still be quite primitive. So bands would
go to record in small Scottish studios. But it could still cost a lot of money.
Some of them would be around £600 a day.</em></p>

<p><strong>Auch, geezo, and I guess that’s £600 then as well.</strong></p>

<p><em>For people without much money, that was a lot. And the Scottish bands who were
playing in bars would be paid very little. I think in some cases they’d get like
£10 and there might be four or five people in the band, and they had to hire a
van to get there which might cost them about £70 — so they were making a loss.</em>
<em>But they were just trying to get their own music out there.</em></p>

<p><em>It was an interesting dynamic but that message about “you can do it too” was
quite widespread. And more than just music. For instance, my friend Martin
Millar was very influenced by that ethos to become a writer. Actors, writers,
people across the creative arts—a lot of people were influenced by that, and
still are today.</em></p>

<figure style="max-width: 30%; margin: 0 auto 1.5em;">
  <img src="https://covers.openlibrary.org/b/id/8779561-L.jpg" alt="Lonely Werewolf Girl book cover" style="width: 100%;" />
  <figcaption>Lonely Werewolf Girl by Martin Millar. Via <a href="https://openlibrary.org/works/OL20126859W/Lonely_Werewolf_Girl">Open Library</a></figcaption>
</figure>

<p><em>I got to do [the writing] for a number of years and earned a reasonable
amount of money and got to travel around and meet a lot of people. And with
various different publications, I probably did it for about 11 years. Although
you got some money, it was difficult to actually make a living.</em></p>

<p><strong>Because it was quite sporadic?</strong></p>

<p><em>Yeah, it was unreliable, I was just a freelance person who was also working a
day job. There were some people who did the writing exclusively. However, they
were probably getting unemployment benefits and things like that, or there might
have been some other small local things that they did. There were a couple of
people who went on to write for the local newspapers, doing the pop column.</em></p>

<p><strong>Which is a bit more of a reliable income.</strong></p>

<p><em>Yes, <a href="https://www.thetimes.com/profile/john-dingwall">John Dingwall</a>, for
instance, he started off with a fanzine and then wrote for Record Mirror.</em></p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="/assets/pics/2026-02-stand_and_deliver.jpg" alt="Stand and Deliver fanzine cover" style="width: 100%;" />
  <figcaption>Stand and Deliver, John Dingwall's fanzine</figcaption>
</figure>

<p><em>When he was just doing Record Mirror he probably wasn’t getting that much, but
he went on to work for the Evening Times and Daily Record and he did that for a
long time, and has been a core part of Scottish journalism since.</em></p>

<p><em>Making money from journalism at that time, even if you were employed by a
Scottish newspaper which was predominantly sold in Scotland, you were paid quite
well. The circulation of newspapers today has plummeted since then.</em></p>

<p><strong>Aye, the issues that face the entire journalism industry today is a whole
fraught topic unto itself.</strong></p>

<p><em>I do know some people who moved to London and maybe had a bit of success. But
they weren’t getting paid that much just working for music papers, or smaller
music magazines, they were very often living in cheap accommodation: squats,
somebody’s spare room, or flats with only cold water and broken windows.</em></p>

<p><strong>I guess in a sense that’s quite punk. You’re getting an appreciation of your
source material.</strong></p>

<p><em>Right, the other side of that, is that the several people I can think of that
did that, they all died quite young. In their early 60s and some even younger.</em></p>

<blockquote style="border-left: 4px solid #c00; margin: 1.5em 0; padding: 0.5em 1em; font-size: 1.15em; font-style: italic; background: #f9f9f9;">
"They'd get like £10 and there might be four or five people in the band, and they had to hire a van which might cost them about £70—so they were making a loss."
</blockquote>

<p><strong>Is that what a lifetime of substandard heating will do to ye?</strong></p>

<p><em>Yeah, and maybe not being able to feed themselves properly as well. It might be
a coincidence.</em></p>

<p><strong>People say the body keeps score.</strong></p>

<p><em>Yes, I obviously have nothing definite about it but you know, it happened to
one photographer I worked with. He moved to London and got a job working for
“Sounds” which was quite a good magazine. Quite well regarded. And I think after
that, he even got a job working for Marvel.</em></p>

<p><em>I used to go and stay with him sometimes in London, but I kind of lost track
after a while. Anyway, he got a brain aneurysm. He came back to Scotland a
number of years ago and I think he’s in a care home.</em></p>

<p><em>The singer from the Bluebells, Ken McCluskey, who we knew, discovered that this
guy Harry Papadopoulos was back in Scotland. And the reason Ken found out about
it, was because Harry’s brother was an electrician or a tradesman of some kind
and went and did a job in his house. The subject must have come up. Ken went to
visit him, and they managed to get a hold of his old negatives. They’ve been on
display in several art galleries and so forth. And there was a book published.</em></p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://covers.openlibrary.org/b/id/14693456-L.jpg" alt="What Presence! book cover" style="width: 100%;" />
  <figcaption>What Presence!: The Rock Photography of Harry Papadopoulos. Via <a href="https://openlibrary.org/works/OL35700027W/What_Presence!">Open Library</a></figcaption>
</figure>

<p><strong>There was the
“<a href="https://www.nms.ac.uk/past-exhibitions/rip-it-up-the-story-of-scottish-pop">Rip It Up: The Story of Scottish Pop</a>”
exhibition at the National Museum of Scotland in 2018, where there were a couple
of things you contributed.</strong></p>

<p><em>I never really collected a lot of memorabilia, but there were some things I
had. Part of the reason for it is that a lot of people in the past have been
asked to lend things of that type and never got them back. So a lot of people
who were asked to lend things would say “nah, not doing that”. But with the
National Museum of Scotland they were known for being quite reliable, and you
did get everything back. So it ended up being quite extensive, and showing off a
lot of items never seen before.</em></p>

<p><strong>Speaking of Scottish pop history being museum-worthy, what place do you think
this sort of thing should have in our collective consciousness?</strong></p>

<p><em>Occasionally in YouGov questionnaires they’ll ask things like “What does
Britain do best?” I’m not saying things like industrial products—I’d say music,
comedy, acting, writing, and the arts in general. And it’s hard to think of
things that Britain does better than those kinds of things.</em></p>

<p><strong>Aye, a lump of steel is more-or-less the same wherever it’s from. But music,
comedy—that’s a product of the people and the culture. You can’t get that
anywhere else.</strong></p>

<p><em>For a very long time pop and rock music that was listened to internationally
was almost exclusively from Britain and America. And that has been changing.
There were certain countries, like Germany, that became quite successful, or at
least critically recognised for what they were doing.</em></p>

<p><strong>Aye, they weren’t playing Kraftwerk on Clyde One initially.</strong></p>

<p><em>No. But there were a lot of other things coming out of Germany at that time,
but it probably remained quite underground, or a niche interest. That’s
continued—music from other countries gaining recognition in the UK. And now that
you have K-pop and J-pop, these are massively successful.</em></p>

<p><strong>Aye, it’s good to see that things are getting a bit more nuanced than just the
catch-all term of “World Music”.</strong></p>

<p><em>Yes, there were phases—African music was a thing for a while, and reggae
especially — Jamaica was close to America which may have helped with discovery
and distribution. It very much had its own sound, developing over the years from
ska to blue beat to reggae, and they had their own version of rap quite early
on.</em></p>

<p><strong>Aye, and you see how dub influenced music worldwide. I’ve been noticing
Afro-house having a similar reach lately.</strong></p>

<p><em>Africa has so many different countries with their own traditions and own
styles, but certainly around that time they would have had a lot of influence
from what was coming out of Britain and America.</em></p>

<p><strong>I suppose folk in Britain and America had a lot more access to the mass
production and distribution required to get their music heard internationally.</strong></p>

<p><em>A lot of these things are very popular in their own country and only certain
ones break through internationally. There are certainly people that can help
give it a boost. Paul Simon recorded an album with African musicians in the
“Graceland” album a number of years ago. And he got a lot of criticism because
South Africa had apartheid going on and there were supposed to be cultural
boycotts.</em></p>

<figure style="max-width: 50%; margin: 0 auto 1.5em;">
  <img src="https://upload.wikimedia.org/wikipedia/commons/c/c3/Graceland_cover_-_Paul_Simon.jpg" alt="Graceland album cover by Paul Simon" style="width: 100%;" />
  <figcaption>Graceland by Paul Simon. Via <a href="https://commons.wikimedia.org/wiki/File:Graceland_cover_-_Paul_Simon.jpg">Wikimedia Commons</a></figcaption>
</figure>

<p><em>However, I think his point was more that “this is the cultural bit and we’re
actually paying people quite a lot more than the going rate”; and some of them
got successful careers out of it internationally.</em></p>

<p><strong>I wonder how many of those musicians were hitting oot with ‘I love apartheid,
now here’s Wonderwall.’ Probably not fans of the regime themselves.</strong></p>

<p><em>Most of the South African musicians involved were Black artists who had lived
under apartheid and whose careers were constrained by it — but I think the
boycott of South Africa was for the whole country. Therefore, even if you were
working with people who were victims of it, it was still frowned upon in many
ways. That being said, I think Paul Simon was quite a tough guy with a lot of
self-belief, so he just did it anyway.</em></p>

<p><strong>This was all well before my time, did it seem like the boycott was a
significant part of how the apartheid came to an end?</strong></p>

<p><em>Probably yes, but there are lots of factors beyond that.</em></p>

<p><strong>Well, thanks for this chat—there are plenty of other threads we could pull on.
The Virgin Megastores opening, people you’ve met over the years. Whenever a
random track comes up you seem to have an anecdote ready.</strong></p>

<p><em>I think for certain things I have quite a good memory. There’s this common
thing that for some people, there’s certain types of music that they liked when
they were in their late teens and that’s what they like forever. Whereas I’ve
always wanted to find new things; and there are some people like that, but I
think that’s the minority because you have to put some effort into it, and you
do have to be interested. And if you’re interested enough you will remember
these things.</em></p>

<p><strong>I think to this day you’re my main source of interesting new music. I find
stuff on my own, but it’s more through happenstance than actively seeking it
out.</strong></p>

<p><em>I think if you’re interested in music quite a lot, it ties in with so many
other things. That would lead you into particular types of books or films or
art. It’s all tied together.</em></p>

<p><strong>Cheers da!</strong></p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="music" /><category term="interviews" /><summary type="html"><![CDATA[In this post, I chat with a former New Musical Express (NME) writer Glenn Gibson (aka, my da) about his experiences breaking into music journalism in the 1970s-80s, the evolution of music publications, the development of Scotland’s music scene during the punk and post-punk era, and various other bits and pieces.]]></summary></entry><entry><title type="html">Invited talk at Alces Flight 2025</title><link href="https://gibsonic.org/blog/2025/10/31/alces_flight/" rel="alternate" type="text/html" title="Invited talk at Alces Flight 2025" /><published>2025-10-31T10:20:08+00:00</published><updated>2025-10-31T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/31/alces_flight</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/31/alces_flight/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-alces-flight.png" width="1024" /></p>

<p>I was honoured to be invited to give a talk at the
<a href="https://alces.network/flight-2025/">Alces Flight 2025</a> conference, which took
place in London, UK, in October 2025.</p>

<p>My talk discussed how interdisciplinary collaboration and playfulness can be
powerful tools, especially for early-career researchers and engineers.</p>

<p>I shared some of my experiences from my PhD and industry work.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="talks" /><category term="compilers" /><category term="dse" /><summary type="html"><![CDATA[I was honoured to be invited to give a talk at the Alces Flight 2025 conference, which took place in London, UK, in October 2025. My talk discussed how interdisciplinary collaboration and playfulness can be powerful tools, especially for early-career researchers and engineers. I shared some of my experiences from my PhD and industry work.]]></summary></entry><entry><title type="html">How We Survived Mac and Even Laughed</title><link href="https://gibsonic.org/blog/2025/10/12/macbook_setup/" rel="alternate" type="text/html" title="How We Survived Mac and Even Laughed" /><published>2025-10-12T10:20:08+00:00</published><updated>2025-10-12T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/12/macbook_setup</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/12/macbook_setup/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-mac.png" width="1024" /></p>

<p>At work, we recently transitioned everyone to MacBooks. I’ve never used one
before, and had spent the past decade on Linux laptops which I’ve gradually
refined to my liking.</p>

<p>Here’s an inconvenient truth — these machines are not designed to meet my
needs. Being able to modify them to meet those needs has been a challenge. In an
attempt to not alienate my readers, this doesn’t mean that folk with other needs
are wrong. Apple clearly has a particular set of users in mind; I’m just not one
of them.</p>

<p>My philosophy is that the tools I use should behave the way I tell them to. This
post describes some of the issues I’ve encountered trying to achieve that, and
how I’ve worked around them. Overall, I’ve been able to get a workable setup.</p>

<!--more-->

<h1 id="windows-and-workspace-management">Windows and Workspace Management</h1>

<p>One of the most important aspects of my workflow is the ability to manage
windows and workspaces efficiently.</p>

<p>I typically have 10 workspaces, with a relatively strict purpose for each one,
and map each to a keyboard shortcut, usually <code class="language-plaintext highlighter-rouge">super+[0-9]</code>. That way I can
quickly switch between different tasks and contexts (e.g., text editor is in
<code class="language-plaintext highlighter-rouge">super+1</code>, email in <code class="language-plaintext highlighter-rouge">super+9</code>, etc). I can also move windows between workspaces
using <code class="language-plaintext highlighter-rouge">super+shift+[0-9]</code>.</p>

<p>macOS has a concept of ‘Spaces’, which are virtual desktops, but the behaviour I
required of sending windows to specific spaces and switching between them with
keyboard shortcuts wasn’t available out of the box. I had to install a
third-party window manager called <a href="https://github.com/koekeishiya/yabai">yabai</a>.</p>

<p>Yabai is a tiling window manager, which means that it automatically arranges
windows in a grid-like layout. This isn’t something I’ve bothered with before,
but I’ve gotten used to it, and I’ve ended up liking it. I’ve even enabled
tiling windows on my Debian laptop, through KDE Plasma. It also helps to deal
with the limited memory of the MacBook, since it pushes me to not have too many
windows open at once.</p>

<p>Alas, Yabai and some other tools had some issues when the macOS Tahoe update
came out in September 2025. This initially broke my setup, and made me feel like
there was a small-calibre bullet in my skull, as it made everything much harder
to use. Some patches have been released since then, and things are mostly
working now.</p>

<p>Example Yabai configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c">#!/bin/bash</span>

<span class="c"># Re-inject scripting addition if Dock restarts</span>
yabai <span class="nt">-m</span> signal <span class="nt">--add</span> <span class="nv">event</span><span class="o">=</span>dock_did_restart <span class="nv">action</span><span class="o">=</span><span class="s2">"sudo yabai --load-sa"</span>
<span class="nb">sudo </span>yabai <span class="nt">--load-sa</span>

<span class="c"># Update workspace number in SketchyBar</span>
yabai <span class="nt">-m</span> signal <span class="nt">--add</span> <span class="nv">event</span><span class="o">=</span>space_changed <span class="nv">action</span><span class="o">=</span><span class="s2">"</span><span class="nv">$HOME</span><span class="s2">/.config/sketchybar/plugins/space_display.sh"</span>

<span class="c"># Set default layout to tiling (bsp)</span>
yabai <span class="nt">-m</span> config layout bsp

<span class="c"># Window padding and gap between tiles</span>
yabai <span class="nt">-m</span> config top_padding         0
yabai <span class="nt">-m</span> config bottom_padding      0
yabai <span class="nt">-m</span> config left_padding        0
yabai <span class="nt">-m</span> config right_padding       0
yabai <span class="nt">-m</span> config window_gap          0

<span class="c"># Focus behavior</span>
yabai <span class="nt">-m</span> config mouse_follows_focus on
yabai <span class="nt">-m</span> config focus_follows_mouse autofocus

<span class="c"># Automatically rebalance split tree when windows are closed</span>
yabai <span class="nt">-m</span> config auto_balance on

<span class="c"># Warp new windows into the tree (default tiling behavior)</span>
yabai <span class="nt">-m</span> config window_placement second_child

<span class="c"># Enable window shadows and blur for floating windows (optional)</span>
yabai <span class="nt">-m</span> config window_shadow on

<span class="c"># Make full-screen toggle (green button) act like regular zoom</span>
yabai <span class="nt">-m</span> config window_opacity off

<span class="c"># Optional: float certain system apps (you can add more)</span>
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"System Preferences"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"System Settings"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"Software Update"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">app</span><span class="o">=</span><span class="s2">"App Store"</span> <span class="nv">manage</span><span class="o">=</span>off
yabai <span class="nt">-m</span> rule <span class="nt">--add</span> <span class="nv">title</span><span class="o">=</span><span class="s2">"Preferences"</span> <span class="nv">manage</span><span class="o">=</span>off

<span class="c"># Optional: make the Dock not steal space if it's visible</span>
yabai <span class="nt">-m</span> config window_shadow               off
yabai <span class="nt">-m</span> config window_opacity              off
</code></pre></div></div>

<p>You may wish to add spacing between windows, but I prefer to have none.</p>

<h2 id="keyboard-shortcuts">Keyboard shortcuts</h2>

<p>I used <a href="https://github.com/koekeishiya/skhd">skhd</a> to manage the keyboard
shortcuts for Yabai.</p>

<p>For example,</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>ctrl - 1 : yabai <span class="nt">-m</span> space <span class="nt">--focus</span> 1

ctrl - m : yabai <span class="nt">-m</span> window <span class="nt">--toggle</span> zoom-parent
ctrl + <span class="nb">shift</span> - c : yabai <span class="nt">-m</span> window <span class="nt">--close</span>

ctrl + <span class="nb">shift</span> - 1 : yabai <span class="nt">-m</span> window <span class="nt">--space</span> 1
</code></pre></div></div>

<p>I became frustrated with additional Mac keyboard issues and made further
changes.</p>

<h1 id="the-keyboard">The Keyboard</h1>

<p>The Mac keyboard is a bit different from a standard PC keyboard. And the keycaps
are labelled differently. That layout doesn’t fit my needs, so I’ve had to make
some changes.</p>

<p>First thing I did was remap the modifier keys in System Settings -&gt; Keyboard -&gt;
Modifier Keys. I set <code class="language-plaintext highlighter-rouge">Caps Lock</code> to <code class="language-plaintext highlighter-rouge">Command</code> (to avoid
<a href="https://news.ycombinator.com/item?id=14370017">Emacs pinky</a>), and <code class="language-plaintext highlighter-rouge">Command</code> to
<code class="language-plaintext highlighter-rouge">Option</code> (aka <code class="language-plaintext highlighter-rouge">Alt</code>). And the <code class="language-plaintext highlighter-rouge">Option</code> to <code class="language-plaintext highlighter-rouge">Control</code> (aka the <code class="language-plaintext highlighter-rouge">Super</code> key). You
may want to swap the <code class="language-plaintext highlighter-rouge">Command</code> and <code class="language-plaintext highlighter-rouge">Control</code> keys instead, if you’re used to the
classic <code class="language-plaintext highlighter-rouge">Ctrl-c</code> and <code class="language-plaintext highlighter-rouge">Ctrl-v</code> shortcuts for copy and paste.</p>

<p>The Mac keyboard is also missing a delete key, so I used an app called
<a href="https://karabiner-elements.pqrs.org/">Karabiner-Elements</a> to map
<code class="language-plaintext highlighter-rouge">Shift+Backspace</code> to <code class="language-plaintext highlighter-rouge">Delete</code>. It has a GUI for remapping, and also has a JSON
config file.</p>

<p>So for that example we can have:</p>

<div class="language-json highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="p">{</span><span class="w">
    </span><span class="nl">"profiles"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
        </span><span class="p">{</span><span class="w">
            </span><span class="nl">"complex_modifications"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                </span><span class="nl">"rules"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
                    </span><span class="p">{</span><span class="w">
                        </span><span class="nl">"description"</span><span class="p">:</span><span class="w"> </span><span class="s2">"Shift + Delete = Forward Delete"</span><span class="p">,</span><span class="w">
                        </span><span class="nl">"manipulators"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="w">
                            </span><span class="p">{</span><span class="w">
                                </span><span class="nl">"from"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w">
                                    </span><span class="nl">"key_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"delete_or_backspace"</span><span class="p">,</span><span class="w">
                                    </span><span class="nl">"modifiers"</span><span class="p">:</span><span class="w"> </span><span class="p">{</span><span class="w"> </span><span class="nl">"mandatory"</span><span class="p">:</span><span class="w"> </span><span class="p">[</span><span class="s2">"shift"</span><span class="p">]</span><span class="w"> </span><span class="p">}</span><span class="w">
                                </span><span class="p">},</span><span class="w">
                                </span><span class="nl">"to"</span><span class="p">:</span><span class="w"> </span><span class="p">[{</span><span class="w"> </span><span class="nl">"key_code"</span><span class="p">:</span><span class="w"> </span><span class="s2">"delete_forward"</span><span class="w"> </span><span class="p">}],</span><span class="w">
                                </span><span class="nl">"type"</span><span class="p">:</span><span class="w"> </span><span class="s2">"basic"</span><span class="w">
                            </span><span class="p">}</span><span class="w">
                        </span><span class="p">]</span><span class="w">
                    </span><span class="p">},</span><span class="w">
</span></code></pre></div></div>

<p>Other remaps worth considering include tilde (<code class="language-plaintext highlighter-rouge">~</code>), quote (<code class="language-plaintext highlighter-rouge">"</code>), at (<code class="language-plaintext highlighter-rouge">@</code>), and
backslash (<code class="language-plaintext highlighter-rouge">\</code>).</p>

<h1 id="external-monitor-issues">External Monitor Issues</h1>

<p>One of the most surprising issues was connecting to an external monitor. I like
to connect the laptop to an external monitor, and I want the external monitor to
be my <em>only</em> display (i.e., turn off the laptop screen). One monitor is
sufficient for my workflow. It turns out, for some reason, this isn’t possible
in Mac out of the box.</p>

<p>One <em>can</em> use “clamshell mode”, where if you close the laptop lid, the external
monitor will become the only display. However, this means that you cannot use
the laptop keyboard, and I prefer to use the laptop keyboard for consistency.</p>

<p>I had to install third-party software to achieve this, called
<a href="https://github.com/waydabber/BetterDisplay">BetterDisplay</a>. In its settings, I
then navigated to Displays-&gt;Overview-&gt;Connection Management Settings-&gt;Disconnect
built-in display when an external display is connected. This capability should
be built into the OS; it exists in most other systems.</p>

<h1 id="sketchybar">SketchyBar</h1>

<p>As part of using Yabai, I wanted a status bar that could show me the current
workspace I’m using. However, out of the box, I couldn’t find a way to do this.</p>

<p>Therefore I used a third-party status bar called
<a href="https://github.com/FelixKratz/SketchyBar">SketchyBar</a>, which is highly
customizable.</p>

<p>I opted to keep it simple, with the current workspace number, to the right of
the battery level.</p>

<p><img src="https://gibsonic.org/assets/pics/2025-10-screenshot.png" alt="Screenshot of desktop" width="1024" /></p>

<p>The default macOS status bar remains accessible with this configuration:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>sketchybar <span class="nt">--add</span> item hide left <span class="se">\</span>
           <span class="nt">--set</span> hide <span class="nv">script</span><span class="o">=</span><span class="s2">"sketchybar --bar hidden=on; sleep 5; sketchybar --bar hidden=off"</span> <span class="se">\</span>
           <span class="nt">--subscribe</span> hide mouse.entered.global
</code></pre></div></div>

<p>But I’m grateful that SketchyBar exists, since there’s a lot of unnecessary
menus and icons in the default Mac status bar.</p>

<h1 id="hiding-the-mouse-pointer">Hiding the Mouse Pointer</h1>

<p>I haven’t fully reached the point of never using the mouse, especially when much
of the web is still designed for mouse interaction. However, I tend to use the
mouse a lot less than most people. Therefore, I want the mouse pointer to
disappear when I’m not using it. To achieve this, I used a third-party app
called
<a href="https://doomlaser.com/cursorcerer-hide-your-cursor-at-will/">cursorcerer</a>.</p>

<h1 id="emacs">Emacs</h1>

<p>The <a href="https://github.com/d12frosted/homebrew-emacs-plus">Emacs Plus formula</a> from
Homebrew is pretty good, but it doesn’t install a <code class="language-plaintext highlighter-rouge">.app</code> file into
<code class="language-plaintext highlighter-rouge">/Applications</code> by default.</p>

<p>I had to copy the <code class="language-plaintext highlighter-rouge">.app</code> file into <code class="language-plaintext highlighter-rouge">/Applications</code> for the shortcuts to work.</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="nb">sudo cp</span> <span class="nt">-R</span> /opt/homebrew/opt/emacs-plus/Emacs.app /Applications
</code></pre></div></div>

<p>I also had to add <code class="language-plaintext highlighter-rouge">(add-to-list 'default-frame-alist '(undecorated . t))</code> to my
<code class="language-plaintext highlighter-rouge">~/.config/emacs/early-init.el</code> file to remove the title bar, and rounded
corners, which I consider unnecessary.</p>

<h1 id="terminal">Terminal</h1>

<p>Alas, I’m not so deep in the Emacs bucket that I use it as my terminal emulator.
I prefer to use a separate terminal emulator, with tabs, and an extra level of
nesting with tmux.</p>

<p>The default terminal on Mac had strange keybindings, and the app <code class="language-plaintext highlighter-rouge">iTerm2</code> had
similar issues.</p>

<p>I ended up using <code class="language-plaintext highlighter-rouge">kitty</code>, which allowed me to configure the keybindings to match
my needs with a simple config file.</p>

<h1 id="conclusion">Conclusion</h1>

<p>There are many more issues I’ve encountered, but these are the main ones that
have got in the way of my workflow. There is a large community of third-party
tools that may be better suited to meet the needs of your workflow, and I’m sure
folk out there have even better setups. For me, this was the minimum viable
setup to get my work done.</p>

<p>On the bright side, the experience of setting up a new environment has allowed
me to feed back some improvements into my normal workflow on Linux as well. For
example, Shift+Backspace to Delete, and tiling window management. Also, missing
the Trackpoint on the Mac keyboard has pushed me to use the keyboard more, which
feels like a win (in the most meaningless sense).</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="linux" /><category term="mac" /><category term="emacs" /><category term="dev" /><category term="workflow" /><summary type="html"><![CDATA[At work, we recently transitioned everyone to MacBooks. I’ve never used one before, and had spent the past decade on Linux laptops which I’ve gradually refined to my liking. Here’s an inconvenient truth — these machines are not designed to meet my needs. Being able to modify them to meet those needs has been a challenge. In an attempt to not alienate my readers, this doesn’t mean that folk with other needs are wrong. Apple clearly has a particular set of users in mind; I’m just not one of them. My philosophy is that the tools I use should behave the way I tell them to. This post describes some of the issues I’ve encountered trying to achieve that, and how I’ve worked around them. Overall, I’ve been able to get a workable setup.]]></summary></entry><entry><title type="html">Show Me Your Code: Binary White Dwarfs &amp;amp; Melize Ferrus</title><link href="https://gibsonic.org/blog/2025/10/11/bwd/" rel="alternate" type="text/html" title="Show Me Your Code: Binary White Dwarfs &amp;amp; Melize Ferrus" /><published>2025-10-11T10:20:08+00:00</published><updated>2025-10-11T10:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/11/bwd</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/11/bwd/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-bwd.png" width="1024" /></p>

<p>I’ve been chatting recently with
<a href="https://orcid.org/0000-0002-2842-2067">Melize Ferrus</a>, currently working on
<span class="pronoun" data-type="possessive"></span> PhD in physics and studying
various aspects of gravitational waves.</p>

<p>It’s not an area I have much expertise in, but through a series of chats and
playing around with some of <span class="pronoun" data-type="possessive"></span>
code (and making some fun demos), I thought I’d discuss what I’ve learned. This
is not a deep dive into the physics, but rather an exercise in cross-discipline
communication, and a chance to play with some Python code. I wrap up with a Q&amp;A
to hear <span class="pronoun" data-type="possessive"></span> take on physics and collaboration.</p>

<!--more-->

<p>I’ve asked Melize to write some clarifications and commentary, which will appear
in block quotes like this:</p>

<blockquote>
  <p>What it do, what it does 🥘</p>
</blockquote>

<p>The rest of the text is my understanding, and may contain errors. Anything you
see that is wrong is my fault, not Melize’s (including quote transcription).
Everything should be prefixed with “I reckon”. You can read more about Melize’s
work on gravitational waves in
<a href="https://nautil.us/a-supermassive-test-for-einsteins-famous-theory-312691/">this article</a>.</p>

<p>Melize’s code is closed source for now while <span class="pronoun" data-type="subject"></span> works on some active areas of research, but I was
given access to it for this exercise. The <a href="https://www.astropy.org/"><code class="language-plaintext highlighter-rouge">astropy</code></a>
and <a href="https://numpy.org/"><code class="language-plaintext highlighter-rouge">numpy</code></a> libraries are used extensively.</p>

<h1 id="the-problem-area">The Problem Area</h1>

<p>The code that Melize shared with me was looking at binary white dwarf (BWD)
systems. These are pairs of white dwarf stars (which are the cores of dead
stars) orbiting each other.</p>

<p>There are a few reasons why these systems are interesting to study. From what I
gather though, of particular interest is that when these stars get close to each
other, they can produce very small gravitational waves.</p>

<blockquote>
  <p>When the white dwarfs get close enough that they become bound and start
orbiting each other, they emit gravitational waves. We’re mostly looking at
ones inside our own galaxy, because anything further out would be way too
faint to detect.</p>
</blockquote>

<p>It is difficult to detect gravitational waves from such small systems, but the
reason why we care is that they contribute noise, or “background radiation”, to
the gravitational wave signals we do care about, such as those from black hole
mergers.</p>

<p>Therefore, understanding these white dwarf systems helps us to better interpret
the gravitational wave data we receive from detectors like
<a href="https://en.wikipedia.org/wiki/LIGO">LIGO</a> and
<a href="https://www.virgo-gw.eu/science/gw-universe/the-first-detections/">Virgo</a>.</p>

<blockquote>
  <p>In my case the work’s for LISA — the space-based gravitational wave detector.
It’ll be much more sensitive and looks at a totally different frequency range
than the ground ones like LIGO or Virgo. You need it in space, because the
arms have to be effectively millions of kilometers long. Ground detectors
catch signals lasting less than a second; LISA will see them for weeks or even
months. That means we can detect black holes long before they merge and
coordinate with telescopes to watch the same event. It’s going to open up a
lot for cosmology and multi-messenger studies.</p>
</blockquote>

<p>So how does Melize’s code tackle this problem?</p>

<h1 id="the-code">The Code</h1>

<p>I saw that Melize’s code had two main parts, both of which use <em>Gibbs Sampling</em>.
Gibbs sampling is a statistical technique used to generate samples from a
probability distribution. We don’t need to use “real” data points from
astronomical observations, especially with the number of data points we need.
Instead, we can use our models of the Galaxy and the binary white dwarf systems
to generate synthetic data points that are statistically similar to what we
might observe.</p>

<blockquote>
  <p>I’d maybe mention it’s a Monte Carlo method — Gibbs sampling is just one type
of that. There are a bunch of approaches; this is the one I happened to use.</p>
</blockquote>

<p>The two main uses of Gibbs sampling in <span class="pronoun" data-type="possessive"></span> code were:</p>

<ul>
  <li>Drawing samples of what the binary white dwarf systems might look like (e.g.,
their masses, distances, and orbital periods).</li>
  <li>Generating <em>where</em> in the galaxy these systems might be located.</li>
</ul>

<p>Boffins have modelled what we think the distribution of these systems looks
like, and this code is drawing samples from this distribution. The specifics of
the distributions are not important for this discussion, and not something I’ve
taken the time to understand.</p>

<blockquote>
  <p>It’s only separated into two parts because I’m lazy. Theoretically they could
all live in the same Gibbs sampler. It’s on my to-do list to merge them into a
proper joint distribution.</p>
</blockquote>

<h1 id="binary-white-dwarf-systems">Binary White Dwarf Systems</h1>

<p>When we generate a sample of a binary white dwarf system, we are generating:</p>

<ul>
  <li>The mass of the first white dwarf (in solar masses).</li>
  <li>The mass of the second white dwarf (in solar masses).</li>
  <li>Their semi-major axis (in solar radii) — essentially the orbital radius, but
these orbits aren’t circular.</li>
  <li>Their orbital eccentricity (what shape their orbit is).</li>
</ul>

<blockquote>
  <p>Semi-major axis is the halfway point of the furthest distance between the two
bodies in their orbit.</p>
</blockquote>

<p>For example, a sample I generated from Melize’s code was:</p>

<p><strong>Example Binary White Dwarf System</strong></p>

<!-- prettier-ignore-start -->
<p>\(\begin{aligned}
m_1 &amp;= 1.33\,M_\odot \\
m_2 &amp;= 0.64\,M_\odot \\
e   &amp;= 0.38 \\
a   &amp;= 7.26 \times 10^5\,R_\odot
\end{aligned}\)
<!-- prettier-ignore-end --></p>

<p>To help with my own exploration, I also gave each system a random name using 2
words from the <a href="https://www.eff.org/dice">EFF Long Wordlist</a>.</p>

<p>E.g.,</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>overrun-nicotine
stack-thursday
goldmine-undesired
strained-hurried
ecologist-undead
cherisher-degree
supermom-unsigned
rescuer-sternum
zebra-crepe
</code></pre></div></div>

<p>From this code, we can generate as many samples as we want, and our set of
binary white dwarf systems will be distributed according to our model.</p>

<p><strong>Melize, what can we do with these samples?</strong></p>

<blockquote>
  <p>What I’m actually computing is the gravitational-wave power contributed by all
the white dwarfs at each discrete frequency. E.g., using some nonsense numbers
and units, it might give one million watts at 1 mHz and something else at 10
mHz. Let’s say those are the bands LISA’s interferometer is looking at, and
that helps us correct our observations. That’s my focus, though you could use
the samples for other analyses too.</p>
</blockquote>

<h1 id="galactic-coordinates">Galactic Coordinates</h1>

<p>We expect the white dwarf systems to be distributed around the Milky Way galaxy,
with a higher density towards the center of the galaxy, and a lower density as
we move away from the center.</p>

<p>The galaxy is modelled as a disk, with a bulge in the center. Melize’s model
generates “2D cylindrical galactic coordinates”, which are:</p>

<ul>
  <li>(R): radial distance: the distance from the center of the galaxy.</li>
  <li>(Z): the vertical distance above or below the galactic midplane.</li>
</ul>

<blockquote>
  <p>The coordinates are cylindrical — the center of the galaxy’s at (0, 0).
They’re distributed to match how main-sequence stars are spread throughout the
Milky Way. From a logical standpoint they’re just dead stars, so BWDs will be
wherever stars are. I can’t think of a strong reason for their distribution to
be very different.</p>
</blockquote>

<p>This is in contrast to the more familiar Cartesian coordinates <code class="language-plaintext highlighter-rouge">(x, y, z)</code>.
However, to convert from galactic coordinates to Cartesian coordinates, we also
need the “azimuthal” angle (φ), which is the angle around the center of the
galaxy. This requires an assumption about how the systems are distributed
<em>around</em> the galaxy. This isn’t necessary for Melize’s work, but I wanted to
visualise the results in a format I was more familiar with.</p>

<p>Therefore I added a third step to the code, which was to draw a random angle
between <code class="language-plaintext highlighter-rouge">[0, τ]</code>, and then convert from galactic coordinates to Cartesian ones.
We already have the <code class="language-plaintext highlighter-rouge">Z</code> coordinate, and we can convert from <code class="language-plaintext highlighter-rouge">(R, φ)</code> to <code class="language-plaintext highlighter-rouge">(x, y)</code>
using:</p>

<!-- prettier-ignore-start -->
<p>\(\begin{aligned}
x &amp;= R \cos(\phi) \\
y &amp;= R \sin(\phi)
\end{aligned}\)
<!-- prettier-ignore-end --></p>

<blockquote>
  <p>For what I’m doing, you do eventually need the azimuthal angle because you
need to know where the binary is located relative to the gravitational wave.
But it’s uniform, so there’s no need to sample it — it’s just drawn uniformly,
sometimes conditional on other factors.</p>
</blockquote>

<h1 id="visualisation">Visualisation</h1>

<p>With Melize’s code, and some minor data transformation, we can now generate
5,000 BWD systems, and also generate their positions in the galaxy. The code is
capable of generating as many samples as we want, but for my purposes I kept the
number small.</p>

<p>This plot is interactive, using the <code class="language-plaintext highlighter-rouge">plotly</code> library, and its <code class="language-plaintext highlighter-rouge">go.Scatter3d</code>
tool. I initially made this in a Jupyter notebook, and then exported it to a
format that can run in the browser using Plotly’s JavaScript library, using
<code class="language-plaintext highlighter-rouge">fig.write_json("2025-10-binaries.json")</code>.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Create an interactive 3D scatter plot of the sampled systems
</span><span class="kn">import</span> <span class="n">plotly.graph_objects</span> <span class="k">as</span> <span class="n">go</span>

<span class="n">fig</span> <span class="o">=</span> <span class="n">go</span><span class="p">.</span><span class="nc">Figure</span><span class="p">(</span>
    <span class="n">go</span><span class="p">.</span><span class="nc">Scatter3d</span><span class="p">(</span>
        <span class="n">x</span><span class="o">=</span><span class="n">x</span><span class="p">,</span>
        <span class="n">y</span><span class="o">=</span><span class="n">y</span><span class="p">,</span>
        <span class="n">z</span><span class="o">=</span><span class="n">z_vals</span><span class="p">,</span>
        <span class="n">mode</span><span class="o">=</span><span class="sh">"</span><span class="s">markers</span><span class="sh">"</span><span class="p">,</span>
        <span class="n">text</span><span class="o">=</span><span class="n">hover_text</span><span class="p">,</span>
        <span class="n">hoverinfo</span><span class="o">=</span><span class="sh">"</span><span class="s">text</span><span class="sh">"</span><span class="p">,</span>
        <span class="n">marker</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span>
            <span class="n">size</span><span class="o">=</span><span class="mi">3</span><span class="p">,</span>
            <span class="n">color</span><span class="o">=</span><span class="n">m1_vals</span><span class="p">,</span>
            <span class="n">colorscale</span><span class="o">=</span><span class="sh">"</span><span class="s">Turbo</span><span class="sh">"</span><span class="p">,</span>
            <span class="n">colorbar</span><span class="o">=</span><span class="nf">dict</span><span class="p">(</span><span class="n">title</span><span class="o">=</span><span class="sh">"</span><span class="s">Primary Mass [M☉]</span><span class="sh">"</span><span class="p">,</span> <span class="n">tickcolor</span><span class="o">=</span><span class="sh">"</span><span class="s">white</span><span class="sh">"</span><span class="p">),</span>
            <span class="n">opacity</span><span class="o">=</span><span class="mf">0.8</span><span class="p">,</span>
        <span class="p">),</span>
    <span class="p">)</span>
<span class="p">)</span>
</code></pre></div></div>

<p>You can see it below, if your browser supports it.</p>

<div id="binaries_plot" style="width:100%;height:600px;"></div>

<p>If you hover over a point, it will show you the details of that binary white
dwarf system, including the randomly generated name I added.</p>

<h1 id="audio-shenanigans">Audio Shenanigans</h1>

<p>Next, I wanted to do something more playful. Using the generated BWD systems, I
tried out a few techniques to turn them into musical notes. I spent some time
tuning how different parameters influenced the audio.</p>

<p>I’ve not done much audio programming before, so I kept it simple, using 4 basic
waveform types: sine, square, snare, and kick.</p>

<p><img src="/assets/pics/2025-10-waves.png" alt="Waveforms" style="width:100%;max-width:800px;margin-bottom:1rem;" /></p>
<div id="waves_audio_controls" style="display:flex;flex-wrap:wrap;justify-content:center;gap:1rem;
            margin-bottom:2rem;position:relative;z-index:1;">
  <button onclick="playArray(window.data_sine)">▶ Sine</button>
  <button onclick="playArray(window.data_square)">▶ Square</button>
  <button onclick="playArray(window.data_snare)">▶ Snare</button>
  <button onclick="playArray(window.data_kick)">▶ Kick</button>
</div>

<p>I generated a bunch of BWD samples, and checked the parameter ranges so I could
normalise them.</p>

<p>My code ended up being quite hacky:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">def</span> <span class="nf">bwd_to_voice</span><span class="p">(</span><span class="n">m1</span><span class="p">,</span> <span class="n">m2</span><span class="p">,</span> <span class="n">e</span><span class="p">,</span> <span class="n">a</span><span class="p">,</span> <span class="n">norm_ranges</span><span class="p">):</span>
    <span class="sh">"""</span><span class="s">Map BWD parameters to sound features and instrument type.</span><span class="sh">"""</span>
    <span class="n">nm1</span><span class="p">,</span> <span class="n">nm2</span><span class="p">,</span> <span class="n">ne</span><span class="p">,</span> <span class="n">na</span> <span class="o">=</span> <span class="n">norm_ranges</span>
    <span class="n">mass_avg</span> <span class="o">=</span> <span class="p">(</span><span class="n">m1</span> <span class="o">-</span> <span class="n">nm1</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">nm1</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">nm1</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">1e-9</span><span class="p">)</span>
    <span class="n">ecc</span> <span class="o">=</span> <span class="p">(</span><span class="n">e</span> <span class="o">-</span> <span class="n">ne</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">ne</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">ne</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">1e-9</span><span class="p">)</span>
    <span class="n">sep</span> <span class="o">=</span> <span class="p">(</span><span class="n">a</span> <span class="o">-</span> <span class="n">na</span><span class="p">[</span><span class="mi">0</span><span class="p">])</span> <span class="o">/</span> <span class="p">(</span><span class="n">na</span><span class="p">[</span><span class="mi">1</span><span class="p">]</span> <span class="o">-</span> <span class="n">na</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span> <span class="o">+</span> <span class="mf">1e-9</span><span class="p">)</span>
    <span class="n">q</span> <span class="o">=</span> <span class="n">m2</span> <span class="o">/</span> <span class="n">m1</span>
    <span class="n">asym</span> <span class="o">=</span> <span class="nf">abs</span><span class="p">(</span><span class="n">m1</span> <span class="o">-</span> <span class="n">m2</span><span class="p">)</span> <span class="o">/</span> <span class="n">m1</span>

    <span class="c1"># instrument choice
</span>    <span class="k">if</span> <span class="n">mass_avg</span> <span class="o">&gt;</span> <span class="mf">0.8</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">kick</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="n">ecc</span> <span class="o">&gt;</span> <span class="mf">0.7</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">snare</span><span class="sh">"</span>
    <span class="k">elif</span> <span class="n">asym</span> <span class="o">&gt;</span> <span class="mf">0.3</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">square</span><span class="sh">"</span>
    <span class="k">else</span><span class="p">:</span>
        <span class="n">voice</span> <span class="o">=</span> <span class="sh">"</span><span class="s">sine</span><span class="sh">"</span>

    <span class="n">freq</span> <span class="o">=</span> <span class="mi">100</span> <span class="o">+</span> <span class="mi">800</span> <span class="o">*</span> <span class="n">mass_avg</span>
    <span class="n">dur</span> <span class="o">=</span> <span class="mf">0.2</span> <span class="o">+</span> <span class="mf">0.8</span> <span class="o">*</span> <span class="p">(</span><span class="mi">1</span> <span class="o">-</span> <span class="n">sep</span><span class="p">)</span>
    <span class="n">vol</span> <span class="o">=</span> <span class="mf">0.3</span> <span class="o">+</span> <span class="mf">0.7</span> <span class="o">*</span> <span class="n">ecc</span>
    <span class="k">return</span> <span class="n">freq</span><span class="p">,</span> <span class="n">dur</span><span class="p">,</span> <span class="n">vol</span><span class="p">,</span> <span class="n">voice</span>
</code></pre></div></div>

<p>With a constant BPM, I passed binary white dwarf systems through this code,
making one note each, and generated the following track:</p>

<div style="position:relative;padding-bottom:56.25%;height:0;overflow:hidden;margin:1.5rem 0;">
  <iframe src="https://www.youtube.com/embed/xEgBRG2BrM0" title="YouTube video player" style="position:absolute;top:0;left:0;width:100%;height:100%;border:0;" allow="accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture; web-share" allowfullscreen="">
  </iframe>
</div>

<p>A tad atonal, which makes sense since we’re mapping astronomical parameters to
musical ones without any harmonic constraints. Maybe I need to read more music
theory. However, it grows on me the more I generate and listen to it.</p>

<p>Perhaps it’s hubris to think that randomly generated white dwarf systems would
immediately make good music, but it’s fun to try.</p>

<blockquote>
  <p>I can’t wait to somehow contribute to a future post where we come at music
from the mathematical angle — figuring out what makes music sound good without
actually knowing what the notes mean.</p>
</blockquote>

<h1 id="qa">Q&amp;A</h1>

<p>Now that I’ve shown some of my hacking around with Melize’s code, here I take
the opportunity to ask <span class="pronoun" data-type="object"></span> some
general questions.</p>

<p><strong>What got you interested in this area of research?</strong></p>

<blockquote>
  <p>Honestly, nothing in particular. I always wanted to be an astronomer as a kid.
At some point I realized I liked physics, so I thought astrophysics would be
cool.</p>

  <p>But I didn’t really know how to read my college website properly, so I didn’t
realize they didn’t even have astronomy. I knew they had physics, but I didn’t
check the course list well enough. Once I was there, I realized—oh, there’s
nothing astronomy-related here.</p>

  <p>I got involved in aerospace engineering stuff for a bit, then kind of gave up
and moved on. Later, I heard about an internship at the Flatiron Institute for
people in the National Society for Black Physicists. I applied, got sent a
list of different research topics, and picked my top three. The one I ended up
doing was literally my lowest-ranked choice.</p>

  <p>I think my top pick was something about solar oscillations, and the second one
I forget. But yeah, I ended up getting the third one, and over the course of
the internship I realized I really liked it. So there was no grand plan like,
“I’ve always wanted to work on black holes.” It just kind of happened.</p>
</blockquote>

<p><strong>What are some big open questions in this area of research that you’re
interested in?</strong></p>

<blockquote>
  <p>I work across a pretty wide range of things in gravitational waves. What I’m
doing now is different from what I did with at Flatiron, and different again
from what I did at King’s.</p>

  <p>On the numerical relativity side, one big question is whether we can come up
with a model or theorem that works for the merger phase of black hole
collisions. We already have post-Newtonian approximations for the inspiral,
and quasi-normal modes for the ringdown. Those let you predict what the
gravitational wave looks like if you know the parameters of the system.</p>

  <p>But for that last bit, right before the black holes coalesce, there’s no
theorem—just heavy computation. It would be great if we had a simpler equation
or model instead of running six-hour-long simulations for that one stage.</p>

  <p>Then there’s eccentricity. Black hole mergers can have different
eccentricities, and that changes the whole signal. But those effects can look
like other things—spin, non-vacuum conditions, whatever. So it’s hard to tell
what’s what. We usually assume circular orbits, but they’re often not.
Understanding the typical black hole orbit better would help a lot—both for
improving models and for things like star formation studies.</p>

  <p>For the LISA mission, a huge open question is what we’ll learn about
cosmology. LIGO only catches the last second or so of a merger. LISA will
detect black holes a month in advance. That means you can get detailed
parameters early, subtract out the known signals, and study what’s
left—possibly signs of inflation, cosmic strings, or first-order phase
transitions. The future looks really exciting for cosmology.</p>
</blockquote>

<p><strong>You deal with some pretty large simulations and computations. Would you say
that programming is a big part of your work? Is there enough collaboration
between physicists and computer experts?</strong></p>

<blockquote>
  <p>Yeah, programming’s a big part of it. But I’d say most physicists are computer
experts only in the sense that they know enough to make their own stuff work.
We’re not computer experts broadly.</p>

  <p>Like, you [ed: Perry] know enough physics to help me out with something, but
not enough physics overall to anticipate what I might need. Same for me—I know
enough computational stuff to get results, but I don’t always follow the best
practices. Someone else could look at my code and think, “Sure, it works, but
this could be done way better.”</p>

  <p>There could definitely be more collaboration. Everyone’s under pressure to
produce results quickly, so code often ends up written in brute-force, opaque
ways. Later, when new people join, they spend weeks just figuring out what the
code even does. Half of it could’ve been explained in a docstring or wiki.</p>

  <p>A lot of scientific code isn’t open source. That really limits reproducibility
and collaboration. Sometimes groups hoard code to keep control—people have to
email them to run a simulation instead of doing it themselves. Then those
teams rack up citations for just pressing run. Nothing’s truly replicable
because others can’t see the underlying code.</p>

  <p>I’ve even been on papers where the authors said they were using the “highly
precise [system] code.” But how do you know it’s precise? You’ve never seen
the infrastructure. Everyone assumes it’s right because a big name’s attached.
It’s very anti-scientific—this blind trust that something’s correct just
because of who made it.</p>
</blockquote>

<p><strong>Amongst other things, you’re black, and present pretty femme, which is still
relatively rare in physics. Have you had any interesting or noteworthy
experiences through this lens?</strong></p>

<blockquote>
  <p>I’ve got a few specific examples, but I don’t want to call anyone out.</p>

  <p>I get mistaken for other people a lot, even at conferences. It happens so
often it’s almost funny, except it’s not.</p>

  <p>Like, once at a conference, I asked in the group chat if anyone had
painkillers because I had cramps. A guy brought me one, fine. The next day, he
said he’d seen “me” while biking and shouted, “Do you still need the
drugs?”—but it was just some random woman with similar hair. He figured that
must be me.</p>

  <p>I’ve also been to plenty of conferences where no one sits with me. Literally,
people will fill every seat around me but not next to me. It feels isolating.</p>

  <p>It’s not that anyone’s openly rude. It’s just that constant, quiet exclusion.
Seeing your peers welcomed while you’re sidelined makes you ask why. It’s
tiring.</p>
</blockquote>

<p><strong>What are the biggest uncertainties in the models you work with?</strong></p>

<blockquote>
  <p>Oh, huge ones. One of the biggest is the merger rate—how many mergers happen
per year. The uncertainty can be as large as the value itself.</p>

  <p>Let me bring up one of my favorite ones. It’s very entertaining to me</p>
</blockquote>

<!-- prettier-ignore-start -->
<p><em>(<span class="pronoun" data-type="subject"></span> types on <span class="pronoun" data-type="possessive"></span> laptop for a moment, then starts laughing.)</em>
<!-- prettier-ignore-end --></p>

<blockquote>
  <p><a href="https://journals.aps.org/prx/pdf/10.1103/PhysRevX.9.031040">Here we go: neutron star mergers [page 26]</a>.
The estimated rate is 920 per gigaparsec cubed per year, with a +2,220 / –790
margin!</p>

  <p>Hands down, that’s my favourite. I roll around in my non-existent grave to
this shit. It’s a couple of years old, so newer estimates are probably tighter
now. This is for the first two observations of LIGO with the neutron star
detection for the collision rate.</p>

  <p>Yeah, I have a lot of confidence in all of the different things I generate
using those kinds of things…</p>
</blockquote>

<p><strong>Anything else you want to say?</strong></p>

<blockquote>
  <p>I really like the kind of work I do. I’ve been lucky to move between
institutions and completely change up what I’m working on each time.</p>

  <p>After my year at Flatiron I felt cocky about starting my PhD, “I run this
bitch,” but when I got to King’s it was like starting from scratch again due
to the alternative perspectives on the topic. It’s cool seeing how much
undergrad material—stuff I once thought was useless—actually shows up all the
time.</p>

  <p>In undergrad, you’re rushing to master something in 13 weeks, then it leaks
out of your head. Doing a PhD gives you the time to actually learn it
properly. None of my physics education was a waste. Even the quantum mechanics
I thought I’d never need has ended up being useful.</p>
</blockquote>

<blockquote>
  <p>It gives you time to learn the thing properly, as opposed to learn the thing
in order to pass the test. Yeah, so like if you didn’t do everything perfectly
in your undergrad, it’s fine. I think it’s just that doing a PhD gives you
more appreciation of it.</p>
</blockquote>

<p><strong>Thank you Melize.</strong></p>

<blockquote>
  <p>Thank you Dr Gibson, I’ll see you on GitHub 🙂‍↕️.</p>
</blockquote>

<h1 id="conclusions">Conclusions</h1>

<p>When I talk to specialists in other fields who are articulate and passionate
about their work, I find it infectious. I usually come away with the feeling of
“ah, so it <em>isn’t magic</em>, but <em>it is</em> hard”. I haven’t eaten my intellectual
vegetables by working through general-relativity textbook exercises. However, by
inhabiting Melize’s code for a while, and picking
<span class="pronoun" data-type="possessive"></span> brain, I feel like I’ve
gained a little more appreciation of the field, and the cool people that work in
it.</p>

<script src="https://cdn.plot.ly/plotly-2.35.2.min.js"></script>

<div id="binaries_plot" style="width:100%;height:600px;"></div>
<script>
fetch('/assets/plotly/2025-10-binaries.json')
  .then(r => r.json())
  .then(fig => Plotly.newPlot('binaries_plot', fig.data, fig.layout, {responsive:true}));
</script>

<script>
fetch('/assets/plotly/2025-10-waves-audio.json')
  .then(r => r.json())
  .then(data => {
    window.data_sine = data.sine;
    window.data_square = data.square;
    window.data_snare = data.snare;
    window.data_kick = data.kick;
  });

function playArray(arr, sampleRate=8000) {
  if (!arr) return;
  const ctx = new (window.AudioContext || window.webkitAudioContext)();
  const buf = ctx.createBuffer(1, arr.length, sampleRate);
  buf.copyToChannel(Float32Array.from(arr), 0);
  const src = ctx.createBufferSource();
  src.buffer = buf;
  src.connect(ctx.destination);
  src.start();
}
</script>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="python" /><category term="science" /><category term="physics" /><summary type="html"><![CDATA[I’ve been chatting recently with Melize Ferrus, currently working on PhD in physics and studying various aspects of gravitational waves. It’s not an area I have much expertise in, but through a series of chats and playing around with some of code (and making some fun demos), I thought I’d discuss what I’ve learned. This is not a deep dive into the physics, but rather an exercise in cross-discipline communication, and a chance to play with some Python code. I wrap up with a Q&amp;A to hear take on physics and collaboration.]]></summary></entry><entry><title type="html">Simple Workflow Tweaks for Scientific Python Projects</title><link href="https://gibsonic.org/blog/2025/10/05/python_science/" rel="alternate" type="text/html" title="Simple Workflow Tweaks for Scientific Python Projects" /><published>2025-10-05T14:20:08+00:00</published><updated>2025-10-05T14:20:08+00:00</updated><id>https://gibsonic.org/blog/2025/10/05/python_science</id><content type="html" xml:base="https://gibsonic.org/blog/2025/10/05/python_science/"><![CDATA[<p><img src="https://gibsonic.org/assets/headers/2025-10-python_tools.png" width="1024" /></p>

<p>I’ve recently been chatting with a couple of mates who are doing scientific
research using Python. Answering specific code questions is a lot of fun, as I
try to figure out enough of their domain to see if/how I can help.</p>

<p>However, there are some general workflow improvements that I think both they and
other scientific Python programmers could benefit from. In this post, I’ll share
some lightweight workflow improvements that can help make your code better.</p>

<!--more-->

<p>Research code is often different from production software: it doesn’t need to be
as robust or strictly engineered. However, a few simple practices can make it
far more reproducible and maintainable.</p>

<p>In this post, we’ll explore steps to improve reproducibility, collaboration, and
confidence in your results — without overcomplicating your code.</p>

<p>This post assumes you’re using GitHub (or a similar platform like GitLab or
Gitea) for version control. If you’re not yet using a VCS, I highly recommend
starting there.</p>

<p>If you are working on more software-engineering-oriented projects, this post is
probably not for you, as there are many more things you should be doing.</p>

<p>We’ll go through a few simple steps:</p>

<ul>
  <li>Creating a Python package with a reproducible environment.</li>
  <li>Writing tests with <code class="language-plaintext highlighter-rouge">pytest</code> to catch bugs early.</li>
  <li>Using pre-commit hooks to maintain code quality automatically.</li>
  <li>Setting up GitHub Actions to run tests on every push.</li>
</ul>

<h2 id="the-project">The Project</h2>

<p>Let’s say we’re using <a href="https://www.astropy.org/">Astropy</a> to do some cosmology
calculations. This isn’t my area of expertise, I’ve just made some bullshit code
that shows the development practices: apologies if it offends your
sensibilities!</p>

<p>Initially, we explored these calculations in a Jupyter notebook. While notebooks
are great for experimentation, they aren’t ideal for <strong>sharing, testing, or
reusing code</strong>. I’ve seen people with functions they copy between every
notebook, making slight changes each time, and then lose track of which version
is “the good one”.</p>

<p>Our first goal is to take some commonly used functions from the notebook and
turn them into a <strong>small, reusable Python package</strong> that we can import into any
notebook or script.</p>

<h2 id="common-package">Common Package</h2>

<p>The outcome of this section can be seen on commit <code class="language-plaintext highlighter-rouge">ed941a</code> of
<a href="https://github.com/Wheest/cosmole-example/tree/ed941aee1683f3be44d3a497437f221986b86acd">this GitHub repository</a>.
I’ll walk through the steps below.</p>

<p>When you have functions that you want to reuse across multiple notebooks or
scripts, it’s best to put them in a <strong>common package</strong> rather than copying and
pasting. Copying code can quickly lead to inconsistencies and bugs as your code
evolves.</p>

<p>For this project, we’ll create a small package called <code class="language-plaintext highlighter-rouge">cosmole</code> containing three
scripts:</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>.
├── cosmole
│   ├── __init__.py
│   ├── angular_separation.py
│   ├── convert_equatorial_to_galactic.py
│   └── redshift_to_distance.py
└── notebooks
    └── 2025-10-07-exploration.ipynb
</code></pre></div></div>

<p>The <code class="language-plaintext highlighter-rouge">__init__.py</code> file defines what is accessible when someone imports the
package:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># cosmole/__init__.py
</span><span class="kn">from</span> <span class="n">.redshift_to_distance</span> <span class="kn">import</span> <span class="n">redshift_to_distance</span>
<span class="kn">from</span> <span class="n">.angular_separation</span> <span class="kn">import</span> <span class="n">angular_separation</span>
<span class="kn">from</span> <span class="n">.convert_equatorial_to_galactic</span> <span class="kn">import</span> <span class="n">convert_equatorial_to_galactic</span>
</code></pre></div></div>

<p>Now (once we’ve finished the following sections), from any notebook or script in
the project, you can import your functions:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">from</span> <span class="n">cosmole</span> <span class="kn">import</span> <span class="p">(</span>
    <span class="n">redshift_to_distance</span><span class="p">,</span>
    <span class="n">angular_separation</span><span class="p">,</span>
    <span class="n">convert_equatorial_to_galactic</span><span class="p">,</span>
<span class="p">)</span>
</code></pre></div></div>

<h3 id="dependency-management">Dependency Management</h3>

<p>In scientific projects, it’s easy for code to stop working later if software
packages you depend on change. When I was writing up my PhD, I had to regenerate
some plots from my first year and ran into issues because <code class="language-plaintext highlighter-rouge">matplotlib</code> had
changed; I wasn’t sure which version I had originally used — it was a pain.</p>

<p>To avoid “it worked on my machine” problems, we can specify exact package
versions using a <code class="language-plaintext highlighter-rouge">requirements.txt</code> file.</p>

<p>This is a simple text file listing all the Python packages your project depends
on, along with their versions. For our project, you can see it
<a href="https://github.com/Wheest/cosmole-example/blob/main/requirements.txt">here</a>.</p>

<p>You can install these dependencies with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install</span> <span class="nt">-r</span> requirements.txt
</code></pre></div></div>

<p>Or with conda:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>conda <span class="nb">install</span> <span class="nt">--file</span> requirements.txt
</code></pre></div></div>

<p>This ensures anyone cloning the repository can reproduce your environment and
run your code without surprises.</p>

<h3 id="setting-up-the-package">Setting up the package</h3>

<p>To make Python aware of your <code class="language-plaintext highlighter-rouge">cosmole</code> package, we need a <strong><code class="language-plaintext highlighter-rouge">setup.py</code></strong> file at
the root of the project. This file tells Python how to install your package and
its dependencies. In our example project,
<a href="https://github.com/Wheest/cosmole-example/blob/ed941aee1683f3be44d3a497437f221986b86acd/setup.py">you can see it here</a>.</p>

<p>We can now install our package with:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install</span> <span class="nt">-e</span> <span class="nb">.</span>
</code></pre></div></div>

<ul>
  <li>The <code class="language-plaintext highlighter-rouge">-e</code> flag means editable — any changes you make to the source code are
reflected immediately when you import the package.</li>
  <li>This is especially handy when working interactively in notebooks.</li>
</ul>

<p>Additionally, adding and executing these lines at the top of your notebooks will
also mean you automatically reload your package whenever you edit any of your
<code class="language-plaintext highlighter-rouge">.py</code> files:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="c1"># Enable autoreload so that changes in imported modules are reflected automatically
</span><span class="o">%</span><span class="n">load_ext</span> <span class="n">autoreload</span>
<span class="o">%</span><span class="n">autoreload</span> <span class="mi">2</span>
</code></pre></div></div>

<h4 id="note-to-conda-users">Note to Conda users</h4>

<p>If you use Conda, you <em>might</em> need an additional file <code class="language-plaintext highlighter-rouge">pyproject.toml</code> in your
project to ensure that the package installs correctly.</p>

<p>E.g.,</p>

<div class="language-toml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="k">[</span><span class="n">build-system</span><span class="k">]</span>
<span class="n">requires</span> <span class="o">=</span><span class="w"> </span><span class="p">[</span><span class="s">"setuptools"</span><span class="p">,</span> <span class="s">"wheel"</span><span class="p">]</span>
<span class="n">build-backend</span> <span class="o">=</span><span class="w"> </span><span class="s">"setuptools.build_meta"</span>
</code></pre></div></div>

<p>This is because modern versions of <code class="language-plaintext highlighter-rouge">pip</code> build packages in <strong>isolated
environments</strong>. So you need to specify that <code class="language-plaintext highlighter-rouge">setuptools</code> and <code class="language-plaintext highlighter-rouge">wheel</code> are
required to build the package (which then installs the dependencies from
<code class="language-plaintext highlighter-rouge">requirements.txt</code>).</p>

<h2 id="testing-your-code">Testing Your Code</h2>

<p>The outcome of this section can be seen on commit
<a href="https://github.com/Wheest/cosmole-example/tree/99050481d5165109625f5c3f18eef9442d1ea4ab"><code class="language-plaintext highlighter-rouge">9905048</code></a>.</p>

<p>Once you have refactored your functions into your package, it’s a good idea to
write tests.</p>

<blockquote>
  <p>Actually, one approach is to write the tests <em>first</em> as we’re developing our
initial implementation of our functions (a practice known as test-driven
development). However, in research, this might not always be the most
practical approach.</p>
</blockquote>

<p>Tests help ensure that your code behaves as expected, which is especially useful
when making changes or refactoring. Good test design is an art, thinking about
edge cases and failure modes.</p>

<p>Even if your research code is exploratory, having a few <strong>basic automated
tests</strong> can catch obvious bugs early and give you confidence that updates don’t
break existing functionality.</p>

<p>During development, you might find that a test itself was wrong, or you changed
the intended purpose of a function. In which case, just update the test — make
them work for you!</p>

<p>We can use the <code class="language-plaintext highlighter-rouge">pytest</code> package to write and run tests. For example, let’s test
one of our functions by adding a file
<code class="language-plaintext highlighter-rouge">tests/test_convert_equatorial_to_galactic.py</code> to the project:</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="kn">import</span> <span class="n">pytest</span>
<span class="kn">from</span> <span class="n">astropy.coordinates</span> <span class="kn">import</span> <span class="n">SkyCoord</span>
<span class="kn">import</span> <span class="n">astropy.units</span> <span class="k">as</span> <span class="n">u</span>
<span class="kn">from</span> <span class="n">cosmole</span> <span class="kn">import</span> <span class="n">convert_equatorial_to_galactic</span>

<span class="k">def</span> <span class="nf">test_convert_equatorial_to_galactic</span><span class="p">():</span>
    <span class="n">ra</span><span class="p">,</span> <span class="n">dec</span> <span class="o">=</span> <span class="mf">83.82208</span><span class="p">,</span> <span class="o">-</span><span class="mf">5.39111</span>  <span class="c1"># Approx location of Orion Nebula
</span>    <span class="n">l</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="nf">convert_equatorial_to_galactic</span><span class="p">(</span><span class="n">ra</span><span class="p">,</span> <span class="n">dec</span><span class="p">)</span>
    <span class="n">coord</span> <span class="o">=</span> <span class="nc">SkyCoord</span><span class="p">(</span><span class="n">ra</span><span class="o">=</span><span class="n">ra</span><span class="o">*</span><span class="n">u</span><span class="p">.</span><span class="n">deg</span><span class="p">,</span> <span class="n">dec</span><span class="o">=</span><span class="n">dec</span><span class="o">*</span><span class="n">u</span><span class="p">.</span><span class="n">deg</span><span class="p">,</span> <span class="n">frame</span><span class="o">=</span><span class="sh">'</span><span class="s">icrs</span><span class="sh">'</span><span class="p">).</span><span class="n">galactic</span>
    <span class="k">assert</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">approx</span><span class="p">(</span><span class="n">l</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">)</span> <span class="o">==</span> <span class="n">coord</span><span class="p">.</span><span class="n">l</span><span class="p">.</span><span class="n">degree</span>
    <span class="k">assert</span> <span class="n">pytest</span><span class="p">.</span><span class="nf">approx</span><span class="p">(</span><span class="n">b</span><span class="p">,</span> <span class="n">rel</span><span class="o">=</span><span class="mf">1e-6</span><span class="p">)</span> <span class="o">==</span> <span class="n">coord</span><span class="p">.</span><span class="n">b</span><span class="p">.</span><span class="n">degree</span>
</code></pre></div></div>

<p>The assert <code class="language-plaintext highlighter-rouge">pytest.approx</code> lines verify that the function returns the expected
results, raising an error if it doesn’t.</p>

<p>To run the tests, from your project root, run:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pytest
</code></pre></div></div>

<p>You should see output like this:</p>

<div class="language-sh highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tests/test_angular_separation.py <span class="nb">.</span>                                                               <span class="o">[</span> 33%]
tests/test_convert_equatorial_to_galactic.py <span class="nb">.</span>                                                   <span class="o">[</span> 66%]
tests/test_redshift_to_distance.py <span class="nb">.</span>
<span class="o">[</span>100%]
</code></pre></div></div>

<p>Which shows that all our tests passed. If we’d introduced a bug (e.g., I
accidentally added 10 to one of my results), the test would catch this:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tests/test_convert_equatorial_to_galactic.py F                                                   <span class="o">[</span> 66%]
tests/test_redshift_to_distance.py <span class="nb">.</span>                                                             <span class="o">[</span>100%]

<span class="o">===============================================</span> FAILURES <span class="o">===============================================</span>
_________________________________ test_convert_equatorial_to_galactic __________________________________

    def test_convert_equatorial_to_galactic<span class="o">()</span>:
        ra, dec <span class="o">=</span> 83.82208, <span class="nt">-5</span>.39111  <span class="c"># Approx location of Orion Nebula</span>
        l, b <span class="o">=</span> convert_equatorial_to_galactic<span class="o">(</span>ra, dec<span class="o">)</span>
        coord <span class="o">=</span> SkyCoord<span class="o">(</span><span class="nv">ra</span><span class="o">=</span>ra <span class="k">*</span> u.deg, <span class="nv">dec</span><span class="o">=</span>dec <span class="k">*</span> u.deg, <span class="nv">frame</span><span class="o">=</span><span class="s2">"icrs"</span><span class="o">)</span>.galactic
<span class="o">&gt;</span>       assert pytest.approx<span class="o">(</span>l, <span class="nv">rel</span><span class="o">=</span>1e-6<span class="o">)</span> <span class="o">==</span> coord.l.degree
E       assert 219.01374318285238 ± 2.2e-04 <span class="o">==</span> np.float64<span class="o">(</span>209.01374318285238<span class="o">)</span>
E
E         comparison failed
E         Obtained: 209.01374318285238
E         Expected: 219.01374318285238 ± 2.2e-04

tests/test_convert_equatorial_to_galactic.py:11: AssertionError
</code></pre></div></div>

<h3 id="pre-commit-hooks">Pre-commit Hooks</h3>

<p>To help maintain consistent code quality, we can use <strong>pre-commit hooks</strong>. These
are scripts that automatically run <strong>before each commit</strong> to check for common
issues like code formatting, linting, or missing documentation.</p>

<p>The key benefits of pre-commit hooks are:</p>

<ul>
  <li><strong>Catch issues early</strong> — errors or style violations are flagged before they
enter your repository.</li>
  <li><strong>Automatic fixes</strong> — many hooks, like code formatters, can fix problems
automatically, saving time.</li>
  <li><strong>Consistency across contributors</strong> — ensures everyone on the project follows
the same style and quality rules.</li>
</ul>

<h4 id="configuration">Configuration</h4>

<p>Pre-commit hooks are configured in a <code class="language-plaintext highlighter-rouge">.pre-commit-config.yaml</code> file at the root
of your project. For example, a simple configuration might include:</p>

<ul>
  <li><strong>Ruff</strong> — a fast Python linter and code formatter.</li>
  <li><strong>Prettier</strong> — for formatting YAML, Markdown, and JSON.</li>
</ul>

<p>In our example project, you can see the configuration file
<a href="https://github.com/Wheest/cosmole-example/blob/main/.pre-commit-config.yaml">here</a>.</p>

<p>You can install pre-commit and set it up with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pip <span class="nb">install </span>pre-commit
pre-commit <span class="nb">install</span>
</code></pre></div></div>

<p>Now, every time you make a commit, the hooks defined in your configuration file
will run automatically on any files that have changed. You can also run them
manually on <strong>all files</strong> with:</p>

<div class="language-bash highlighter-rouge"><div class="highlight"><pre class="highlight"><code>pre-commit run <span class="nt">--all-files</span>
</code></pre></div></div>

<p>In our code, several automatic reformatting steps were applied: none of which
should change our functionality, only the neatness of our code. For example,
removing unused <code class="language-plaintext highlighter-rouge">import</code>s, making sure lines don’t get too long, being
consistent with the use of whitespace, etc.</p>

<p>However, there are also some issues that need manual review. For example, Ruff
complained that we had an ambiguous variable name <code class="language-plaintext highlighter-rouge">l</code> (lowercase L - which looks
like a <code class="language-plaintext highlighter-rouge">1</code>).</p>

<div class="language-plaintext highlighter-rouge"><div class="highlight"><pre class="highlight"><code>tests/test_convert_equatorial_to_galactic.py:8:5: E741 Ambiguous variable name: `l`
   |
 6 | def test_convert_equatorial_to_galactic():
 7 |     ra, dec = 83.82208, -5.39111  # Approx location of Orion Nebula
 8 |     l, b = convert_equatorial_to_galactic(ra, dec)
   |     ^ E741
 9 |     coord = SkyCoord(ra=ra*u.deg, dec=dec*u.deg, frame='icrs').galactic
10 |     assert pytest.approx(l, rel=1e-6) == coord.l.degree
   |
</code></pre></div></div>

<p>Normally, I’d recommend following the rules — they’re opinionated but usually
sensible.</p>

<p>However, we can tell Ruff to ignore this specific warning by adding a comment to
the end of the line.</p>

<div class="language-python highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="n">l</span><span class="p">,</span> <span class="n">b</span> <span class="o">=</span> <span class="nf">convert_equatorial_to_galactic</span><span class="p">(</span><span class="n">ra</span><span class="p">,</span> <span class="n">dec</span><span class="p">)</span>  <span class="c1"># noqa: E741
</span></code></pre></div></div>

<p>You <em>can</em> skip pre-commit using <code class="language-plaintext highlighter-rouge">--no-verify</code>, but only do so if you have a good
reason (like it’s 10pm and you just want to get your changes saved before bed
😴).</p>

<p>In my example, you can see all the pre-commit changes in
<a href="https://github.com/Wheest/cosmole-example/commit/d23d21a9a4343d64522cd9ad15745c95c6e45be1"><code class="language-plaintext highlighter-rouge">d23d21a</code></a>.
In practice, these changes would be applied at the time of writing the code in
the first place, but I wanted to show the before-and-after.</p>

<h3 id="github-actions">GitHub Actions</h3>

<p>Now, we have tests and pre-commit hooks, which are great for local development.
However, we also want to make sure that our code is tested when we push changes,
especially if we’re collaborating with others.</p>

<p>GitHub Actions allows you to run workflows on GitHub-hosted machines. While
these have limited compute power, they can easily handle running basic tests and
automation tasks.</p>

<p>For our example, we can create a workflow that runs our tests and pre-commit
hooks on every push to the repository. If your code can run and pass on a
different machine, that is a great indicator that it is reproducible and not
dependent on your local setup.</p>

<p>Let’s do this by creating a file <code class="language-plaintext highlighter-rouge">.github/workflows/ci.yml</code> as shown
<a href="https://github.com/Wheest/cosmole-example/blob/main/.github/workflows/ci.yml">here</a>.</p>

<p>Now, every time you push changes or create a pull request, GitHub Actions will
automatically run your tests and hooks. This adds an extra layer of confidence
and helps maintain a reliable, reproducible scientific codebase.</p>

<p>You can see on the repo’s GitHub page, a yellow circle after we’ve pushed,
meaning the checks are running</p>

<p><img src="/assets/pics/2025-10-05-gh_actions_yellow.png" width="1024" alt="GitHub Actions workflow running" /></p>

<p>You can see initially, this run fails, and we can click on the red ❌ to see the
<a href="https://github.com/Wheest/cosmole-example/actions/runs/18319638023/job/52169145433">terminal logging what went wrong</a>.</p>

<p>In this case, we didn’t actually install our package on the GitHub runner.
Therefore, we need to add <code class="language-plaintext highlighter-rouge">pip install .</code> to the workflow:</p>

<div class="language-yaml highlighter-rouge"><div class="highlight"><pre class="highlight"><code><span class="pi">-</span> <span class="na">name</span><span class="pi">:</span> <span class="s">Install the package</span>
  <span class="na">run</span><span class="pi">:</span> <span class="s">pip install .</span>
</code></pre></div></div>

<p>Now, our code passes!</p>

<p><img src="/assets/pics/2025-10-05-gh_actions_passed.png" width="1024" alt="GitHub Actions workflow passed" /></p>

<p>In future, we’ll be able to see which commits introduced bugs in our code. If
you use a <code class="language-plaintext highlighter-rouge">git</code>
<a href="https://www.atlassian.com/git/tutorials/comparing-workflows/feature-branch-workflow">feature branch workflow</a>
(using branches for features and PRs), then you can enforce that any commits to
<code class="language-plaintext highlighter-rouge">main</code> <strong>must</strong> pass these checks. However, this may be overkill for a small
research project.</p>

<h2 id="conclusion">Conclusion</h2>

<p>Ultimately, the goal of research code is to help us explore and answer our
research questions. However, small software engineering standards can pay
dividends if applied in a sensible way.</p>

<p>There are more things you may want to explore, for example, you can add more
rules to Ruff
(<a href="https://github.com/Wheest/cosmole-example/pull/1">like enforcing documentation</a>).
Similar workflows can also be applied to projects in other programming
languages. You may also want to standardise your git commit message format,
e.g., using
<a href="https://www.conventionalcommits.org/en/v1.0.0/#summary">Conventional Commits</a>.</p>

<p>P.S. props to my black-hole buddy
<a href="https://orcid.org/0000-0002-2842-2067">Melize</a> for providing the header image,
which is his reproduction of
<a href="https://academic.oup.com/mnras/article/483/4/5518/5251998">Korol et al. 2018</a>.</p>]]></content><author><name>Perry Gibson 🍐</name></author><category term="blog" /><category term="python" /><category term="science" /><category term="reproducibility" /><category term="testing" /><category term="github-actions" /><category term="pre-commit" /><summary type="html"><![CDATA[I’ve recently been chatting with a couple of mates who are doing scientific research using Python. Answering specific code questions is a lot of fun, as I try to figure out enough of their domain to see if/how I can help. However, there are some general workflow improvements that I think both they and other scientific Python programmers could benefit from. In this post, I’ll share some lightweight workflow improvements that can help make your code better.]]></summary></entry></feed>