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:

Terminal window
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 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.