Building tools that
I actually like :)

Plugins, recipes, and notes from me to you. have fun :)
01 plugin shipped
11 recipes published
03 posts written
// plugins
Things I've shipped
view all →
// recent recipes
From the cookbook
view all →
// blog
Field notes
view all →
plugins

Rock Plugins

Open source plugins for the Rock ChMS ecosystem. More in the pipeline.
1 plugin
recipes

Rock Recipes

Patterns, snippets, and the occasional bit of chaos. All live on the Rock community.
11 recipes
blog

Thoughts & Findings

No editorial calendar. Just things worth writing down from the Rock trenches.
3 posts
plugins / omni-lingua / v1.0.0 / user guide
/ blog
musings 4 min read

The country turned 250 and I've been thinking about milestones

The United States turned 250 last week, an anniversary with a name I have yet to hear a single person say out loud with confidence. Semiquincentennial. I watched the fireworks from a parking lot with family and lukewarm lemonade, and somewhere between the finale and the traffic jam I started thinking about round numbers.

249 got nothing

Last year the country turned 249 and I remember nothing about it. Same country, same founding, one year less of it. The difference between an ordinary July and a historic one turns out to be arithmetic in base ten. We are pattern-loving creatures, and a number with a zero or a five on the end reads as a landmark while its neighbors read as filler.

You can decide that makes milestones meaningless. The number is arbitrary, the calendar is a convention, and the republic did not become more of anything at midnight. I spent a few days in that camp.

What a milestone actually does

Watching a whole country pause at the same time moved me out of it. A milestone doesn't hold meaning the way a box holds contents. It works more like a mirror someone hung in the hallway: there is nothing in it until you stop and look, and then suddenly there is everything. The 250 didn't change the country. It made a few hundred million people glance at the same mirror during the same week, and that shared glance is a real thing regardless of what anyone sees in it.

I notice the same mechanism at church all the time. A congregation turns one hundred and suddenly people who never talk about the past are telling founding stories in the lobby. A couple hits fifty years and four generations show up with a cake. Nothing changed on the actual day. Everything the milestone celebrates was already true the week before. The marker just gave everyone permission to stop and say it out loud.

I spend my working hours in a database full of dates. First visit dates. Baptism dates. Wedding anniversaries. Rock will happily tell you that this Sunday marks somebody's tenth year since baptism, and the query that finds them treats the number ten exactly like the number nine. The significance is not in the data. It shows up when a pastor sees the report and makes a phone call, and the person on the other end realizes a decade has gone by and someone noticed.

A milestone is an empty container with good handles. It carries whatever you load into it: gratitude, grief, recommitment, a party. Left empty, it's just a number with a zero on the end.

The morning after

The 251st year started the next morning and looked exactly like the week before it. That used to strike me as evidence that the whole thing was theater. I've come around to the opposite reading: the looking was the point, and the ordinary morning after is the thing you were looking at. Countries, churches, careers, all of it runs on long stretches of unremarkable Tuesdays, and a milestone is the agreed-upon moment where you stand still long enough to see how far the Tuesdays have carried you.

My own numbers are smaller. A first recipe, a first plugin, a community point total I still check more often than I should admit. None of them round, most of them meaningful, because someone (usually me, at 11pm) stopped to look.

/ blog
findings 5 min read

VBS week: screams of joy, headcounts, and an fun check-in screen

VBS week ended three days ago and I am still finding labels everywhere. If you've never worked a Vacation Bible School, the best description I can offer is that it's summer camp compressed into three to five days, powered by fruit punch and volunteers (big emphasis on the volunteers, shoutout to them), and it is simultaneously the most fun and one of the more serious thing we do with Rock all year.

Why so serious?

For one week, several hundred parents hand us the people they love most in the world and drive away. That's the entire arrangement. Every fun thing that happens inside the building rests on a promise that when they come back at noon, we can account for every single child, know exactly which room each one is in, and release each one only to the right adult and in one piece.

