Skip to content

feat: add pi package publishing to release workflow - #62

Merged
itayinbarr merged 7 commits into
itayinbarr:mainfrom
dbmrq:feat/pi-package-publishing
Sep 18, 2026
Merged

itayinbarr merged 7 commits into
itayinbarr:mainfrom
dbmrq:feat/pi-package-publishing

Conversation

@dbmrq

@dbmrq dbmrq commented Jun 28, 2026 •

Copy link
Copy Markdown
Contributor

Summary

Adds automatic publishing of a pi package (pi-little-coder) alongside the main little-coder npm package on tagged releases.

Changes

  • scripts/build-pi-package.mjs: Builds a pi-compatible package from the little-coder source tree. Auto-discovers extensions from .pi/extensions/*/index.ts at build time (mirrors how the launcher discovers them), removing the risk of shipping a stale set. Explicit exclusion list documents what doesn't ship and why.
  • scripts/build-pi-package.test.mjs: Smoke test that verifies the build produces a loadable package (valid package.json, all extension dirs present, README present).
  • .github/workflows/publish.yml: Adds publish-pi-package job that runs after the main publish job.
  • package.json: Added build:pi-package npm script, postinstall script.
  • .gitignore: Added dist/ to ignore build artifacts.

What the pi package includes

28 extensions (auto-discovered, excluding 6 little-coder/benchmark-specific ones), 3 skill categories, plus _shared utility module.

Excluded extensions (with rationale):

  • branding — little-coder-specific TUI branding
  • llama-cpp-provider is included (needed by phase-model → plan-mode chain)
  • benchmark-profiles, evidence, evidence-compact — GAIA benchmark-specific
  • hello — example/test extension
  • browser-extract-retention — depends on excluded evidence

How it works

When a version tag is pushed (e.g., v1.19.0):

  1. Main publish job publishes little-coder to npm
  2. New publish-pi-package job builds the pi package from source
  3. Publishes pi-little-coder@1.19.0 to npm with provenance

For users

Vanilla pi users can now do:

npm install pi-little-coder

What's NOT included (behavioral differences)

This is a curated subset of the extension layer, NOT little-coder-in-a-box. The following behaviors come from patching pi itself or from launcher-level code and are not shipped:

  • scripts/patch-pi.mjs re-applies source edits on launch (e.g. suppressing the "Operation aborted" marker)
  • --no-extensions plus explicit extension load order
  • Global settings merge (quietStartup, lastChangelogVersion)
  • llama.cpp context re-probe on startup
  • Update check wiring

See the generated README for full details.


Closes the draft PR after rebasing on main (v1.19.0) and implementing all requested changes from review.

@dbmrq
dbmrq marked this pull request as draft June 28, 2026 21:28
@dbmrq

dbmrq commented Jun 28, 2026 •

Copy link
Copy Markdown
Contributor Author

This PR clearly wasn't ready to be published yet, but little-coder did it by itself. 😂

I marked it as a draft, but the idea would be to also publish the little-coder extensions and skill system (minus benchmarking stuff) as a regular pi package. I know little-coder goes beyond this, but I still think many of the additional extensions would be valuable for pi independently, and it would be convenient to be able to install them with something pi install little-coder. What do you think of this idea, @itayinbarr ?

@itayinbarr

Copy link
Copy Markdown
Owner

Ha — I love that little-coder shipped its own PR by itself 😄.

And I like the idea a lot. A good chunk of these extensions — read-guard, evidence, thinking-budget, tool-gating, plan-mode, the skill-inject/knowledge-inject system — are genuinely useful to vanilla pi users independent of the small-local-model angle, and pi install <something> would be a clean way to get them. Happy to see this move forward.

If you want to take it further, here's what I'd want before merging:

  • Naming + scope. A distinct package name (e.g. pi-little-coder), and an explicit, documented allowlist of what ships. Your PI_PACKAGE_EXTENSIONS list is a good start — but some clearly don't belong (branding, llama-cpp-provider, and anything benchmark-related are little-coder-runtime-specific, not general pi value).
  • Sync strategy. The build copies from .pi/extensions/ at publish time, so the pi-package needs to track the main version and there should be a note in the release flow so it doesn't silently drift. A small test that the build produces a loadable package would go a long way.

One important caveat to set expectations, and it's the crux: not everything little-coder does is "just an extension." Several load-bearing behaviors are applied by adapting pi itself, not by adding extensions on top:

  • scripts/patch-pi.mjs re-applies source edits to the installed pi on every launch (e.g. suppressing pi's bare "Operation aborted" marker). That's patching pi, not extending it.
  • Launcher-level wiring — --no-extensions plus an explicit load order, the global-settings merge (quietStartup, pinning lastChangelogVersion), the update flow, the llama.cpp context re-probe — lives in bin/, not in any extension.

None of that comes along in a pi install package. So what you'd be shipping is a curated subset of the extension layer, not little-coder-in-a-box — and the two will behave differently in places precisely because the wrapper/patch layer isn't there. Worth calling that out plainly in the package README so users aren't surprised when, say, an aborted-run marker shows up or startup is chattier than it is under little-coder.

If you're up for it, finish it along those lines and un-draft when it's ready — I'll review properly. Thanks for pushing on this one.

@itayinbarr

Copy link
Copy Markdown
Owner

Checking in on this one since it has been sitting in draft for a while. It now conflicts with main, which is not surprising given how much has moved: the extension set has grown well past the 23 this script enumerates, and bin/little-coder.mjs has changed shape underneath it.

I still like the idea. A little-coder-pi package that vanilla pi users can install to pick up the extensions and skills is a genuinely good distribution channel, and it is a thing I would not have built myself.

Two things would need settling before I merge it, and both are more about maintenance than code:

  1. The extension list has to be derived, not enumerated. A hardcoded list silently ships a stale set the first time someone adds an extension and forgets the script. Reading .pi/extensions/*/index.ts at build time, the same way the launcher discovers them, removes that failure mode entirely.
  2. The two packages will drift. little-coder pins its own pi version and patches the runtime at launch, which the pi package cannot do. Some extensions will therefore work differently, or not at all, outside the launcher. That needs to be stated in the pi package's README rather than discovered by a user.

