diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 0876dbe..a418bd2 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -159,11 +159,37 @@ jobs: sha256sum "$f" > "$f.sha256" done + # Release notes come from changelog//RELEASE.md, written during release preparation and + # committed BEFORE the tag (the release job runs on the tag's checkout, so a file added afterwards + # is invisible here). Present and non-empty -> published verbatim as the body; absent -> GitHub + # generates a body from the merged PRs. Either way the Release can never ship an empty body, which + # is what happened to v0.1.1: the step passed neither body nor generate_release_notes, the action + # left the body unset, and the omission was only visible once the Release was public. + - name: Resolve release notes + id: notes + env: + TAG: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} + run: | + NOTES="changelog/${TAG#v}/RELEASE.md" + if [ -s "$NOTES" ]; then + echo "Publishing curated release notes from $NOTES" + echo "body_path=$NOTES" >> "$GITHUB_OUTPUT" + echo "generate=false" >> "$GITHUB_OUTPUT" + else + echo "No $NOTES; falling back to GitHub-generated notes." + echo "body_path=" >> "$GITHUB_OUTPUT" + echo "generate=true" >> "$GITHUB_OUTPUT" + fi + # On tag-push use the ref name; on manual dispatch use the input tag. + # An empty body_path is falsy for the action and simply ignored (it never tries to read it), so the + # fallback branch cleanly leaves generate_release_notes to compose the body on its own. - name: Publish GitHub Release uses: softprops/action-gh-release@v2 with: tag_name: ${{ github.event_name == 'workflow_dispatch' && inputs.tag || github.ref_name }} + body_path: ${{ steps.notes.outputs.body_path }} + generate_release_notes: ${{ steps.notes.outputs.generate }} files: | dist-artifacts/*.tar.gz dist-artifacts/*.sha256 diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 27d800f..80580f5 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -86,6 +86,11 @@ pnpm test:e2e # core live-model e2e, need `changelog//README.md`. The layout is documented in [`changelog/README.md`](changelog/README.md). Related changes may share one entry file (extending its details) instead of opening a new file per small change. +- **A release ships its own announcement**: `changelog//RELEASE.md` is published + verbatim as the GitHub Release body. Write it during release preparation and **commit it + before creating the tag** — the release workflow reads it from the tag's checkout, so a + file added later never reaches the Release page. Without it the workflow falls back to + GitHub's auto-generated notes. - README assets under `assets/readme/` are generated — the benchmark charts from the landing benchmark data, and the demo screenshots via `node packages/landing/scripts/capture-readme-demo.mjs` (build first; needs Playwright diff --git a/changelog/0.1.1/RELEASE.md b/changelog/0.1.1/RELEASE.md new file mode 100644 index 0000000..e0aa255 --- /dev/null +++ b/changelog/0.1.1/RELEASE.md @@ -0,0 +1,38 @@ +PenguinHarness 0.1.1 — Gemini 3.6 support, a self-upgrading CLI, and the skills that let an agent serve and fine-tune its own models. + +## Install + +```sh +curl -fsSL https://penguin.ooo/install.sh | sh +penguin web +``` + +Linux and macOS, x64 and arm64, with a bundled Node runtime. Or via npm (needs Node >= 24): + +```sh +npm install -g @prismshadow/penguin-cli +``` + +## Highlights + +**Gemini 3.6.** `gemini-3.6-flash` and `gemini-3.5-flash-lite` are in the model catalog, on both the Google endpoint and OpenRouter, with the full 1,048,576-token context and vision. The rest of the catalog was rebuilt against AgentHub 0.4.1's supported-model registry and grew from 59 to 70 entries — Claude 5 on Anthropic, Kimi K3 on Moonshot, and more on OpenRouter and SiliconFlow. + +**Serve and tune your own models, by asking.** Three new skills — vLLM, Ollama and LlamaFactory — teach an agent to stand up and fine-tune the models it runs on: describe what you want in plain language and it serves the model, scores itself, trains on what it got wrong, redeploys and measures again. With a local engine the data never leaves the machine. + +**`penguin update`.** Upgrades an existing install through the mechanism it was installed with — the tarball installer or a global npm/pnpm/yarn/bun package — after showing exactly what it will do. `--check` reports without changing anything, and your data root is never touched. + +**A sidebar that scales.** Conversations group by Workspace (or by Agent), groups can be pinned, sessions created by subagents and scheduled tasks file into their own folders, and long lists load a page at a time. Collapsed, the sidebar is now an eight-entry navigation rail with bilingual tooltips. + +## Notable in this release + +- **Subagents follow the parent session.** A spawned subagent inherits the parent's model and thinking level instead of falling back to the Project default, and a resumed session restores the level its Trace recorded. +- **Empty tool lists stay off the wire.** Strict OpenAI-compatible servers such as vLLM reject `tools: []`; tool-less requests (the connectivity probe, title generation, the vision describer) now omit the field entirely. +- **Two new prompt guardrails.** The agent no longer kills processes on the harness's own service ports — it picks a free port instead — and on an API key error it retries once, then stops and asks you to update the key outside the chat. +- **Per-model max output tokens.** A 32k-context model no longer 400s because the agent-level output cap does not fit its window. +- **Thinking level moved into the conversation**, next to the model picker, and writes through to the Agent's settings. + +## Requirements + +Linux or macOS (x64 / arm64). The installer bundles its own Node runtime; installing from npm needs Node >= 24. All data stays under `~/.penguin/data`. + +Full detail: [changelog/0.1.1/](https://github.com/Prism-Shadow/penguin-harness/tree/main/changelog/0.1.1) diff --git a/changelog/README.md b/changelog/README.md index 5af84ff..3580a93 100644 --- a/changelog/README.md +++ b/changelog/README.md @@ -4,7 +4,9 @@ The root [../CHANGELOG.md](../CHANGELOG.md) keeps one brief line per release. Wo - `/README.md` — the summary: one brief line per change, each linking its detail file, e.g. `- [YYYY-MM-DD] Brief description. ([details](YYYY-MM-DD-short-slug.md))` - `/YYYY-MM-DD-short-slug.md` — one detail file per entry, named by the entry date: an H1 title, then what changed and why, using `##` sections once the entry covers more than one thing. +- `/RELEASE.md` — the announcement published verbatim as the GitHub Release body: a lead sentence, then `## Install`, `## Highlights`, `## Notable in this release`, `## Requirements`, and a closing link to this folder. Only a numbered folder has one; it is written at release, when the version is finally known. - Entries are grouped by the surface they change — Models, Web App, landing site, skills, docs, tooling — rather than one file per commit. A related change extends the existing file and its summary line instead of opening a new one. -- Unreleased changes go in `unreleased/`, never in a numbered folder: the next version number is not knowable while the work is being written — the batch that accumulated as `0.2.0/` shipped as 0.1.1 — so a guessed number only creates a rename to get wrong later. At release, rename `unreleased/` to the version actually shipped, swap its `# Unreleased` heading for `# Version X.Y.Z` plus a `Released on .` line, add the release line to the root file, and create a fresh empty `unreleased/`. Released folders are frozen. +- Unreleased changes go in `unreleased/`, never in a numbered folder: the next version number is not knowable while the work is being written — the batch that accumulated as `0.2.0/` shipped as 0.1.1 — so a guessed number only creates a rename to get wrong later. At release, rename `unreleased/` to the version actually shipped, swap its `# Unreleased` heading for `# Version X.Y.Z` plus a `Released on .` line, write `RELEASE.md`, add the release line to the root file, and create a fresh empty `unreleased/`. Released folders are frozen. +- `RELEASE.md` must be **committed before the tag is created**: the release workflow reads it from the tag's own checkout, so a file added afterwards is never published. When it is missing, the workflow falls back to notes GitHub generates from the merged PRs rather than publishing an empty body. Written in English. History starts after the v0.0.1 release (2026-07-19); earlier changes are not backfilled.