When I wrote the first version of Shikomi last December, I described it as “not groundbreaking technology.” It was a script that asked you questions and generated other scripts. Useful, but humble.
Six months later I gave a talk about it at the Concord Software Developers meetup, and the project is genuinely unrecognizable from where it started. This post is an attempt to trace how that happened.
Where We Left Off
At the rebrand in December, Shikomi was an interactive wizard: run shikomi, answer some questions, get a project scaffold. The core components were a script generator, a bump-version utility, and a security setup tool for existing repos. It worked. It saved me time. That was enough.
Then I started using it every day.
The Features You Don’t Know You Need
January — Template expansion and logging
The first thing that became obvious in practice was that not all macOS admin scripts are the same shape. Jamf Pro Extension Attributes are a specific format: they run on the device, collect a single value, and print it wrapped in <result></result> tags. They don’t take parameters. They don’t log to a file. Treating them the same as a policy script was wrong. So Shikomi grew a --template ea flag and a dedicated Extension Attribute template.
January also brought built-in logging functions — log(), log_warn(), log_error(), log_success() — baked into every generated script. Not because every script needs elaborate logging, but because writing echo "$(date): Something happened" for the fiftieth time gets old, and having a consistent format makes log aggregation actually work.
January — 1Password integration
This one was driven by something I’d been uncomfortable with for a while: how do you handle secrets in scripts? The orthodox answer for Jamf is encrypted parameters, which are fine for values passed at policy execution time. But for scripts that need to pull credentials at runtime — API keys, tokens, service account passwords — you need somewhere to store them, and I wanted that somewhere to be 1Password. So the generator learned to ask how you want to store secrets and wire up the retrieval code accordingly. The script template changed from a placeholder comment to actual working 1Password CLI calls.
There’s an important caveat worth being upfront about: 1Password integration only works for scripts running locally or in local testing contexts. Scripts deployed and executed by Jamf Pro run under the management agent, not in an authenticated user session — so op CLI calls won’t have access to a signed-in 1Password account and will simply fail. If a script needs to handle secrets through Jamf, additional deployment considerations apply and the right approach will depend on your environment. The 1Password integration in Shikomi is genuinely useful, just not for that specific execution path.
March — GitHub Actions deployment
This is the one I’m most proud of, and also the one that took the longest to get right.
The idea is straightforward: when you merge a pull request that bumps a script’s version, that script gets automatically deployed to Jamf Pro. No manual upload. No “did someone forget to push this?” The git history is the source of truth, and the deployment follows from the commit.
Getting it right in a monorepo context — where you might have fifteen scripts and you only want to deploy the ones that changed — took several iterations. The final implementation detects which versioned scripts were modified in the PR, extracts their metadata from the script header, and runs a targeted deploy for each one via the Jamf Pro API. The deploy workflow is optional, but when it’s set up, the GitOps loop is complete.
March — Modular architecture
By the time deploy workflows landed, shikomi.sh was 1,320 lines. I extracted it into six library files: templates.sh, readme.sh, docs.sh, workflows.sh, git-setup.sh, and collection.sh. The main script dropped to a ~570-line orchestrator. This made testing specific functions possible and fixed a latent portability problem — the monolithic script had GNU sed assumptions that don’t hold on stock macOS. The library refactoring gave me the excuse to rewrite those parts with awk.
March — Non-interactive mode and Claude Code integration
The interactive wizard was fine for human use, but I wanted to be able to call Shikomi from other tools without babysitting it. The --auto flag arrived, along with twelve other CLI flags covering everything the wizard previously asked.
Around the same time, I added Claude Code integration: when you pass --claude y, Shikomi generates a CLAUDE.md and SESSION_DIARY.md alongside your script. If you’re using Claude Code as an AI pair programmer — which I do regularly for these scripts — having a structured project context file means the AI understands the script’s purpose, parameters, and versioning conventions from the first message. You’re not re-explaining the project setup every session.
April — System-wide bump-version
A minor but important change: I removed per-repo copies of bump-version.sh in favor of the system-installed command. I had fourteen repositories with their own copies and they were already diverging. The system-installed version is the single source of truth now.
What Shikomi Looks Like Today
Running shikomi with full flags looks like this:
shikomi my_script --auto --claude y --hooks enhanced --workflow y --deploy-workflow y --github y
You get a complete project: version-controlled script with semantic versioning headers, README and CHANGELOG, two-tier pre-commit hooks, a GitHub Actions PR workflow, an optional Jamf Pro deploy workflow, and Claude Code context files. In seconds.
The bump-version tool has kept pace:
bump-version patch "Fixed the permission check on Big Sur"
bump-version minor "Added retry logic for network operations" --commit
One command updates the version in the script header, the README, the CHANGELOG, and any munkipkg PackageInfo files — then optionally commits everything. The consistency problem I was fighting before Shikomi doesn’t exist anymore.
The Concord Software Developers Meetup
On May 14th I gave a talk about Shikomi at the Concord Software Developers meetup. It was my first time presenting something like this outside of an IT-specific audience, and I had to think carefully about what’s interesting to a general software developer versus what’s interesting to a macOS admin.
The answer I landed on: the interesting part isn’t the MDM integration. It’s the pattern.
Shikomi is fundamentally a tool that enforces a discipline. It says: every project, no matter how small, gets versioning, documentation, and secrets protection from the first commit. That’s not an MDM-specific idea. That’s a software idea. The specific implementation happens to involve Jamf Pro and Extension Attributes because that’s the domain, but the underlying problem — how do you build good habits into a workflow that usually skips them — is universal.
I walked through the evolution of the tool: why I built it, what I got wrong first, how the architecture changed as the requirements became clearer, and what the CI/CD deployment workflow actually looks like end-to-end. The slides and notes are available here.
What’s Next
I have a workshop accepted at MacAdmins in July — three and a half hours, hands-on. That’s the near-term deadline I’m working toward. Between now and July I want to build a proper test harness for Shikomi itself (the irony of a tool that enforces good practices not having its own tests is not lost on me), and document the things that were hard to figure out the first time.
After July, the roadmap includes a .shikomi.yml team configuration file to eliminate CLI flag fatigue, a shikomi init command for adding Shikomi to existing projects that predate it, and early exploration of MDM-agnostic mode — Intune, Kandji, and Mosyle support alongside Jamf.
The project is MIT licensed and on GitHub. If you’re an MDM admin and any of this sounds familiar, I’d be glad to have collaborators.