Rock check-in is the backbone of that promise. Security codes on matching parent and child labels. Allergy flags printed where a volunteer will actually see them. Live attendance by room, so if a fire alarm goes off during snack time we know who is supposed to be standing on the lawn, by name, in about thirty seconds. None of this is glamorous and all of it is the actual product. The crafts are a delivery mechanism.

Every fun thing that happens inside the building rests on a promise.

The fun

Once the serious layer is solid, check-in becomes a place to play, because the kiosk screen is just a themed web page and themed web pages will do whatever you tell them.

My favorite discovery this year (I don't know why I didn't think of it before): the check-in theme takes a background image, and nothing anywhere says that image has to hold still. Point it at an animated GIF and the whole kiosk comes alive. We ran our VBS theme art with shooting stars, and kids started arguing over who got to press the buttons. A five-year-old fighting for the privilege of checking himself in is a level of engagement no lanyard ever produced.

A few practical notes if you try this. Keep the animation subtle, because a strobing background behind a search field helps nobody. Watch the file size, since a kiosk pulling a 40MB GIF over church Wi-Fi at 8am will teach you patience you did not ask for. And test on the actual kiosk too, not your laptop, because the aging iPad at the far entrance has opinions.

Thursday

By Thursday the volunteers were tired in the way you can only get from a week of VBS. Labels everywhere, every kid went home everyone was ready to get some rest.

/ blog
story 5 min read

Preparing my RX session is mostly deleting things

Two years ago I walked into a Rock Star meeting at RX by accident and was trapped in a corner with my friend so I stayed. To be honest I thought it was an additional session that was open to the public since it was my first year at RX. I was asked to consider speaking earlier in the year so I went ahead and figured with all I've gotten from RX it was time to give back. I've been preparing ever since, because the preparation turned out to be nothing like what I expected.

The brain dump was the easiest part

I opened a blank document and typed every single thing I could imagine sharing. Tricks. Check-in. Lava patterns I lean on weekly. SQL habits that have saved me. Lessons from the plugin. Not long after I had material for a six-part series and a small book, and I felt great about it.

That document was the last time this felt easy. Everything since has been subtraction.

Reading the room

A conference session is hard in a way a blog post is not, and the reason is the room. At RX, the person on the left aisle might be a volunteer coordinator who inherited the role three weeks ago. The person next to them might have been writing custom blocks since before we realized how bad that was hehe. They could both pick my session. They both gave will have given me the same time, time that could've been at another session, and they both deserve to walk out with something they can use.

Pitch everything at the beginner and the rock admins will start checking their email. Go deep on architecture and the new admins spend forty-five minutes politely lost. For a while I kept trying to build one talk that was secretly two talks, and every draft that tried to serve everyone equally ended up serving no one in particular.

They all deserve to walk out with something they can use.

Deleting my way to a talk

The version of the session I have now is maybe a fifth of the original brain dump. Getting there meant learning the test I now run against every slide: can most of this room do something with this on Monday morning? Not admire it. Use it. If the answer is no, the slide goes, no matter how proud I am of the thing it describes.

Some of the cuts hurt. Gone. At least for a moment.

Practice, Practice, Practice.

Now I need to make the thoughts real, and practice them. I'll bounce it off my coworkers, I'll bounce them off my wife, I'll even bounce it off my dog.

I'll write about the actual session after it happens.

/ blog
story 5 min read

From check-in to development

I worked in children's ministry. Not as a developer. Not even close. My entire relationship with Rock at the time was knowing which buttons to press on check-in Sunday so the right label printed and the right kid went home with the right family. That was the job. That was the whole thing.

I was good at it. Showed up early, kept the line moving, didn't panic when the printer jammed. Very normal staff stuff.

The label incident

Then I moved over to the membership department, and Rock stopped being a check-in screen and started being everything. Every workflow we touched, every report we ran, every list we pulled. All Rock. So I started spending more time in it.

Somewhere in that transition I made a mistake with a label template. I don't remember the exact details of what I changed, but the result was labels printing wrong, wrong layout, wrong fields in the wrong places. Something was off in the ZPL and I had caused it.

