Chris Dodds

Tech Person, Writer, Misc.

Fish Stick: Stateless Incident Management

I released Fish Stick, a stateless incident management bot for Slack. Written it up over at Fishstick Labs.

This is the sixth or seventh time I’ve built this bot at different jobs. Figured it was time to stop reinventing the wheel and ship something I could reuse (and that others could use too). I’ve actually had a multi-tenant version of this sitting in a folder for several years, but decided to rip all that stuff out and lean into simplicity and OSS.

Most incident management tools are either too basic (Slack workflows that can’t do enough) or way too complex (enterprise platforms with a thousand knobs you’ll never touch). Fish Stick sits in the sweet spot - does what you actually need without making you wade through (and pay for) features you don’t.

The interesting technical bit: it’s completely stateless. No database, no web UI, no OAuth dance. Slack is the database. Channel properties hold metadata, messages are the timeline, pinned messages are the summary. You can restart the bot whenever and lose nothing. Obviously there are some data durability and keeping-up-with-Slack-API tradeoffs there, but I think it works for this niche and use case. Design constraints for the win.

Check out the full writeup for details on features, architecture decisions, and setup. It’s MIT licensed on GitHub.

RageBlock

I built a Firefox extension that blocks mainstream news sites while keeping investigative journalism and wire services accessible. It’s called RageBlock.

I wanted it for myself.

I noticed that checking news sites made me feel worse without making me better informed. I’d feel anxious and angry, but I wouldn’t actually know anything more useful than I did before. The information-to-anxiety ratio was terrible. And I was often just opening them out of habit, like a nervous tic.

Cable news sites and major papers have optimized for clicks and engagement - and profit. That optimization twists facts toward grievance and keeps you in a constant state of low-grade anxiety. At least it does for me. Breaking news alerts. Live updates. The 24/7 outrage cycle.

Meanwhile, places like ProPublica and The Intercept do deep investigative reporting that matters. And wire services like AP and Reuters still do a pretty good job of reporting “just the facts”. There’s still plenty to be mad about, but less outright manipulation. They’re not trying to keep you glued to the screen refreshing every five minutes.

I still want to stay informed. I still want to read long-form investigative pieces that dig into how things work and why. I just want to skip the outrage porn.

I looked for existing tools. There are content blockers that get reasonably close, but they require you to build your own list or block things in big chunks. Apple’s parental and screen time controls are clunky. Nothing felt right.

So I made something closer to what I want: a curated list (still had to build it), some behavioral nudging, and some insight into my own patterns.

Blocked page view
Extension popup

RageBlock has an opinionated blocklist by default. It blocks 60+ sites: CNN, Fox News, MSNBC, NYT, WaPo, Reddit, Twitter, Facebook, Instagram, TikTok, and most news aggregators. Full domains, including all subdomains.

When you hit a blocked site, you see a message with alternatives. You can bypass for 5 minutes or until midnight if you need to check something specific. But the default is blocked.

The extension tracks your blocks and bypasses from the past week. If you’re bypassing too often, it shows reflection prompts. Gentle reminders to check in with yourself about why you’re doing this.

Building it

This was my first Firefox extension in a while. It’s mostly web dev as long as you’re not doing anything too crazy.

My initial attempt was to make it cross-browser, but I quickly discovered that the WebExtensions standard is a lie. Different APIs, different behaviors, different permissions models. So I punted and went Firefox-only since that’s my browser anyway.

Vibe coding worked reasonably well for this and I think this type of thing is actually a perfect fit for vibe coding. Most of it is boring scaffolding. I had to steer a few things: DRY this up, stop making this so complex, write tests that actually test the code instead of mocking the entire implementation.

The initial block list is basic. I’ll grow it over time as I figure out more things that make sense to block by default.

I debated adding local news sites. They’re generally terrible and subject to the same click-optimization as the major sites. Still deciding what I want to do there.

You might want this too

RageBlock is open source and available on GitHub. It’s MIT licensed. Do whatever you want with it.

It’s also on the Firefox AddOns store.