If you want to rebase and address those, I will review it properly. If you would rather not, say so and I will close it as a good idea nobody has time for right now, with no hard feelings.

@dbmrq

dbmrq commented Aug 22, 2026 via email

Copy link
Copy Markdown
Contributor Author

- Add scripts/build-pi-package.mjs to build little-coder-pi package from source
- Add build:pi-package npm script for local builds
- Add publish-pi-package job to GitHub Actions workflow
- Package includes 23 extensions and 3 skill categories
- Published as little-coder-pi to npm on tagged releases
Remove duplicate entries and ensure only generally-useful extensions are included.
Excludes: benchmark-profiles, branding, clear-command, hello, llama-cpp-provider,
shortcuts-help, turn-cap (little-coder/benchmark specific)
The build script now removes *.test.ts files after copying extensions,
so they don't get loaded as invalid extensions by pi.
…d test

- Auto-discover extensions from .pi/extensions/*/index.ts at build time,
  removing the hardcoded list that silently ships a stale set.
  Explicit exclusion list documents what doesn't ship and why.
- Rename package from little-coder-pi to pi-little-coder.
- Update pi dependency versions to ^0.83.0 to match main.
- README documents this is a curated extension subset, NOT little-coder-in-a-box.
  Explains that launcher-level wiring (patch-pi.mjs, --no-extensions load
  order, global-settings merge, llama.cpp re-probe) is not shipped.
- Add smoke test verifying the build produces a loadable package
  (valid package.json, all extension dirs present, README present).
@dbmrq
dbmrq force-pushed the feat/pi-package-publishing branch from 7d7c9d4 to b80d7a8 Compare September 2, 2026 22:14
@dbmrq
dbmrq marked this pull request as ready for review September 2, 2026 22:15
@dbmrq

dbmrq commented Sep 2, 2026

Copy link
Copy Markdown
Contributor Author

@itayinbarr Ok, I asked the robots to work on this and it appears that they did a decent job, although this isn't my area of expertise. Please let me know what you think!

@dbmrq

dbmrq commented Sep 16, 2026

Copy link
Copy Markdown
Contributor Author

@itayinbarr, bumping this for when you have the time :)

@itayinbarr
itayinbarr merged commit cb10cfc into itayinbarr:main Sep 18, 2026
@itayinbarr

Copy link
Copy Markdown
Owner

Merged in v1.20.0, and pi-little-coder@1.20.0 publishes with this release. Thank you for coming back to it twice, including the time you did not have.

Both of my conditions are met. Extensions are derived from .pi/extensions/*/index.ts at build time rather than enumerated, and that paid for itself immediately: this release adds a project-context extension for #104, and the build picked it up on its own with no edit to your script. The drift failure mode is genuinely closed rather than merely documented. And the generated README states the divergence plainly, which is the thing a user will otherwise discover by being surprised.

Four changes I made before merging, so the record is clear about what is yours and what is mine:

  1. Dropped the postinstall. little-coder ships no npm install scripts on purpose. A postinstall was the one thing tripping Socket's AI malware scan (Malware #75), and it was already redundant, because /update and the launcher's self-update both install with --ignore-scripts so it never ran for anyone upgrading. applyPiPatches() is called from the launcher on every launch instead, which also means it patches wherever pi actually lives and self-heals if pi is reinstalled underneath.

  2. Reverted the formatting churn in publish.yml. The quote-style rewrite made a 30-line addition read as a 39-line diff. Your new job is now a pure append.

  3. Excluded project-context from the package. It exists only because little-coder launches pi with --no-context-files. Vanilla pi discovers AGENTS.md itself, so shipping it would inject a second copy of the same instructions. Good illustration of why the exclusion list needs a stated reason per entry rather than just a name, which yours already does.

  4. Fixed a real bug your work surfaced. skill-inject and knowledge-inject resolved skills/ by counting three directories up from the extension, which is right in this checkout (.pi/extensions/<name>/) and wrong in your layout (extensions/<name>/). Both loaders end in if (!existsSync(dir)) return;, so the package would have shipped 28 extensions with none of the skill content and nothing anywhere saying so. They search upward for the directory now, which is correct in both layouts. Nobody would have caught that from the outside, and it is exactly the kind of thing a package build is supposed to expose.

I also added the build's smoke test to the publish job, so a package that does not load fails the release rather than reaching npm.

For the record, since you opened this by pointing out that little-coder filed its own PR: it has now also reviewed and merged one. I am choosing not to think too hard about that.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants