Contributing
This page is for people building imprnt itself. imprnt is open source under the MIT license.
The monorepo
Everything lives in one git repository: the core and every plugin, wired together with bun workspaces so one bun install sets up the whole thing and you develop it all side by side. At publish time the one repo splits into two package families.
imprnt packages/imprnt/ ingest, recall, check, plus init, snapshot, hot, context, and plugin. One install gives two commands, imprnt for machinery and imp for humans, served by a single program.
imprnt-plugin-* packages/plugin-*/ every plugin ships on its own. The naming convention matches the shape ESLint uses, so anyone can publish a plugin without joining an npm org. The core never imports or depends on one (the one place it names them is a short list of hints so imprnt plugin list can suggest official plugins).
bun installbun run build # compile each packagebun run test # test all packagesbun run check # typecheck + test + buildShip Node, build with Bun
What a user installs runs on Node, the runtime everyone already has, so npm i -g imprnt works without making anyone install Bun first. A code plugin compiles the same way, so running plugin code needs only Node too.
bun build --target=node makes one self-contained file npm i -g works Generic ships, personal stays private
- the generic plugin gallery
- Scribe, the default character you copy
- the universal anti-slop core
- your edited copy of a gallery plugin
- your own character and house style
- anything in plugins/_personal/
To personalize, copy a gallery plugin into _personal/, edit it, and wire the local file directly.
Releasing
imprnt publishes to npm on two dist-tags: named pointers that tell npm which version of the one imprnt package to install.
| Channel | Install | What it is |
|---|---|---|
latest | npm i -g imprnt | Stable. What a normal user gets. Promoted deliberately. |
edge | npm i -g imprnt@edge | Every push to master. May be rough. |
Every package versions independently. Turborepo’s --affected works out which packages a change actually touched, so a package whose files did not change is never republished. A core installed from edge pulls its plugins from edge too, so the newest core gets exercised against the newest plugins automatically.
All publishing runs through one GitHub Actions workflow with two paths:
push to master edge: affected packages @edge automatic run publish.yml mode=release latest: affected since release @latest pauses for human approval, then tag + GitHub Release Three safeguards sit on that workflow:
The workflow signs in to npm with OIDC: GitHub proves which repository and workflow is publishing, run by run, so there is no long-lived token to steal.
Every published package carries a signed public record of the exact commit and workflow that built it.
A stable release pauses at a GitHub Environment until a required reviewer clicks approve. Nothing automated reaches latest on its own.
Trusted publishing is configured once per package on npmjs.com.
To cut a stable release, use the imprnt-release skill (it fires the workflow and reports), or run it by hand:
# fire the release, then approve the npm-production gategh workflow run publish.yml -f mode=release
# plan only, publishes nothinggh workflow run publish.yml -f mode=release -f dry_run=truenpm only allows a full unpublish within 72 hours, so for a normal release you cannot count on it. To undo a bad latest, point the tag back to the last good version and deprecate the bad one:
npm dist-tag add imprnt@<last-good> latestnpm deprecate imprnt@<bad> "broken release, use <last-good>"