If you use Chrome, you’ll have to port it yourself. I’m not dealing with Manifest V3 right now.

And if you think the default blocklist is wrong, PRs are welcome, or fork it and make your own. That’s the point. Make the tools that work for you.

Showing Up & Goodbye WTFPod

I listened to the final episode of WTFPod on the way to Santa Fe last week (Airpods plugged in, daughter yelling along with Bluey from the seat behind me). It was the first time I’ve listened to a podcast in quite a while. The structure of my life (working from home, taking care of kids) doesn’t have as much room for them as it once did.

Marc Maron’s interview with Barack Obama ended up hitting close to home. Obama spoke about knowing your values and beliefs as being foundational for building connections and having meaningful conversations, which is something I’ve been thinking about a lot. The core of his point (and Maron chimed in as well) was that having that foundation lets you have difficult, meaningful conversations and there’s a vulnerability to earnestness that helps others listen.

They talked about in-person connection and what we’ve given up by adopting social media. How we see only narrow slices of people and not their contradictions or the unspoken goodness that might only show up in close proximity. I’ve been thinking about this a lot as well. Living in a suburban bubble, I’ve felt the weight of how few unmediated interactions I have anymore.

I know I need a community — and that I’d have something to give back, too. I’m not alone in this. I’ve read a dozen articles this year about how we’ve become an introverted society. Doing something about it is a whole other challenge.

It feels like a core leverage point. If we want things to get better, to live in a world that’s closer to our ideals, we’ve got to start talking to one another again - vulnerable, in-person, not hiding behind a screen. I haven’t gotten in an internet fight in a long time, but I haven’t engaged with the physical world much either. So I’ve got to change.

I found some meetups. Board games, nature walks, random stuff that is at least painless on the surface. So I’m forcing myself to show up. To talk, to listen, to try. If only so my kids see what trying looks like.

I wouldn’t say it was the best WTFPod episode ever, but it reminded me of Obama’s decency and why Maron has always appealed to me. The former made me sad. It was comforting in the moment, but wrapped up in loss as well. Decency is depressingly underrated.

Maron though… I think he’s wired into one of the ideals I’m striving for - to lead with vulnerability. It doesn’t have to be trauma dumping (although he’s done that from time to time), but he’s been a great example of seeing someone be open and enabling others to share that openness with him. I’ll miss his show for that. I wish more disaffected guys would have plugged into that energy instead of mainlining Joe Rogan.

Yeah, Rogan gave people a community, but it’s an aggrieved one that’s mostly defined by its contrarianism and devaluing of decency. There’s a weird vulnerability to the psychology of the manosphere that’s obvious from a distance. “Oh, this is for people who are hurting or empty in some way.” But the manosphere would never admit that.

A younger version of me would have rolled his eyes that I’m writing about decency and vulnerability being the building blocks for the world I want. Luckily, he grew up and knows how to admit he was wrong.

The robot learns to listen

ChatGPT and Claude have been my go-to model families for a while. I’ve tried others, they’re not as good. For the last several months, I’ve mostly used Claude for coding/dev work and ChatGPT for everything else: documentation, analysis, etc.

I’ve tried using GPT for coding a few times and am not impressed. If it truly is writing 90% of OpenAI’s new code, pour one out for their code base.

Claude Sonnet 4.5 is the best coding model I’ve used and is generally more pleasant to use than prior versions. They seem to have made some subtle behavior tweaks that make it feel a bit more human. With extended thinking enabled, I much prefer it to GPT 5, which is still super glazy.

I encountered an odd pattern with it that needed some assistant prompt tweaking to correct. In prior iterations, when I asked Claude “are you sure?” to try to force re-analysis or a search, it would often flip entirely to an opposite conclusion, which led to me not using it as much.

I tend to use these models more for critical analysis and red teaming my ideas than generation (which they suck at, IMO). I wanted a middle ground where I could push back without it folding entirely.

