Features Don't Compose
I'd been circling something for weeks. Building toward it without being able to name it. You know the feeling — you sense the shape of an idea, you're making decisions that point toward it, but you can't articulate 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.
But those compound commands were just compositions of simpler operations. coverage was really list + get + compare to docs. audit was snapshot + diff. Every "feature" decomposed into the same five primitives.
So I deleted the features. Kept the primitives:
openpkg list ./src/index.ts # list exportsopenpkg get ./src/index.ts foo # single export detailsopenpkg snapshot ./src/index.ts # full spec JSONopenpkg diff old.json new.json # compare specsopenpkg docs spec.json # generate markdown
Five commands. Everything else is composition.
The article had a test: "To change behavior, do you edit prose or refactor code?" If the answer is refactor code, you've bundled logic that belongs in prompts.
I started thinking about it like gardening. I was trying to build flowers — specific features, specific outcomes. What I should be doing is cultivating the environment where flowers can grow. Build the primitives. Let the prompts do the composing.
This realization hit harder when I looked at another project I'd been building on top of openpkg. A lot of complex logic. A lot of features encoded in code. Turns out, everything it did could be achieved by composing the primitives I already had — with prompts, not code.
More on that soon.