feat(release): publish forge-core, forge-skills, forge-plugins as Go library modules#153
Merged
Merged
Conversation
…libraries External consumers (e.g. the Initializ platform) need to embed the agent runtime as a library, not shell out to the CLI: go get github.com/initializ/forge/forge-core@v0.15.0 Today that fails. The library modules cross-reference each other via `replace ../forge-skills` (and `v0.0.0` placeholder require lines) which is correct for workspace-mode local dev but unusable for a Go module proxy fetch. The Initializ build sees `replace ../forge-skills`, can't find the local path, and fails. Path-prefixed Git tags are the standard Go multi-module convention for this — `forge-skills/vX.Y.Z`, `forge-core/vX.Y.Z`, `forge-plugins/vX.Y.Z` per release. But pointing those tags directly at the binary-release commit would publish the broken go.mod files verbatim. Need a tagged tree where `replace` is dropped and `require` references real sibling versions. This commit adds the "ephemeral release commit" pattern: 1. scripts/release/tag-libraries.sh — runs `go mod edit` on a detached worktree of the binary-release tag to drop `replace` directives and bump `require` lines to the new version. Commits the result as a throwaway commit (one parent = the binary tag, never merged to main). Tags forge-core/vX.Y.Z and forge-plugins/vX.Y.Z at that ephemeral commit; tags forge-skills/vX.Y.Z at the binary commit directly (leaf module, no rewrite needed). Pushes all three. 2. .github/workflows/release.yaml — new `library-tags` job that runs the script after goreleaser succeeds. Uses GITHUB_TOKEN and the workflow's `contents: write` permission to push tags. 3. docs/reference/library-modules.md — full reference covering the three importable modules + their roles, the path-prefixed tag scheme, the ephemeral-commit mechanism with an ASCII diagram, the versioning policy (unified during v0.x), the currently-stable public API surface, and what workspace-mode dev still looks like (unchanged — `replace` stays on main). 4. README.md — Library Modules row in the Operations doc table. 5. CONTRIBUTING.md — Project Structure table gains a "Published as library?" column and a sentence pointing at the new doc. Main is untouched by every release. The workspace-mode `replace` directives stay; main never has go.mod files with cross-module `require vX.Y.Z` lines that would break local dev (workspace mode can't satisfy `require X v0.15.0` from a local source tree). Script supports --dry-run (verified) and --no-push for safe manual testing. Refuses to overwrite existing path-prefixed tags so a hotfix re-release can't accidentally clobber a published version. Verified locally: - bash -n syntax check passes - --dry-run output matches expectations against v0.14.1 - `go mod edit` rewrites produce clean go.mod files (replace dropped, require bumped to v0.14.1) Next release (v0.15.0) will be the first one that publishes library tags. Initializ can then `go get github.com/initializ/forge/ forge-core@v0.15.0` and import the runtime directly.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds the release-pipeline change needed so external consumers (e.g. the Initializ platform) can embed Forge as a Go library — `go get github.com/initializ/forge/forge-core@vX.Y.Z` — instead of shelling out to the CLI.
This is step 1 of 3 in the multi-module library release plan we sketched:
What blocks Initializ today
The library modules cross-reference each other via:
```go
// forge-core/go.mod
require github.com/initializ/forge/forge-skills v0.0.0
replace github.com/initializ/forge/forge-skills => ../forge-skills
// forge-plugins/go.mod
require github.com/initializ/forge/forge-core v0.0.0
replace github.com/initializ/forge/forge-core => ../forge-core
```
Correct for `go.work`-based local dev (workspace mode resolves to the local source tree). Broken for an external `go get` — the consumer sees `replace ../forge-skills`, can't find that path, and fails.
Strategy: ephemeral release commit
Tagging the library modules at the binary-release commit directly would publish the broken `go.mod` files verbatim. Instead, the new `scripts/release/tag-libraries.sh`:
```
main ◀── workspace-mode go.mod files
│
├─ ... (regular commits)
│
└─ tagged: v0.15.0 ◀── flat binary-release tag (consumed by goreleaser)
│
└── release-libs(go.mod rewrites) ◀── forge-core/v0.15.0
forge-plugins/v0.15.0
```
Main is never touched. Workspace-mode dev keeps working unchanged — `replace ../forge-skills` stays on main.
End-to-end verification
(Did not run end-to-end with real tag creation — sandbox correctly flagged that as a release-adjacent operation that needs explicit authorization. The first real run will happen on the v0.15.0 release tag push.)
Script safety
Files
What ships on the next release
Once this lands and the next `vX.Y.Z` tag is pushed, the workflow automatically tags + pushes:
Initializ can then put in their `go.mod`:
```go
require github.com/initializ/forge/forge-core v0.15.0
```
and the build resolves correctly via the Go module proxy.
Versioning
Unified during v0.x — all three library modules ship at the same version as the CLI on every release, even when only one of them changed. Simpler operational model, matches how the workspace evolves (changes routinely span modules). See docs/reference/library-modules.md § Versioning for the future v1.0 stability promise.
Out of scope
Test plan