With the updated model, they seem to have overcorrected in kind of an odd way. When I asked “are you sure?”, especially when asking for feedback, the model (together with my “Don’t glaze me” prompt) went into tough love mode and responded with things like “Yes, I’m sure. Stop trying to pick apart this idea and go ship your blog post.” or something to that affect.

“Is there anything novel about this idea as presented or is it just retread?” would get me “Quit asking me to validate you. You know you’re good. Just ship it.”

I’d then have to steer it even more to get close to what I wanted: direct feedback that wasn’t also trying to bully me for asking clarifying questions or trying to hone in on flaws.

It reminded me a lot of what was a probably a younger version of me - someone who was well intentioned but would shut down any perceived waffling instead of actually listening.

So I ended up with this prompt:

Be direct and honest - no glazing. But respond like a trusted peer who’s emotionally intelligent. Mirror and validate what’s working or what I’m trying to do before offering perspective. Be collaborative rather than corrective. Acknowledge the effort and intention, then steer if needed.

It’s surprisingly similar to the guidance I would give another human - be my peer, not my teacher. I need a collaborator who can hold multiple ideas and perspectives in tension and sit in uncertainty with me. That’s an area I’d love to see more tuning around. Expert systems and tools are nice and all, but I want a thought partner.

Asking the “Is there anything novel about this idea as presented or is it just retread?” question now gets me responses more like:

“X is pretty well trodden, nothing new there, but Y is a more uncommon take. Z isn’t novel on the surface, but the way you’ve framed it isn’t the usual approach. You might dig in more there.”

Good job, robot. 🤘

Selective pain

I started my back piece over a year ago, a mosaic of mandalas, necker cubes, and pseudo-sacred geometry in black and grey. Since then, I’ve gone to my artist every month to get stabbed for 3.5-4.5 hours at a time - around 50 hours under the needle so far. I’ve got another 10 hours or so to go.

I’m ready for it to be over, I think.

This isn’t my first tattoo. I have five others, all decent size. None of them have affected me like this one though. I’m not proud of any of them like I am of this one.

Everything before this was done in one or two sessions. They didn’t cost anything other than money. This one has at times drained me and filled me up.

The needle stings until about the 30 minute mark. At that point the body is flooded with adrenaline and endorphins. Some of the edge goes away. You settle in to the rhythm of the process. There have been sessions where I’ve almost dozed off.

When the endorphins start to wear off, the pain comes back hard. My wall is usually at about 4 hours. It takes a lot of focused breathing to get much past that.

There have been a few sessions where the drugs my body makes weren’t powerful enough to help much at all. Over the ribs, the kidneys. My lower back in general is surprisingly sensitive. At times the needle felt more like a scalpel. Those sessions were hours of misery.

But it was worth it. It’s one thing to endure pain you can’t walk away from. Kidney stones, broken bones, trauma. Those teach survival. You gain something else from selective pain: discipline, a more concrete sense of where your limits are when you could walk away, how much control you have - your agency.

I don’t enjoy pain, but I feel like I learn a lot about myself from it, and I recognize the weird privilege I have to be able to opt in. I’ve learned that I am way tougher than I give myself credit for and can push myself deep into discomfort and choose to sit with it peacefully for a long time.

This is also the first tattoo I’ve got since learning that I am autistic and finally understanding how deep touch affects me, how grounding it is, even though light touch can drive me bonkers. I’ve become more comfortable with how I’m wired going through the process, more forgiving of how I’m affected by the world I live in. I give myself more grace. It sounds so stupid to my ear, but it’s real that someone can hurt you and heal you at the same time.

I don’t know that we’re friends, but the artist and I have a relationship at this point. It’s hard not to when you spend that much time with someone else. It’s strangely intimate. We share the same birthday, a year apart. We know each other’s kids’ names, ages, personalities. She’s tattooed my wife.

It’s always funny when people ask me what one of my tattoos means. For me, they don’t mean anything. They’re just the physical mark that’s left at the end of the process. Something to help you remember being tattooed.

I said I thought I was ready for this to be over and that’s true. I think I’ve learned about all I’m going to learn from this piece.

Which means I’m already planning another.