Higher-Order Skills
That concept you learned and then probably forget from your Lisp class is still important.
warning: this is a very coding/software heavy post
There’s a programming truism that sounds like a Zen koan if you say it the right way: map is a function that takes a function. Roll the words around. It’s not weird until you realize most things in life aren’t like that. You don’t usually hand someone a recipe and ask them back for a different recipe. You hand them a recipe, and you ask for cake.
But the trick of higher-order functions — the small, almost rude maneuver of treating code itself as the raw material — is one of those moves that, once you see it, starts showing up everywhere you didn’t expect. Decorators. Middleware. map, filter, reduce. Currying. Every framework that ever asked you to pass in a callback. It’s a difference stance on how to build, moving away from an authoritarian dictate of the exact steps and moving towards a bunch of legos that can be combined.
I think skills — the little markdown-and-prompt bundles that have become the dominant unit of “thing the model knows how to do repeatedly” — can have a much higher ceiling, just like coding does, when you make skills that work on skills: Higher-order skills. And the gap between the two shapes of composition, the two ways you might think you’re combining skills, is the difference between getting cake and getting recipes for better cake.
Two expressions, almost the same
Here’s the whole setup, in code, about an outer and an inner function.
outer(inner(x))
outer(inner)(x)
Squint and they look like the same thing. The parens are just in different places, like a typo. But they do completely different work, and languages have entire features built around marking which one you mean.
outer(inner(x)) is the easy one. You compute inner(x) — that’s a value. You hand the value to outer. It’s a pipeline. Data flows left to right, each stage staring at the back of the head of the stage in front of it. outer has no idea what inner was, what tools it used, whether it tried six times before succeeding, whether it had a bad day. outer sees the output. It works with the residue. Verb one gets noun 1, changes it to noun 2, then verb 2 gets noun 2, and turns it into noun 3.
outer(inner)(x) is the strange one. outer doesn’t get a value — it gets inner itself, the whole function, its name, its body, its tools, the comments inside it. outer does something with this — wraps it, modifies it, memoizes it, decides not to call it at all — and returns a new function. That new function gets x. You haven’t run anything yet at the moment outer(inner) evaluates. You’ve manufactured a new tool. The tool runs when (x) finally lands.
Higher-order functions are like adverbs. They don’t take a noun and give you a new noun. They take a verb and give you a new verb:
“carefully bake a cake” → (carefully bake) (a cake).
“eat a baked cake” → eat (whatever comes out of (bake(a cake))
What this looks like for skills
I keep half a dozen skills in my Claude Code setup that I use most days. /weekly-report. /meeting-prep. /draft-email-decline. /concept-audit. They’re little crystallized routines — context loaded, voice tuned, output shape baked in. When one isn’t quite right, the temptation is to compose: run the skill, then run another skill on its output to fix what was off.
That’s outer(inner(x)). It works. It’s also kind of limited.
Imagine I want my weekly report rewritten for a less-technical audience. The nested move is: run /weekly-report, get a tight engineering-flavored document, then run /rewrite-for-business-audience on that document. Two skill invocations. Two LLM passes. The second one is reading prose that was written for the wrong audience and trying to launder it into prose for the right one — like translating English into French and back into English to “improve” it. Some signal survives. Some doesn’t. And the second pass has no idea what the first pass was trying to say. It only sees what came out.
The higher-order move is different. It says: don’t post-process the output, modify the skill. Hand /weekly-report to a wrapper — call it /for-audience — that injects “your reader is a non-technical exec; emphasize impact, defer detail” into the inner skill’s prompt before it ever runs. The inner skill generates in the right voice from the start. One pass. No translation residue. The audience instruction shaped generation, not the artifact.
outer(inner)(x) instead of outer(inner(x)). Same letters. Different world.
The skills you can’t write any other way
The audience-rewriter is a soft case — you can fake it with nesting if you don’t mind the extra compute. The interesting higher-order skills are the ones you cannot simulate with nesting at all, because they need to modify the inner skill’s machinery, not its output.
/sandbox <skill> — run any skill with its write tools stripped out. A dry-run wrapper. You can’t take tools away from a skill after it’s run; by then the writes have already happened. The wrapper has to intercept the skill’s tool list before execution. There is no nested version of this. The post-processing pass doesn’t have a time machine.
/best-of-n <n> <skill> — run the inner skill n times, with varied temperature or prompt seeds, and return the one you like best. Nesting can’t do this because nesting only ever sees one output. It cannot regenerate. The wrapper has to be holding the inner skill itself to call it repeatedly.
/with-context <docs> <skill> — load specific documents into the inner skill’s context before it runs. The skill reasons over the docs while generating, instead of being handed a summary after the fact and asked to incorporate it retroactively. Reasoning-with is not the same as reasoning-about, and the difference is the entire point.
/audit <skill> — wrap any skill so every intermediate tool call, every chain-of-thought, every detour gets logged. You’re not transforming the final output; you’re tapping into the process. Nesting has no access to process. It only sees the artifact.
/parallel <skill_a> <skill_b> <skill_c> <x> — run three skills against the same input concurrently, then merge their outputs with some reconciliation logic. The wrapper takes a list of skills and produces a new skill. This is map for skills, almost literally — and the moment you have it, you have fan-out/fan-in, ensembling, debate-style critique loops, all the patterns that ML researchers have spent the last two years rediscovering one paper at a time.
You can keep going. Caching wrappers. Retry wrappers. Permission-elevating wrappers. Wrappers that swap the underlying model (cheap pass for drafts, expensive pass for finals). Wrappers that re-route the inner skill’s tool calls through a proxy that redacts PII before they hit a third-party API. Every one of these is a thing you can build with higher-order skills and cannot build with nested ones, because nested ones only see what comes out.
What gets layered on
There’s a habit of thought I’d offer here, which is to stop reading nested invocations as composition and start reading them as pipelining. Pipelines move data. They do not modify the machines that produced the data.
Higher-order composition is a different verb. It modifies the machine. It’s why decorators in Python aren’t really “wrapping the result” — they’re producing a new function that the runtime then calls. It’s why middleware in a web framework isn’t post-processing your handler’s response — it’s installing scaffolding around your handler before the request ever arrives. The wrapping happens at the layer of the tool, not the trace. At a higher order.
Skills, right now, are mostly built as machines that get pointed at inputs. The interesting next layer is the one where skills become things you can pass around — first-class arguments to other skills, the way functions became first-class arguments to other functions in the 1960s and somehow kept being a revelation for the next forty years.
When you can do that, the meta-layer opens up. Sandboxing. Best-of-n. Audit. Audience lenses. Cost lenses. Capability lenses. All of them are outer(inner)(x), not outer(inner(x)). The gap between those two shapes of parenthesis is, it turns out, the gap between I made a tool and I made a tool for making tools.
Once you have done the inner step, like baking a cake, you can only eat, share, trash the cake. You cannot un-bake the cake. You cannot bake it differently. But if you can change the recipe (make it spicier, make it sweeter, make it in a fire instead of an oven), you open up a lot more.