The sensible thing would have been to flag it and let someone else fix it. I did not do the sensible thing. I decided I was going to fix it myself.

I knew nothing about ZPL. I had never heard of ZPL. ZPL is the programming language Zebra label printers use, and it is not something you just pick up in an afternoon. But I sat down with it anyway, started reading, started trying things. Most of them didn't work. I tried more things. Eight hours later I had fixed the label.

Eight hours. For a label template. I was not going to let it beat me.

That's the thing about those moments. You don't realize they're turning points while they're happening. You just think you're being stubborn about a printer problem.

One week, fully sucked in

What those eight hours actually taught me had nothing to do with ZPL. The point was that I discovered something about how I work: I will chase an "aha" moment for an unreasonable amount of time, and it doesn't feel like work. It feels like a puzzle. Something that can be solved if I just keep going.

That was on a Monday. By the following Monday I had read the entire Rock admin hero guide, watched every Master Class video I could find, mapped half of the data model in my head, and was writing my first Lava templates. I have no other way to describe that week except that I got sucked in. Every time I learned one thing, three other things I didn't know about poked their heads up to be learned next.

Master Class lit the fire. I had no business going that deep that fast (I wasn't even on the IT team), but the way the material was structured made the whole stack feel knowable instead of intimidating. Lava, then SQL, then workflow actions, then Pre-HTML, then theme zones, then check-in configuration. I was making notes in margins. I was running test queries against a sandbox at midnight.

Accidentally crashing a Rock Star meeting

Then I went to RX. If you don't know what RX is, it's the annual Rock conference, the gathering of everyone who builds on or works in Rock. I went the first year I was eligible, mostly to soak it in.

And I ended up in a Rock Star meeting by accident.

I want to be transparent: I did not know it was a Rock Star meeting. I walked in. The door was open. People were sitting around. I sat down. And then I realized everyone in the room had earned the Rock Star title and I had not.

The polite thing would have been to slip out. I did try. I made what I think was a reasonable effort to leave and was, very kindly, told to stay. So I stayed.

What I heard in that room was an entire room of people who had built things in Rock that I didn't even know were possible. Plugins, integrations, gnarly migrations, custom blocks, crazy theme work. They were trading war stories and asking each other for help on problems I couldn't yet describe, let alone solve.

I left that meeting with one thought: I'm coming back next year and I'm earning that title for real.

What I learned the year after

Reader, I earned it.

The year between that accidentally-crashed meeting and the next RX was the most concentrated year of learning I've ever had. Started writing real Lava. Wrote my first SQL reports that actually held up. Started contributing recipes to the community. Got into Obsidian. Built things. Broke things. Fixed the things I broke. The Rock community point system kicked in around month three and that's a whole other post.

The gap between "power user" and "developer" is smaller than it looks from the outside. Rock is a good place to close that gap because you can do genuinely useful things at every level (Lava templates, SQL reports, workflow actions) before you ever have to write a line of C#. By the time I started on actual plugins, I already understood enough of the system that the C# wasn't the scary part. The scary part was deploying to production on a Sunday morning. Still is, if I'm honest.

No CS degree. No formal background. Just a label that printed wrong, a week of getting sucked in, a meeting I shouldn't have walked into, and enough late nights to eventually figure out what I was doing. Stubbornness dressed up as curiosity. It's served me pretty well.

/ blog
musings 4 min read

The Rock community point system is a trap (a good one)

I'm going to be transparent about something: I refreshed my Rock community profile at 11pm on a Tuesday to see if my points had gone up.

They had. By two. I was unreasonably pleased about this.

How it starts

The Rock community has a point system. You answer questions, share recipes, people like your contributions, you get points. Simple. And it is extremely effective at making you want more points.

I answered my first question because I actually knew the answer and thought I'd help. Reasonable, healthy motivation. Then I watched the notification appear. Then I checked whether anyone had upvoted it. Then I found another question I could answer while I was already there anyway, just because.

This is how it begins.

For the record: I have full awareness that I'm being lightly gamified. This does not stop it from working. Whoever designed this system understood something real about human psychology.

The thing is, it actually makes you better

Here's what I didn't expect: the point-chasing is mostly a red herring. The actual effect of answering questions on the Rock community is that you get really good at Rock.

When someone asks a question you don't fully know the answer to, you have two choices: move on, or figure it out. The points provide just enough silly motivation to push you toward figuring it out. And then you know something you didn't before. Then someone replies with a better approach and now you know two things. It compounds.

I've learned more from trying to write a clear answer to someone else's Lava question than I have from most formal documentation. You have to understand something well enough to explain it, which is a higher bar than just understanding it yourself. The points get you in the door. The learning is the actual reward.

The community is the real thing

The points are not actually why I keep coming back. The community is just good. People are generous with their knowledge, the tone is helpful rather than gatekeep-y, and there's a shared understanding that everyone is working toward the same general goal: churches running well, staff not losing their minds, ministry actually happening.

That shared purpose makes it feel different from a lot of tech spaces. Nobody is posturing. Nobody makes you feel bad for asking a beginner question. Everyone was a beginner at Rock once and most people seem to remember that.

The points are fun. The community is the real thing. The points just got me in the door fast enough to realize that.

(My current total is none of your business.)

/ blog
findings 6 min read

Building my first Rock plugin nearly broke me (and I'd do it again)

There were three separate nights where I was still at my computer past 3am, staring at an exception I didn't understand, wondering what I had done to deserve this.

This is the story of building the omniLingua plugin: a tool that lets churches translate any Rock page into another language. It was the most frustrating thing I'd built in Rock so far, and also the most satisfying. Writing it down while the details are still fresh.

Why I built it

We have Spanish-speaking families at our church who interact with Rock through public-facing pages: event registrations, group sign-ups, giving forms. All of it was in English. There was no clean built-in way to serve them in their language.

I'd already built the recipe version, which uses a Lava shortcode and a Defined Type to do client-side text swapping. It works, and it's on the Rock community if you want it now. But I wanted something cleaner. OWIN middleware for the server-side paint. A proper JS engine for live switching. A real admin UI instead of copy-pasting Pre-HTML on every registration page.

So I started down that road.

What I underestimated

The service container. Rock uses dependency injection throughout, and if you get the lifetime of a service wrong (say, you inject a scoped service into a singleton), you get an exception that tells you nothing useful on the surface. I spent the better part of an evening convinced my code was correct before I found a Stack Overflow post from 2019 that put the pieces together.

It was 1:30am. I read that post three times. Fixed one line. Rebuilt. It worked. I sat back and stared at the ceiling for a minute.

If you are hitting cryptic DI exceptions in Rock plugins: check your service lifetimes first. Scoped inside singleton equals a bad time. I say this as someone who lost significant sleep to this exact lesson.

The 3am problem

There's a version of late-night coding that's actually productive. You're in flow, things are clicking, the world is quiet and you're just building. I had sessions like that.

Then there's the other kind, where you've been staring at the same bug for two hours, your brain stopped being useful an hour ago, and you keep trying variations of the same wrong approach hoping one of them will magically work. I had sessions like that too.

The honest lesson: the second kind is the problem. The first kind is fine. If you're productive late, go for it. But the moment you catch yourself copy-pasting the same broken code with slightly different spacing, close the laptop. I didn't always listen to that cue.

Every fix I found after sleeping was obvious. Every single one. Not one of them required me to be awake past midnight. I just had to not know that yet.

What I loved about it

All of that said, the frustration was real but so was the satisfaction on the other side. The first time I loaded a registration page and watched every English label flip to Spanish in real time, correctly, without any visible delay. That was a genuinely great moment.

Building a plugin forces you to understand Rock at a different level than recipes or Lava ever will. You're inside the framework. You're looking at how blocks work, how the service layer is structured, how OWIN middleware intercepts responses. That context makes you better at everything else in Rock, even the surface-level stuff.

The plugin isn't live yet, still polishing before the public release. When it drops, it'll be worth the sleep debt. Probably.