Features Don't Compose

I'd been circling something for weeks. Building toward it without being able to name it. You know that feeling where every decision you make points the same direction but you couldn't tell someone why.

Then I read "Agent-Native Architecture" and it clicked.

"Tools should be atomic primitives. Features are outcomes achieved by an agent operating in a loop."

OpenPKG had compound commands: coverage, audit, report. Feature-rich, helpful defaults, the kind of CLI developers expect. The kind I expect, honestly.

But those compound commands were just simpler operations glued together. coverage was really list + get + compare against docs. audit was snapshot + diff. Every "feature" decomposed into the same five primitives, every single one.

So I deleted the features. Kept the primitives:

Terminal
openpkg list ./src/index.ts # list exports
openpkg get ./src/index.ts foo # single export details
openpkg snapshot ./src/index.ts # full spec JSON
openpkg diff old.json new.json # compare specs
openpkg docs spec.json # generate markdown

Five commands. Everything else is composition.

The article has a test I keep coming back to: to change behavior, do you edit prose or refactor code? If the answer is refactor code you've bundled logic that belonged in prompts.

I keep thinking about it like gardening. I was trying to build flowers, specific features, specific outcomes. What I shouldve been doing is growing the environment flowers come out of. Build the primitives, let the prompts do the composing.

This hit harder when I looked at another project I'd built on top of openpkg. Lots of logic, lots of features encoded in code. Turns out everything it did could be done by composing the primitives I already had, with prompts, not code.

More on that soon.