Changelog, dev startup, README, AgentHub 0.4.0, model catalog, and landing site (#7)

Branch-length batch covering tooling, the model layer, the Web App and the public
surfaces. Highlights:

- Changelog: a per-release `changelog/<version>/` tree, grouped by the surface each
  change touches, with a root CHANGELOG.md holding one line per release.
- Dev startup: `scripts/dev-prebuild.mjs` serializes the skills+core prebuild behind a
  lock and keeps `pnpm install` current; `pnpm dev` runs server+web together.
- AgentHub 0.3.3 -> 0.4.0: OmniMessage complete payloads carry one opaque `fidelity`
  object in place of item-level `signature`/`phase`, threaded verbatim through Trace,
  replay and resume; malformed classification adapted to the new error types.
- Model layer: a model is always referenced by an explicit `(provider, model_id)` pair.
  The provider is never inferred, guessed or defaulted -- both the catalog inference and
  the unique-match config resolution are gone, and CLI, SDK, server routes and
  run_subagent all require the complete pair. Catalog gains the Qwen Token Plan, Qwen
  Pay-As-You-Go and Fireworks AI gateways, plus an expanded OpenRouter group.
- Web App: catalog preset sync and per-group speed test on the Models page, positional
  slash commands, a markdown renderer, skill-library update reminders, and a vertically
  centred draft page whose upward menus size themselves to the room available.
- Public surfaces: restructured READMEs, the penguin.ooo landing site and blog, refreshed
  benchmark results for both suites, and the demo videos playing on the landing page.

Includes the fixes from a full review of the branch: 23 confirmed findings, among them a
provider-inference bug that could send one vendor's API key to another vendor's endpoint,
and an Escape handler that destroyed the composer's contents unrecoverably.

Verified on the branch head: pnpm test (1127 passing, 7 packages), pnpm typecheck and
pnpm format:check clean, Playwright e2e 14/14.
This commit is contained in:
Yaowei Zheng authored and GitHub committed 2026-07-21 17:43:31 +08:00
1 parent abf0a2f248
commit d4faee3a1e
214 files changed
+9406 -1688

No files matched your search

@@ -0,0 +1,84 @@
# Landing site
The penguin.ooo landing page: story, structure, animations, navigation, and the install domain.
## Landing, README, and blog retell one story, with penguin.ooo/install.sh
The marketing surfaces now tell the same 1x/100x story, persuade through one numbered "Why" section, and install from the site's own domain.
- **penguin.ooo/install.sh** — the landing site ships a thin `public/install.sh` that forwards to the latest GitHub release installer (GitHub Pages cannot serve real redirects), so `curl -fsSL https://penguin.ooo/install.sh | sh` works everywhere; the hero command, README (en/zh), docs installation/quickstart (en/zh), and blog posts all switch to it.
- **Landing** — the hero replaces the rotating-word headline with the two-line story ("With LangChain, you build agents by hand — at 1x; with PenguinHarness, agents build agents — at 100x", the 100x fragment in brand color) plus the "zero-code Harness CLI and Web UI, 1000+ models" subtitle. One numbered Why section (1 benchmark suites + DeepSeek tuning, 2 one-sentence build demo with the real RAG shot, 3 self-evolution loop with a "demo video coming soon" pill) absorbs the former Pillars / Showcase / Benchmark / SelfImprove sections; UI screenshots leave the home page; nav anchors become why / quickstart / contract / features (reason 1 keeps the #benchmark anchor). The blog already shares the landing Nav, theme, and language settings.
- **README (en/zh)** — subtitle now says "Harness CLI and Web UI"; website/docs/blog/community links render as shields.io badges; the top screenshot and the Changelog-Blog-Docs section are gone; the three reasons sit numbered with emoji under "Why PenguinHarness"; the models table keeps only a one-line "any OpenAI-protocol endpoint works" note; requirements become a table; install sections gain emoji; the roadmap adds a desktop app and Windows support; the credits link LlamaFactory, the PrismShadow AI Team, and Fable 5.
- **Blog** — the introduction post (en/zh) leads with the same story line and phrasing.
## Landing back to the classic structure, with tabbed features/cases and a docs-matching nav
The previous landing overhaul went too far; the classic section set returns, with the new material folded in as tabs and side sections instead of replacements.
- **Restored as they were**: the rotating hero headline ("Efficient Self-Improving Harness for Developers/Enterprises"), the three pillars, the self-improvement loop (now with a "demo video coming soon" pill), Quickstart, the standalone Benchmark section, CONTRACT.md, and Security.
- **LangChain comparison moved, not deleted**: the 1x/100x story lives in its own compact section after the pillars — two cards (LangChain, hand-built, 1x, de-emphasized vs PenguinHarness, agents building agents, 100x, brand-emphasized) with the story sentence as the subtitle.
- **Features become switchable tabs**: all nine feature descriptions remain, each as a tab with its icon; the three views with real captures — multi-session chat, Trace view, Agent evaluation — show their locale/theme-matched screenshot in the active panel, bringing the Trace and benchmark shots back onto the page.
- **Use cases become tabs too**: a Cases section with a tab bar holds the RAG case only for now (prompt + captured result); future cases append as tabs.
- **Community section added at the end**: Discord / X / WeChat group / GitHub as outbound cards after the CTA.
- **Docs nav now mirrors the landing nav exactly** — same link row (Highlights / Quick start / Benchmark / CONTRACT.md / Features / Blog / Docs) with the same sliding hover pill, anchoring into the landing one level up, so the two sites link seamlessly; the old standalone "Website" link is absorbed by the row.
- **Launch blog post back to its original skeleton**: the "Why PenguinHarness" three-pillar bullets, the benchmark section wording, and the closing "start right now" paragraph return, with the GDPevo origin story, images, models table, roadmap, and community call-to-action kept as additions rather than replacements.
## Landing trace screenshots: same opened timeline in English and Chinese
The English trace screenshots showed the empty "select a Session" state while the Chinese ones showed a full trace; all four now capture the same opened trace with stats and an execution timeline containing tool calls.
- The capture script navigated to `/traces?sessionId=...` — but the traces page only honors the session deep link when `agentId=` is present (the product's own links always carry both), so selection relied on a fragile title click that silently failed for English via `.catch()`. The script now uses the canonical `?agentId=default_agent&sessionId=...` deep link and waits for the timeline's `exec_command` lanes before shooting, so an empty capture fails loudly instead of shipping.
- The scripted English session title was 31 chars and core clips titles at `TITLE_MAX_CHARS = 30`, producing "…Agent ap" in the shots; the mock title is now "Build a data-analysis Agent" (27 chars).
- Regenerated `traces-{en,zh}-{light,dark}.webp`; chat and benchmark shots are unchanged.
## Landing polish: sliding announcements, construction animation, trend value labels, feature split
A polish pass over the landing page's motion and grouping, plus web-first usage guidance in the blog.
- **Announcement bar** — light brand-tinted background; both entries now link to blog posts (the new-models entry to the launch post, the credits entry to the AMD post); switching SLIDES horizontally (auto-advance, hover pause) with dot indicators instead of arrows; the trailing arrow icon is gone.
- **LangChain comparison** — a looping "construction" animation on a shared cycle: the LangChain card lays one gray block at a time and never tops out before the cycle resets, while the PenguinHarness card raises a whole brand-blue skyline in under two seconds and holds it. Reduced-motion shows both skylines complete.
- **Self-improvement trends** — the three outcome charts are now driven by one rAF clock, and a value label rides each curve's moving head (score climbing, cost and time falling), changing as the line draws; reduced-motion shows the finished line with its final value.
- **Features split by capture** — only the three features with real screenshots (multi-session chat, trace view, agent evaluation) form the tab bar; the remaining six sit below as the classic card grid, closed with an "and more…" card.
- **Blog usage goes web-only** — the launch post's getting-started and the AMD post's setup now guide through `penguin web` and the Models page only; the CLI config/run alternatives are removed to funnel users into the Web UI.
## Announcement carousel: one-direction slide, arrow kept, dots removed
The announcement bar keeps the small arrow marking each entry as a click-through link, drops the dot switch buttons on the right, and auto-rotates by sliding in ONE direction only: a clone of the first slide follows the last, and once the clone is fully in view the track snaps back without animation — the bar never visibly slides backwards. Hovering still pauses the rotation.
## Feature tabs drop the description card
The three screenshot-backed feature tabs no longer render an icon card above the capture; the feature's one-line description now sits as centered text directly above the image (the tab chip already carries the title and icon). The no-capture features keep their card grid below.
## Trend value labels carry units with animated decimals
The self-improvement loop's three outcome labels now read as real measurements while they ride the curve head: score as a percentage with one decimal (79.0%), cost in dollars with two decimals ($0.25), and time in seconds with one decimal (83.0s) — the decimal part animates continuously along with the line.
## Fix the nav hover highlight sweeping in from the edge
The landing and docs navs' sliding hover pill animated from its hidden state at the nav's left edge, so the first hover sent a gray pill flying across the whole link row (and it slid back on leave).
The pill now appears IN PLACE under the first link it lands on — the position jumps with only the fade animating — slides while moving between links, and fades out where it is when the pointer leaves. Applied identically to the landing nav and the landing-parity docs nav.
## Merge main to restore the persistent nav active highlight
The branch predated main's PR #6 ("correct navigation state and anchor scrolling"), so it was missing the nav's persistent active highlight — the black chip that marks the current section or route — and would have reverted that fix on merge. Merging origin/main brings it back and reconciles it with the branch's nav work.
- Landing nav: section links route through `/#id` again with `getActiveNavItem` tracking (new `lib/nav-state.ts` + tests), the active link keeps its black chip with `aria-current`, and the branch's in-place hover pill behavior is preserved on top.
- Also restored from #6: anchor targets scroll below the sticky header via `.section-anchor` (ids moved onto the section's inner div), footer/hero/CTA anchors as router links, and the docs brand logo returning to the landing site.
- Docs nav (landing-parity) additionally marks its own "Docs" link as the current page with the same black chip.
## Nav highlight follows the live scroll position
The nav's black current-item chip previously updated only from the URL hash (i.e. on click); while scrolling, it stayed stale. A scroll-spy hook now measures the five section anchors on every scroll frame (rAF-throttled, document-level capture so any scrolling container works) and lights up the LAST section whose top has crossed the activation line under the sticky header — null above the first section, and in-between sections keep the previous anchor lit. On the home page the highlight is fully live; other routes keep route-based state (Blog).
## The Cases tab shows the finished RAG app with a localized prompt
The RAG case now displays the condensed claude-code-docs configuration-expert prompt from the strings catalog (localized zh/en) and the finished-product app screenshot matched to the visitor's locale and theme, replacing the shared English prompt and the PenguinHarness chat capture.
## The penguin sled game joins the cases, with a $0.02 cost hook on the RAG demo
The draft-screen game example becomes a cute Antarctic penguin sledding game, lands on the landing page as a second case after RAG, and every RAG demo now leads with how little it cost to generate.
- The draft-screen example card (zh/en) swaps the 2D motocross runner for a penguin sledding game: Space to jump the rocks on the ice, speed and difficulty ramping up, live scoring, one-click restart, cute cartoon look — the full detailed prompt still gets submitted as-is.
- The landing Cases section gains a "Penguin sled game" tab after the RAG one, showing the finished play screen per language and theme (light = polar day, dark = polar night with an aurora) from the new dependency-free `penguin-game-mockup.html` + `capture-game-mockup.mjs` pipeline.
- README (en/zh), the launch blog post (en/zh), and the landing RAG case now carry an emphasized hook under the finished-product shot: generating the entire RAG app burned just $0.02 (¥0.2) of tokens on DeepSeek V4 Pro.
@@ -0,0 +1,259 @@
# Model catalog, Models page, and credential handling
Preset provider groups, catalog entries and ordering, and the Models page features built around them.
## Add the Qwen Token Plan provider group to the model catalog
The built-in catalog gains a Qwen Token Plan subscription gateway group (OpenAI-compatible,
preset base URL) with five models — qwen3.8-max-preview, qwen3.7-max, qwen3.7-plus, glm-5.2,
and deepseek-v4-pro — plus a custom provider logo.
## Details
- New provider `qwen-token-plan` ("Qwen Token Plan"), placed with the gateway cluster after
SiliconFlow: OpenAI-compatible endpoint preset to
`https://token-plan.cn-beijing.maas.aliyuncs.com/compatible-mode/v1`, API-key page
`https://platform.qianwenai.com/pricing/token-plan`, model-id docs page
`https://platform.qianwenai.com/docs/token-plan/personal/token-plan-personal-overview`;
env fallback is `OPENAI_API_KEY`/`OPENAI_BASE_URL` like the other gateways.
- Five catalog entries with `client_type: openai` and the inlined base URL. Vision flags per
the plan's supported-model table (qwen3.8-max-preview and qwen3.7-plus see images; the
rest do not). Pricing and context windows come from each model's page at
`www.qianwenai.com/models/<id>` (official CNY list prices; limited-time promotions are not
stored): qwen3.7-max ¥2.4/¥12/¥36, qwen3.7-plus ¥0.4/¥2/¥8, glm-5.2 ¥2/¥8/¥28,
deepseek-v4-pro ¥1/¥12/¥24 (cache-hit/input/output per M tokens), windows 1M (glm-5.2:
1.04M). qwen3.8-max-preview is preview-only with a quota-multiplier promotion and no
per-token list price, so it alone carries no pricing (costs read as 0, same as unpriced
user models); the pricing invariant in the catalog tests is scoped to that one entry.
- Catalog invariant updated: bare model ids may now repeat across providers (the gateway
resells vendor models under their upstream ids, e.g. `glm-5.2` / `deepseek-v4-pro`);
uniqueness is the `(provider, model_id)` pair, matching the catalog's sole lookup key.
- New provider logo: the official Qwen wordmark (icon + lettering) from the brand SVG,
gradient fills flattened to currentColor monochrome, coordinates rounded to 2dp.
- Docs (models.en/zh) provider table and gateway notes updated.
## Add the Qwen Pay-As-You-Go provider group
A pay-per-token gateway group below Qwen Token Plan (DashScope's OpenAI-compatible
endpoint) with four preset models — qwen3.7-max, qwen3.7-plus, and the resold
vendor-prefixed kimi/kimi-k3 and ZHIPU/GLM-5.2 — priced from each model's official page.
## Details
- New provider `qwen-pay-as-you-go` ("Qwen Pay-As-You-Go") right after Qwen Token Plan in
the gateway cluster: preset base URL `https://dashscope.aliyuncs.com/compatible-mode/v1`,
API-key link `https://platform.qianwenai.com/docs/api-reference/preparation/api-key`,
models page `https://www.qianwenai.com/models`; `OPENAI_*` env fallback like the other
gateways.
- Four entries (`client_type: openai` + inlined endpoint), official CNY list prices and
specs from each model's page: kimi/kimi-k3 ¥2/¥20/¥100 (1.04M, vision), qwen3.7-max
¥2.4/¥12/¥36 (1M), ZHIPU/GLM-5.2 ¥2/¥8/¥28 (1.04M), qwen3.7-plus ¥0.4/¥2/¥8 (1M,
vision). Resold third-party models keep their vendor-prefixed upstream ids.
- The group shares the Qwen emblem (glyph extracted into a shared constant), and
`modelHomepageUrl` URL-encodes the slash-prefixed ids
(`.../models/ZHIPU%2FGLM-5.2`). Docs (models.en/zh) provider tables and gateway notes
updated.
## Add the Fireworks AI provider group
An OpenAI-protocol gateway group below OpenRouter with five preset models (GLM-5.2,
Kimi K2.7 Code, DeepSeek V4 Pro, MiniMax M3, DeepSeek V4 Flash), priced from each model's
Fireworks page.
## Details
- New provider `fireworks` ("Fireworks AI") right after OpenRouter in the gateway cluster:
preset base URL `https://api.fireworks.ai/inference/v1`, API-key page
`https://app.fireworks.ai/settings/users/api-keys`, models page
`https://app.fireworks.ai/models`; `OPENAI_*` env fallback like the other gateways.
- Five entries (`client_type: openai` + inlined endpoint) with standard-serverless USD
pricing (cached input / uncached input / output per M tokens) and specs from each page:
glm-5p2 $0.14/$1.40/$4.40 (1M), kimi-k2p7-code $0.19/$0.95/$4.00 (262K, vision),
deepseek-v4-pro $0.15/$1.74/$3.48 (1M), minimax-m3 $0.06/$0.30/$1.20 (512K, vision),
deepseek-v4-flash $0.03/$0.14/$0.28 (1M). API model ids use Fireworks' full
`accounts/fireworks/models/<slug>` form (sent verbatim).
- `modelHomepageUrl` maps the `accounts/<owner>/models/<slug>` id to the model page
(`app.fireworks.ai/models/<owner>/<slug>`), falling back to the models listing for
nonconforming user-added ids. A simplified starburst glyph approximates the brand mark
(same approach as Z.AI). Docs (models.en/zh) provider tables and gateway notes updated.
## Expand the OpenRouter catalog with twelve models
The OpenRouter gateway group grows from 4 to 16 entries, adding the current flagship and
free tiers with pricing, context windows, and vision flags taken from each model's
OpenRouter page.
## Details
- Added (ordered by output price): anthropic/claude-fable-5 ($10/$50), openai/gpt-5.6-sol
($5/$30), openai/gpt-5.5 ($5/$30), anthropic/claude-opus-4.8 ($5/$25),
anthropic/claude-opus-4.7 ($5/$25), moonshotai/kimi-k3 ($3/$15), openai/gpt-5.6-terra
($2.50/$15), anthropic/claude-sonnet-5 ($2/$10), z-ai/glm-5.2 ($0.93/$3),
deepseek/deepseek-v4-pro ($0.435/$0.87), deepseek/deepseek-v4-flash ($0.09/$0.18), and
nvidia/nemotron-3-ultra-550b-a55b:free (input/output per M tokens; all 1M context).
- Vision per the pages: the Claude models, GPT-5.5, and Kimi K3 accept image input; the
rest do not.
- None of these pages list cache pricing, so cache_read carries the standard input price
(no discount). The :free tier stores a genuine $0 price — not "unknown" — so costs
correctly compute to 0; the catalog pricing invariant gains a free-tier case.
## Add Grok 4.5 to the OpenRouter catalog
`x-ai/grok-4.5` joins the OpenRouter group: $2 input / $6 output per M tokens (no cache
price listed, so cache_read carries the input price), 500K context, vision-capable —
inserted at its dictionary position.
## Add Gemini 3.5 Flash to the OpenRouter catalog
`google/gemini-3.5-flash` joins the OpenRouter group: $1.50 input / $9 output per M tokens
(no cache price listed, so cache_read carries the input price), 1M context, vision-capable
— at its dictionary position; the README model table's Gemini row now lists OpenRouter too.
## Order catalog models by dictionary, newer versions first
Within each provider group, catalog entries are now in dictionary order by model id, except
that newer versions of the same series come first (gpt-5.6-* before gpt-5.5,
claude-opus-4.8 before 4.7, glm-5.2 before glm-5) — precomputed by hand in the catalog
literal, with no runtime sorting anywhere.
## Details
- Every provider section of MODEL_CATALOG is hand-reordered: dictionary order
(case-insensitive) across families and tiers; within a version series, the newest version
block leads, tiers inside a version staying alphabetical. Section comments and the
exact-order test assertions are updated to match.
- The order flows everywhere in-group order is preserved: new Projects' preset config, the
models page cards, and the chat model dropdown (orderModelsLikeLibrary). Existing Project
configs keep their stored order — the sync-presets merge deliberately preserves local
positions.
## Catalog data: official Fireworks logo, two SiliconFlow models, per-model vendor pages
The Fireworks group now wears the official burst mark, SiliconFlow gains
moonshotai/Kimi-K2.7-Code and deepseek-ai/DeepSeek-V4-Flash, and Z.AI / Moonshot models
link to their per-model docs pages.
## Details
- Fireworks logo: the official three-stroke burst mark (viewBox 0 0 638 315, currentColor)
replaces the interim starburst approximation.
- SiliconFlow entries (official CNY pricing, dictionary position):
deepseek-ai/DeepSeek-V4-Flash ¥0.02/¥1/¥2 (1M) and moonshotai/Kimi-K2.7-Code
¥1.3/¥6.5/¥27 (262K, vision).
- modelHomepageUrl: zhipu -> `docs.z.ai/guides/llm/<model_id>`; moonshot ->
`platform.kimi.com/docs/pricing/chat-k<version-without-dot>` (kimi-k2.6 -> chat-k26),
nonconforming ids falling back to the group's models page.
## Add a sync-presets button to the Models page
A small owner-only button next to the Models page search box merges the built-in catalog
into the Project's model table: catalog entries missing locally are added, entries present
on both sides are reset to the catalog's fields, locally added models and API keys stay
untouched.
## Details
- Union semantics (`catalog-sync.ts`, pure and unit-tested): keyed by the
`(provider, model_id)` pair. Catalog-only entries are appended (gateway base URLs preset);
intersecting entries take the catalog's context window, pricing (including removal when
the catalog carries none, e.g. the unpriced preview model), protocol, base URL, and vision
flag — the catalog wins wherever the two differ; local-only models (including
user-defined groups) are kept verbatim and in place.
- Credentials are structurally untouched: merged rows submit no `apiKey` (the PUT
full-table replace keeps stored keys when the field is absent), and existing rows keep
their credential state; a user base-URL override on a preset model is reset to the
catalog's (the API-key carve-out is the only one).
- Feedback via toasts: "Presets synced: N added, M updated", or "already up to date"
without a PUT when nothing differs. Strings added to both locales.
- The Qwen Token Plan provider logo is trimmed to the official emblem only (the wordmark
lettering dropped), on a square viewBox.
## Model test no longer fails on thinking-only responses
Testing a reasoning-heavy model (e.g. qwen3.8-max-preview) failed with "OpenaiClient
returned no content other than thinking (finish_reason=\"length\")": the connectivity
probe's tiny output cap was burned entirely on thinking. The probe now counts a streamed
thinking-only ending as reachable — the endpoint, credential, and model id all
demonstrably work.
## Details
- The probe deliberately sends one "ping" with `maxTokens: 16` and thinking disabled
(single-digit token cost by design). Reasoning models behind OpenAI-compatible endpoints
can ignore the disabled thinking level, hit `finish_reason=length` with no text, and
AgentHub 0.4 raises `EmptyResponseError` — collapsed to a `malformed` outcome, which the
probe previously reported as a test failure.
- `testModel` now tracks whether genuine model content (thinking or text, partial or
complete) was streamed, and a `malformed` ending after streamed content passes the test;
timeouts, auth/parameter failures, and malformed endings with nothing received still
fail. The logic lives in two pure functions (`isProbeContent` / `probeVerdict`) with unit
tests, including the exact qwen3.8-max-preview case.
## Group speed test on the Models page
Each model group header gains an owner-only speed-test action: after a quota warning it
probes the group's models one at a time, measuring time-to-first-token and output rate, and
writes tone-colored badges (green / yellow / red) onto each card; the model-homepage link
moves from the card corner into the config dialog.
## Details
- Server: the model-test endpoint gains a `speed` flag — the probe's output cap rises from
16 to 64 tokens so a real streaming window exists, and the response now carries `ttftMs`
(request start -> first streamed content) and `tps` (output tokens over the streaming
window, from the completed stream's usage report; thinking-only endings carry TTFT but no
rate). The plain connectivity test is unchanged.
- Web: a gauge button on each group header (owner-only) opens a confirmation dialog warning
that one real request per model will consume API quota; on confirm the group is tested
**strictly sequentially** (concurrent probes trip provider rate limits), each result
landing on its card as it finishes. Badges: clock icon + ms for TTFT (green < 1s, yellow
<= 3s, red beyond), zap icon + tok/s for TPS (green >= 40, yellow >= 15, red below);
failures show a red "test failed" with the reason on hover. Thresholds live in a pure,
unit-tested helper; results are session-scoped.
- The model-homepage link moves off the card corner into the config dialog next to the
"get model ids" link (the card stays a single clickable surface; the freed corner hosts
the speed badges).
- Refinements: the group-header actions (add model / bulk API key / speed test) are all
icon + text buttons; the speed badges live on the card's meta line in their own
non-shrinking slot (the numbers never crowd or wrap the title row); the probe prompt
discourages reasoning and ends with an empty `<think></think>` block so reasoning models
skip their thinking phase instead of burning the probe budget on it.
## Model page refinements: draft follows the new default, ordered dropdown, GPT vision, homepage links
Four refinements: changing the Project's default model now resets the stored draft's model
selection to follow the new default; the chat model dropdown lists models in the same order
as the model library page; all GPT models are marked vision-capable; and model cards link to
each model's homepage.
## Details
- Draft follows the default: when saving a default-model change on the Models page, the
current user's stored draft for that Project drops its `modelRef` — the draft chat then
resolves the (new) default live instead of pinning the old model forever.
- Dropdown order: a new `orderModelsLikeLibrary` helper (unit-tested) flattens the library
grouping — built-in provider groups in MODEL_PROVIDERS order, user-defined groups after,
custom last, in-group order preserved — and the chat model dropdown now uses it.
- GPT vision: `openai/gpt-5.6-sol` and `openai/gpt-5.6-terra` are flipped to
vision-capable — GPT models are uniformly multimodal (OpenAI product-line policy) even
where the gateway page omits the modality.
- Homepage links: a new `modelHomepageUrl` helper (unit-tested) — OpenRouter and Qwen Token
Plan have stable per-model URL patterns (working for user-added ids in those groups too;
the unpaged Token Plan preview model falls back to the plan overview), direct vendors link
to their model docs page, custom/user-defined groups have none. Model cards show the link
as a corner external-link icon (a sibling of the clickable card, since interactive
elements must not nest).
## penguin-sdk and agenthub-models keep model keys project-local
Both skills now spell out where model API keys belong: in the project under the working directory, never in the user's global `~/.penguin`.
- penguin-sdk (v6) and agenthub-models (v3) instruct configuring keys with the penguin CLI into the app's own data root under CWD (`penguin config model add --root <data_dir> …`), or relying on vault-injected environment variables; reading, copying or falling back to model keys stored in the global `~/.penguin` directory is explicitly forbidden — that config belongs to the person running Penguin, not to the app being built.
- The no-key path stays as before: stop and ask the user to open the agent's settings via the gear icon on its card and update the key vault.
## Vault edits take effect on the next task; global keys don't count as usable
A vault save now invalidates the Agent's cached Session runtimes so the next task runs with the new values, and the AI-app skills stop counting keys from the global `~/.penguin` as usable.
- Server: `PUT /agents/:agentId/vault` bumps the Agent's config generation in the session manager; every runtime built before the update is discarded on its next idle access and re-resumed via the loader (resume re-reads `agent_state/.vault.toml`; history is preserved through the Trace). A task already in flight keeps the values it started with and rebuilds on the first access after it finishes. Unit and integration tests cover idle/busy entries and the HTTP wiring; the configuration docs (en/zh) and the web Vault tab hint document the new semantics.
- penguin-sdk (v9) and agenthub-models (v6): only two sources count as a usable credential — a vault-injected environment variable, or a key configured in the app's own data root (`penguin config model list --root <data_dir>`). Keys in the global `~/.penguin` (what a bare `penguin config model list` without `--root` reads — the CLI defaults to the global root) or any other `.penguin` directory never count and must never be used or copied; when no counted key is usable, stop immediately and ask the user to configure one instead of building or retrying.
@@ -0,0 +1,74 @@
# READMEs, blog, and docs site
## READMEs
The repository READMEs (en/zh).
### Restructure the README around the product story
The README now leads with the agents-build-agents pitch and community links, then three
feature showcases (benchmark chart, one-sentence RAG demo, self-evolution), followed by
changelog/blog/docs, supported models, human-first installation, a roadmap, CONTRIBUTING,
a citation, and credits.
### Details
- New narrative header: "With LangChain, you build agents by hand — at 1x speed. With
PenguinHarness, agents build agents — at 100x." with the subtitle "A zero-code CLI and
Web UI, connected to 1000+ models," plus community links (Discord / X / WeChat).
- Feature 1 "Simple and Efficient": light/dark benchmark bar charts generated from the
landing benchmark data (accuracy and cost per run vs Claude Code and OpenAI Codex, all
driven by DeepSeek V4 Pro), committed as `assets/readme/benchmark-{light,dark}.svg`.
- Feature 2 "Build an Agent in One Sentence": the RAG one-sentence prompt plus a real
product screenshot captured by the new `packages/landing/scripts/capture-readme-demo.mjs`
(same real-server + mock-LLM pipeline as the landing shots), committed as
`assets/readme/rag-demo-{light,dark}.webp`.
- Feature 3 "Self-Evolution": copy describing the evaluate-optimize-snapshot loop with an
HTML-comment placeholder for the upcoming demo video.
- New sections: Changelog / Blog / Docs links, a supported-models table (DeepSeek V4,
Kimi K3, GLM 5.2, Hunyuan 3, Qwen 3.8 Max, GPT 5.5, Gemini 3.5 Flash, Claude Opus 4.8
with their providers, plus the 1000+-via-gateways note), Requirements and Installation
split into "Web App — for humans" and "CLI & SDK — for agents", a Roadmap (benchmark
suite release), a BibTeX citation ({PrismShadow Team}), and the license/credits footer.
- New `CONTRIBUTING.md` absorbs the developer content: dev commands, repo layout table,
quality gates, the English-only and changelog working rules, and the README-asset
regeneration notes; the README's Development section now points there.
- `README.zh.md` mirrors the new structure in Chinese.
### Refresh the README model table against the current catalog
The supported-models table (the same eight models) becomes two columns — model on the
left, the comma-separated providers it's available from on the right (per today's catalog)
— and the note below now names all five OpenAI-compatible gateways.
### Details
- Availability per the catalog: DeepSeek V4 in five groups, GLM 5.2 in six, Kimi K3 via
OpenRouter and Qwen Pay-As-You-Go, Qwen 3.8 Max as the Token Plan preview, GPT 5.5 and
Claude Opus 4.8 native + OpenRouter, Hunyuan 3 via OpenRouter, Gemini 3.5 Flash native.
- The gateway note lists OpenRouter, Fireworks AI, SiliconFlow, Qwen Token Plan, and
Qwen Pay-As-You-Go. README.zh.md mirrors.
### Split badge rows and showcase the finished RAG app
The site badges (Website / Docs / Blog) and the community badges (Discord / X / WeChat) now sit on separate lines. The one-sentence example becomes the condensed claude-code-docs configuration-expert prompt (the chat page's example task carries the full version), and the demo image shows the FINISHED PRODUCT — the generated docs-expert app with cited clickable sources and example questions (`assets/readme/rag-app-<lang>-<theme>.webp`, per-language shots; the zh README shows the Chinese prompt and shots) — instead of the PenguinHarness chat UI. The mockup renderer (`rag-app-mockup.html` + rewritten `capture-readme-demo.mjs`, no server needed) comes along so the assets stay regenerable.
## Blog and docs site
Blog posts and the docs site.
### Announcement bar, AMD Fireworks-credits blog post, and the GDPevo launch story
The site gains a rotating announcement bar, a new campaign post, and a launch post that finally tells the whole story.
- **Announcement bar** — a switchable bar above the nav (auto-rotates every 6s, paused on hover, prev/next chevrons): entry 1 announces Kimi K3 and Qwen 3.8 Max availability (links to the models docs), entry 2 the $50 Fireworks credits campaign (links to the new post). Bilingual, on every page, scrolls away with the page.
- **New blog post `fireworks-credits-amd` (en/zh)** — announces the AMD AI Developer Program partnership bringing free Fireworks redemption codes: step-by-step application (join ADP, Member Perks, form with Fireworks AI selected, review, coupon email, redeem + API key, screenshots adapted from WhatGhost's guides with credit), then a three-step PenguinHarness setup (install, Fireworks group bulk-key + presets + speed test, run).
- **Launch post rewrite (en/zh)** — now opens with the GDPevo origin story: self-evolution was validated in the team's GDPevo Benchmark (linked), and bringing it to everyone is why PenguinHarness exists. The rest mirrors the README: three numbered reasons with the benchmark chart and RAG demo images (served from the site's own /blog-assets/), the security contract, the models table with the any-OpenAI-protocol note, install/usage steps, the roadmap (benchmark suite, desktop app, Windows), and a closing community call-to-action (Discord / X / WeChat / GitHub).
### The launch post settles on the numbered three-reasons structure
The launch blog post (en/zh) keeps the GDPevo origin story and the numbered "Why PenguinHarness" structure — ### 1 better on complex tasks at lower cost (benchmark chart + tables), ### 2 one-sentence Agent-builds-your-app (prompt + demo shot), ### 3 self-evolution — followed by the security contract, the models table, a Web-only "How to use it" (install + penguin web + Models page; no CLI commands), the roadmap, and the community call-to-action.
### The launch post shows the finished RAG app with the condensed prompt
The one-sentence build section now uses the condensed claude-code-docs configuration-expert prompt (Chinese in the zh post) and the finished-product screenshot of the generated docs-expert app (per-language, served from /blog-assets/), replacing the PenguinHarness chat capture.
+30
View File
@@ -0,0 +1,30 @@
# Skill library and the AI-app skills
## One-shot RAG app flow: skills rewrite and a draft-screen example task
PR #11's squash — briefly lost to a force-push race during the branch rebase — is restored: the skills library rewrite that makes one-sentence RAG apps one-shot, a draft-screen example task card, and the finished-product showcase pipeline.
- penguin-sdk rewritten around a complete RAG recipe (corpus collection, heading chunking, local BM25 retrieval, per-request Session SSE answers with citations, run-and-verify checklist); web-design gains the Penguin visual language and chat/RAG layout recipes; agent-creation covers skill bundles; agenthub-dev retires and a firecrawl skill joins.
- The Web draft screen gains example task cards (full prompts submitted as-is), with chat stream rendering refinements (markdown module, work summaries, stream follow) and colorful skill icons.
- The landing capture pipeline drives the docs-expert conversation and renders the finished-app mockup; README/Cases assets and prompts match the earlier finished-product switch.
## Skill library regrouped by audience, with square card actions
The library's six ad-hoc groups become four audience-oriented ones, and the card actions move into a tidy column.
- New groups, in order: Office Productivity / 办公效率 (`data-analysis`, `firecrawl`), Software Development / 软件开发 (`web-design`, `software-engineering`), AI App Development / AI 应用开发 (`penguin-sdk`, `penguin-cli`, `agenthub-models`), and Agent Tuning / Agent 调优 (`agent-creation`, `benchmark-design`, `agent-evaluation`, `agent-optimization`). Docs tables, skills/server tests, and the skills e2e spec follow.
- Skill card actions (update nudge / quick invoke / manage installs) are now equal squares stacked in one column, vertically centered at the card's right edge; the metadata line moves under the header.
## Skills: pin the CLI --root to the app dir and fast-stop when no key
Three skills gain two hard rules for AI-app development: always target the app's own data root with the penguin CLI, and stop asking for help the moment no API key is usable.
- penguin-sdk (v7), agenthub-models (v4), penguin-cli (v2): when building an AI app, `penguin config ...` must always pass `--root <data_dir>` pointing at the app's data directory inside the current working directory (the same path given to `createAgent({ root })`, e.g. `./penguin_data`); running without `--root` writes to the global `~/.penguin/data`, which belongs to the person running Penguin, not the app.
- penguin-sdk (v7) and agenthub-models (v4): when no API key is usable, stop immediately and ask the user for help instead of looping on tool calls — re-running `env`, re-checking the vault, or retrying the build wastes turns and money; one clear check, then hand back to the user (open the agent's settings via the gear icon and add a key to the key vault).
## System prompt exposes Provider and Model ID; skills state the key-first premise
The Agent system prompt's Environment section now carries the session model reference, and the AI-app skills spell out the key-and-root prerequisites up front.
- The `# Environment` section gains `Provider: {{PROVIDER}}` and `Model ID: {{MODEL_ID}}` placeholders (the session model's provider group and upstream id, filled from the resolved model entry) right before `Session ID`, and the fields are reordered to `Project Dir → Agent ID → CWD → Provider → Model ID → Session ID`. `assembleSystemPrompt` / `SessionEnvironmentValues` / `sessionEnvironment` thread the two new values through; the configuration docs' placeholder table (en/zh) follows.
- penguin-sdk (v8) and agenthub-models (v5) open with the prerequisite: for AI-app development, have the user add the model API key in **this agent's key vault** *before* building, and keep the app's Penguin data root **inside the CWD workspace** (`--root ./penguin_data`), never `~/.penguin`; model ids can come from the penguin CLI catalog.
+156
View File
@@ -0,0 +1,156 @@
# Tooling, language, and infrastructure
Repository language, dev commands, the changelog layout itself, and dependency upgrades.
## Make English the repository working language
Translated all residual non-i18n Chinese (comments, error/log messages, test titles and
fixtures, package metadata, e2e mock content) to English; Chinese remains only in i18n
catalogs, zh documents, and CJK-purpose test fixtures.
## Details
- Package metadata: `package.json` descriptions (root/server/web/landing) and the `link:cli`
fallback echo.
- Source comments: all remaining Chinese comments, including the SQL comment set in
`packages/server/src/db/schema.ts`.
- Hardcoded non-i18n user-facing strings (user-visible language change; error codes,
placeholders, and limits untouched): server HTTP/validation/409 messages, schedule TOML
validation errors, server logs, core SDK errors, CLI fallback errors, web provider
invariants.
- Tests: all Chinese describe/it titles and language-irrelevant fixtures translated;
assertions realigned to the new English source strings.
- e2e: mock LLM conversation content and cross-file branch markers translated consistently
(the substring relationships the mock's `includes()` dispatch relies on are preserved);
zh-locale UI assertions kept; `e2e/README.md` translated.
- Kept as required Chinese: zh i18n catalogs and fields (`strings.ts` dictionaries, CLI
`i18n.ts`, `titleZh`, `short_description_zh`, the zh language-name label, `*.zh.md` docs) and
test literals that assert zh i18n output or exercise CJK-specific behavior (display width,
CJK id validation, title-language consistency, zh-CN e2e UI assertions).
- Known gap: web `formatTaskStats` still hardcodes zh stat-line fragments; the proper fix is
routing them through the locale catalogs.
PR: [#5](https://github.com/Prism-Shadow/penguin-harness/pull/5) (merged 2026-07-20)
## Reorganize the changelog by release version
The top level now holds only version folders; each version's README carries the
one-line-per-change index, and detail files live inside the folder (mirrors agenthub PR
#162).
## Details
- `changelog/<version>/README.md` is the release summary: one line per change with its
title and one-sentence summary, linking the detail file relatively; `0.0.2/README.md`
absorbs the section previously kept in the top-level index.
- `changelog/README.md` now documents only the layout and the entry conventions (no
per-file listing).
- The working rules (AGENTS.md, CONTRIBUTING.md) point index updates at the version
folder's README instead of the top-level file.
## Serialize the dev prebuild to fix concurrent dev:server / dev:web clobbering
dev:server and dev:web now share a lock-serialized, deduplicated prebuild of skills and core,
so launching both at the same time no longer corrupts dist/ (previously two tsup builds with
clean:true raced in the same output directories).
## Details
- New `scripts/dev-prebuild.mjs`: takes an exclusive on-disk lock (atomic mkdir under
`node_modules/`) around `pnpm --filter skills --filter core build`; concurrent invocations
wait instead of clobbering. Locks left by crashed runs are stolen when the holder PID is
dead or the lock is older than 10 minutes.
- A 5-second success stamp collapses duplicate builds: starting dev:server and dev:web
simultaneously builds once (the waiter skips), and dev:server's inner re-invocation is a
no-op. The window is deliberately tiny so an edit-then-restart cycle always rebuilds —
the "never start on stale deps" behavior is unchanged.
- Root `dev:server` now just delegates to the server package's `dev` script (which prebuilds
via the shared script), removing the historical double build of core; `dev:web` prebuilds
via the script and then starts Vite.
- `pnpm dev` run standalone from `packages/server` now also builds skills (it previously
built only core, even though the server imports skills at runtime).
- Verified: concurrent invocations wait/skip correctly and release the lock; a simultaneous
dev:server + dev:web start performs a single build with both servers coming up cleanly.
## Add a combined pnpm dev and a dev:landing shortcut
`pnpm dev` now starts the backend and the web app together with prefixed logs (workspace deps
built once via the shared prebuild lock), and `pnpm dev:landing` serves the landing page dev
server from the repo root.
## Details
- `pnpm dev` runs `concurrently -n server,web "pnpm dev:server" "pnpm dev:web"`. Merging the
two was previously unsafe: each command prebuilt skills/core with tsup `clean: true` into
the same dist/ directories and the parallel builds clobbered each other. The lock-serialized
prebuild (see the serialize-dev-prebuild entry) removed that race, and its success stamp
collapses the two prebuilds into a single build on a combined start.
- `pnpm dev:landing` delegates to the landing package's Vite dev server (port 7366, completing
the 7364/7365/7367 dev-port family). The landing package has no workspace deps, so no
prebuild is involved.
- `concurrently` added as a root devDependency; the dev-command lists in README.md and
README.zh.md now cover `dev` and `dev:landing`.
- Verified: a combined start performs exactly one skills+core build (the other prebuild
waits and skips), with the server on 127.0.0.1:7364 and Vite on localhost:7365; the
landing dev server responds on localhost:7366. Note Vite binds localhost (IPv6 ::1) —
use `localhost`, not `127.0.0.1`, when probing the Vite ports with curl.
## Dev commands keep pnpm install current automatically
Forgetting `pnpm install` before a dev command no longer breaks the start: every dev
command's prestep checks install freshness (lockfile-hash stamp) and runs `pnpm install`
itself when node_modules is missing or the lockfile changed.
## Details
- `scripts/dev-prebuild.mjs` gains an install-freshness step inside its existing lock: the
pnpm-lock.yaml content hash is stamped after a successful install, so the usual dev start
pays nothing; a fresh clone or a pulled lockfile change triggers `pnpm install`
automatically (concurrent dev commands still install/build exactly once).
- The lock and stamps move from `node_modules/` to the OS temp directory keyed by the repo
path — they must exist before the first install does (the old location crashed on a fresh
clone), and per-checkout isolation comes from the key.
- `dev:docs` / `dev:landing` have no workspace deps to build but still need current
installs: they now run the prestep with `--install-only`.
## Upgrade AgentHub to 0.4.0 and adopt the opaque fidelity payload
@prismshadow/agenthub 0.3.3 -> 0.4.0 (agenthub PR #159): content items replace the item-level
`signature`/`phase` fields with one opaque `fidelity` object, and OmniMessage now carries it
verbatim end to end — Trace, replay, and resume included; the `agenthub-dev` skill joins the
built-in library.
## Details
- OmniMessage complete payloads (text, thinking, inline_data, inline_thinking, tool_call)
replace `signature?: string` / `phase?: string | null` with `fidelity?: Record<string,
unknown>` — an opaque wire-fidelity payload written to the Trace as-is and passed back
verbatim on replay (Claude thinking signatures, GPT-5 encrypted reasoning `{id,
encrypted_content}` and `{phase}` markers, the OpenAI-compatible `{reasoning_field}` name).
Builders take the object directly; an empty object is treated as absent.
- GenerativeModel's streaming translator mirrors AgentHub baseClient aggregation: a thinking
block is closed by its fidelity payload and a run of equal fidelity is one block (the
OpenAI-compatible clients stamp every thinking delta with the same `{reasoning_field}`,
which must not split blocks — this carries agenthub's reasoning-field replay fix through
PenguinHarness so multi-turn conversations against strict OpenAI-compatible upstreams
survive); a text segment splits on a differing `fidelity.phase` and closes on
`fidelity.signature`, merging fidelity keys. Text-phase stickiness across segments is gone
(mirrors baseClient).
- The `agenthub-dev` skill (AgentHub's own model-support development workflow) is installed
into the built-in library under the Penguin Development group, completed to the library
contract (version/updated frontmatter, short descriptions, a "Before you start" section,
and a custom icon).
- Malformed-classification fix for 0.4.x: agenthub now surfaces truncated streamed tool-call
arguments as its own `ToolCallArgumentParseError` (previously a raw `SyntaxError`) and
thinking-only completions as `EmptyResponseError`; `isMalformedJsonParseError` recognizes
both (instanceof + name fallback + cause chain), so these still end as `malformed` and the
engine reconnects and retries instead of failing the turn (caught by the malformed e2e).
- Docs (omni-message, interfaces, sessions-and-traces; en + zh) and the design specs updated
to the fidelity semantics.
- Traces written before this change carried `signature`/`phase` on payloads; per the
pre-release no-migration policy they are not converted (old fields are ignored on replay —
resume of such Sessions loses provider fidelity; delete and recreate if needed).
## The changelog folder merges related entries
One file per change had grown to 35 fragment files for this release alone; related changes are now merged into six date-slug entry files (models-and-catalog, web-app, landing-site, blog-and-docs, readme, tooling), each keeping the standard entry shape — H1 title, one-sentence summary, then per-change details — with the version README listing one line per entry file. The layout convention itself is unchanged; the branch was also rebased onto main to linearize away the merge commit with the final tree kept byte-identical.
+99
View File
@@ -0,0 +1,99 @@
# Web App
Chat input, session titles, and the skill library in the Web App.
## Chat input: positional slash, skill chips above the input, wider skill menu
The `/` command menu now opens from any caret position (like `@` mentions) and running a
command removes just the token; selected skills display as chips above the input next to
the agent chip; chip remove buttons recolor on hover instead of washing a background; the
skill dropdown widens for readable descriptions while staying inside phone screens.
## Details
- Positional slash (`slash-token.ts`, pure + unit-tested): a `/` at the start of the text
or after whitespace opens the command menu from wherever the caret is (paths/URLs never
trigger it), mirroring the existing positional `@` mention matching; running a command
removes only the `start..end` token and keeps the rest of the text. Send-time `@`
semantics are unchanged — only a leading `@` hands off.
- Selected skills render as chips above the input in the same row as the `@` handoff chip
(skill icon + monospace name + remove x), appearing as you pick them from the dropdown;
the toolbar count badge stays in sync.
- Chip remove buttons (agent and skill) lose the hover background — the x recolors instead.
- The skill dropdown widens (26rem, clamped to the viewport) so descriptions stay readable
on desktop without overflowing phones.
- The models-page group speed button collapses to icon-only below the sm breakpoint (three
labeled actions don't fit a 390px header — caught by the layout e2e).
## Start title generation after 1000 chars of body text
Session titles start generating as soon as ~1000 characters of main-session body text have
streamed, instead of waiting for the whole Task to finish — long answers no longer overrun
the title material — and the title prompt now suppresses chain-of-thought.
## Details
- Server: the output relay fires the title generator mid-run once EARLY_TITLE_BODY_CHARS
(1000) of main-session complete body text have streamed (sub-session text doesn't count);
the generator self-guards (NULL title, single flight), and the Task-completion trigger
stays as the short-answer fallback. Covered by a gated mid-run test proving the early
fire happens while the run is still in flight.
- Core: the captured assistant-side title material is capped at 1000 chars (the user side
keeps 2000) — a title only needs the opening of the answer.
- The title prompt adds an explicit "answer immediately — do not think aloud or produce
chain-of-thought" rule and ends with an empty `<think></think>` block, which many
reasoning models treat as an already-closed thinking phase (same trick as the model
probe), keeping the one-off request's budget on the title itself.
## Skill library: update reminder, borderless groups, accent icons
The skill library reminds you when an Agent's installed copy of a skill is older than the
library's version — an accent rotate button on the card updates every outdated Agent in one
click, and the manage-installs dialog marks outdated rows with an Update button. Group
sections lose their border, and card icons sit on a theme-accent background.
## Details
- The installed-skills snapshot now tracks each installed copy's `version` (the read API
already returns it — the installed SKILL.md frontmatter is the source). A pure
`outdatedAgentIds` helper (unit-tested) flags Agents whose copy is strictly older than
the library's; not-installed Agents and locally *newer* copies never trigger it.
- Card footer: when any Agent is outdated, an accent rotate button appears
("有新版本:更新 N 个 Agent 的安装" / "Update available"); clicking reinstalls the current
library copy on every outdated Agent (install-again-is-update semantics) with one batch
success toast; partial failures keep the succeeded Agents and toast the first error.
- Manage-installs dialog: outdated rows show an accent "更新"/"Update" button next to
"已安装"/"Installed", updating just that Agent.
- Styling: group sections are borderless (header background alone carries the grouping);
card icons use the theme accent (`--accent-bg`/`--accent-fg`, following the theme-color
setting) instead of the gray bordered tile.
## Titles strip skill-invocation markers; Agent cards show the installed skill count
Two Web App additions: generated titles no longer leak the `<use_skills>` block, and Agent cards display how many Skills are installed.
- Session titles strip machine markers before generation and in the fallback path: `stripConversationMarkers` (core, exported) removes `<use_skills>…</use_skills>` and the handoff / scheduled-task marker blocks from the material sent to the model, from the model output (via `sanitizeTitle`), and from the server's first-line fallback — so a skill invocation's marker can never become the title. Ordinary angle-bracket text (e.g. `<div>`) is left untouched.
- The Agent card's stats line gains an installed-skill count (open-book icon): the agents API/service compute `skillCount` from the `agent_state/skills/<name>/SKILL.md` directories, alongside the existing session / tool / vault-key / schedule counts.
## Slash menu stays on screen; skill card buttons go horizontal and light
Two Web App polish fixes: the slash command menu could grow past the top of the viewport, and the skill card actions change arrangement again.
- The slash menu (which lists /compact plus every installed skill) now caps its height at min(20rem, 40vh) with internal scrolling, so its top edge never leaves the screen; the active row keeps itself scrolled into view for keyboard navigation.
- Skill card actions return to a single horizontal row (still equal squares, vertically centered at the card's right edge), and all three buttons now wear the light secondary background.
## Password field polish, model-key visibility, and borderless skill cards
Several small UX fixes across the password fields, the model key input, and the skill library cards, plus a redrawn penguin game shot.
- The change-password dialog's current-password field now shows a hint naming the built-in admin's default initial password (penguin-2026), so a user who forgot it can still get in.
- The password show/hide toggle is removed from the tab order (tabIndex -1): Tab now moves between fields instead of landing on the reveal button.
- The model API key input gains the same show/hide toggle (it reuses PasswordInput), so a pasted key can be verified before saving.
- Skill library cards drop their border; hover now tints the whole card with a light gray background instead.
- The penguin sled game mockup is redrawn so the penguin stays a single connected cartoon shape (it had looked fragmented), and the game example is emphasized as 2D with a smoother, gentler difficulty ramp in the draft-screen card, its prompt, and the landing tab label.
## The admin initial password becomes penguin-2026
`admin123` sits in every breach corpus, so Chrome flags the first login as a compromised password; the seeded admin now starts as `penguin-2026` — unflagged, brand-related, all lowercase plus a hyphen so it stays easy to type.
The value swaps everywhere it appears: the server seed (`ADMIN_INITIAL_PASSWORD`), the release installer's first-login hint, READMEs, docs (quickstart / web-app / server-api), blog posts, landing quickstart copy, the screenshot capture scripts, and the e2e auth helper. The change-it-soon banner semantics are unchanged.
@@ -0,0 +1,17 @@
# Explicit model reference pairs, and a batch of review fixes
The provider group is no longer resolved automatically anywhere — a model is referenced by the complete `(provider, model_id)` pair or not at all — and a code review of the release branch turned up a further set of correctness, accessibility and documentation defects, all fixed here.
- **The provider is never inferred, guessed, or defaulted (core, CLI, server, web).** Two mechanisms used to pick a group on the user's behalf, and both are gone. Catalog inference (`inferProviderForUpstream`) took the first bare-id match, and gateways resell vendor models under their upstream ids — `glm-5.2`, `qwen3.7-max`, `qwen3.7-plus` and `deepseek-v4-pro` each belong to two groups now — so `penguin config model add --model-id glm-5.2 --api-key <key>` wrote a Z.AI credential onto the Qwen Token Plan entry and sent it to Alibaba's endpoint (on the previous release the same command resolved to `zhipu`). Config resolution (`resolveModelRef`) separately matched a bare `model_id` against the Project's configured models whenever it happened to be unique. Both are deleted, along with `inferProviderForUpstream` and `providersForUpstream`. The rule everywhere is now **both halves or neither**: `--provider` is required on `config model add`; on `run` / `chat` the pair as a whole stays optional (omit both for the Project default) but supplying one half is an error; `addModel` and `Agent.createSession` require the pair at the type level; `POST /sessions` and the schedule routes return 400 for a half reference, and a schedule file persisted with only a `modelId` is reported invalid instead of silently binding to a guessed group. `run_subagent` gains a `provider` argument beside `model_id` and refuses half a reference, so a delegating model cannot land a subagent on the wrong vendor either. The trace viewer stops attributing cost to a first-match guess for pre-tag traces, showing no cost instead. CLI help, the CLI/models/server-api/quickstart/configuration/interfaces docs (en+zh), the READMEs and every skill that scripts the CLI were updated to pass the pair.
- **Escape no longer wipes the composer (Web App).** The slash menu's Escape handler cleared the whole input — correct back when the menu only opened on a draft starting with `/`, but the menu became positional this release, so dismissing it from a `/token` mid-draft destroyed everything typed so far, unrecoverably (the textarea is controlled, so undo could not bring it back). Escape now only dismisses the menu, mirroring `@` mentions via a `slashDismissed` offset. Separately, `removeSlashToken` collapsed *every* run of two or more spaces in the surviving draft rather than the join seam, silently reflowing pasted code, YAML, aligned tables and indentation; it now touches the seam alone.
- **The penguin.ooo installer forwards its arguments.** `https://penguin.ooo/install.sh` piped the real installer straight into `sh`, so `--universal` and `--version` were silently discarded — leaving unsupported-architecture users with advice ("re-run with `--universal`") that could not work through the documented URL, and turning version pinning into "latest". The forwarder now downloads to a temp file, runs it with `"$@"`, and propagates the exit code; this also removes the partial-execution hazard of piping a truncated download into a script that deletes the old install before moving the new one in.
- **Speed test reports throughput or nothing.** Speed mode raised the output cap to 64 tokens but reused the connectivity prompt, which demands a single word — so the rate was computed over a 1-3 token sample dominated by the closing usage chunk's round trip, and the same model graded green or yellow on 30ms of jitter. Speed mode now has its own prompt that keeps generating into the cap, and the new pure `probeTps` drops the rate below meaningful sample floors (16 tokens, 100ms), leaving TTFT alone rather than a fabricated number.
- **Announcement bar (landing).** Rotation pauses on keyboard focus as well as hover, so the focused link is no longer left inside an `aria-hidden` slide translated out of view (an ARIA violation and a WCAG 2.2.2 failure); under `prefers-reduced-motion` the carousel no longer strands itself on the clone slide.
- **Streaming fidelity rules are pinned by tests.** The two rules added with the AgentHub 0.4.0 payload — a `fidelity.signature` closes the open text segment, and fidelity keys merge rather than replace across deltas — had no coverage; both mutations passed the whole suite. Tests now fail on either, guarding against a replay handing the provider a signature covering text it never signed, and against GPT-5 phase segmentation being lost on resume.
- **New benchmark results, and a comparison that changed shape.** Both suites are refreshed, and the design of the comparison changed with them: instead of running all three harnesses on one shared DeepSeek V4 Pro, each now runs the model it is normally paired with — PenguinHarness on DeepSeek V4 Pro, Claude Code on Claude Opus 4.8, OpenAI Codex on GPT-5.5 — so the model column is part of the result rather than a constant, and Tokens/cost are suite totals rather than per-run means. Data analysis (15 tasks, single run): 66.67% for PenguinHarness against 53.33% for both rivals, at $0.55 versus $38.48 and $19.41. Coding (40 tasks × 2 runs, accuracy over all 80 outcomes): 71.25%, level with Codex and behind Claude Code's 86.25%, at $3.81 versus $220.08 and $146.97. The copy moved with the data — the section no longer claims "same model" or "highest accuracy of the three", both of which the new results contradict, and leads on cost-per-quality instead; the 35×/70×/58×/39× multiples in that copy are now asserted against the data by unit test so they cannot drift on the next refresh. The README and blog charts are generated from the same source by `render-benchmark-svg.mjs`. Bars stay linear and zero-based, but carry a minimum length: at true scale the cost panels put PenguinHarness at ~2px, which reads as an empty slot rather than as the winning series, so the floor keeps it visible while still plainly the shortest bar — with the exact figure printed beside every one. The README's chart caption is now a single-line conclusion rather than a paragraph of run settings, matching the RAG cost hook.
- **The demo videos reach the landing page.** The self-improvement section's "demo video coming soon" pill is replaced by the recording itself, and the RAG case tab plays the finished app instead of only picturing it — both following the READMEs, both locale-matched (`evo_zh`/`evo_en`, `rag_zh`/`rag_en`). The files stay out of this repo: at ~9 MB each against a ~17 MB history, committing four would triple what every contributor clones for assets only the marketing site shows, so they are served from the sibling `penguin-harness-community` repo via `raw.githubusercontent`, which answers with `accept-ranges: bytes` (seeking works) and `access-control-allow-origin: *`. Its `application/octet-stream` type does not block playback — `nosniff` is enforced for scripts and styles, not media — and this was verified end to end in Chromium rather than assumed. Every embed pairs a poster with `preload="none"`, so a page view downloads one ~37 KB still and no video byte until someone presses play (asserted by watching the network on load: zero mp4 requests). The standalone embed deliberately drops the BrowserFrame chrome the screenshots use, because the self-improvement recording is a narrated deck rather than the product's own UI; the RAG case keeps the frame, because there it really is the app.
- **The draft page is genuinely centred, and the upward menus stop clipping.** The brand block sat inside the upper flex spacer, so the gap above it was shorter than the gap below the example cards by exactly the brand's own height — the whole page rode high, and the slash menu, which opens upward from the composer, ran into the top of the scroll area. The brand now lives in the same centred block as the composer, pills and example tasks, making the two gaps identical (measured: 134/134 at 1000px tall, 84/84 at 900, 34/34 at 800). The slash and `@` menus additionally cap their height to the room actually measured between the composer and the nearest clipping ancestor instead of a fixed `40vh`, which could not know that distance: previously the menu was cut by ~50px at 900px tall and still 5px at 800px, and now it fits at every height down to 620px, shrinking and scrolling internally instead of being clipped.
- **Web polish.** Speed-test badges reset when the active Project changes (results are keyed by `(provider, model_id)`, so they used to leak across Projects); the work-group header ticks and settles on the same span, so its duration never jumps backwards; the markdown renderer's component map has a stable identity, so streaming no longer remounts closed code blocks and drops text selection or Copy state.
- **Sources are diffable again.** Four files embedded a literal NUL byte as a composite-key separator instead of the `\0` escape, which made git treat them as binary — `catalog-sync.ts`, the model-catalog and models tests, and the scheduler produced no reviewable diff, no `git grep` output, and no textual merge. The runtime value is unchanged.
- **Docs and metadata.** The workspace `files/content` preview mode and its response headers are documented in the server API reference (en/zh); the skills README lists the groups that actually exist; the skill-library page's docstrings describe the per-skill palette and two-column grid it really renders; `penguin-cli`'s `updated` date matches its version bump; the penguin-sdk RAG recipe stops installing the entire skill library into the app it generates; the README model table no longer lists Kimi K3 under Moonshot, which does not serve it; and a Chinese comment in the catalog's pricing block is translated.
- **A test that did not test.** The early-title case asserting that sub-session output does not count toward the 1000-character trigger stayed green with the origin guard removed; it now fails without it.
+17
View File
@@ -0,0 +1,17 @@
# Version 0.0.2
Unreleased.
- [2026-07-21] A model is always referenced by an explicit `(provider, model_id)` pair — the provider is never inferred, guessed, or defaulted — together with the fixes from a full review of the release branch, refreshed benchmark results, and the demo videos on the landing page. ([details](2026-07-21-model-reference-and-review-fixes.md))
- [2026-07-20] Model catalog: preset provider groups, catalog entries and ordering, the Models page features built around them, and where model credentials are allowed to live. ([details](2026-07-20-models-and-credentials.md))
- [2026-07-20] Web App: chat input and slash menu, session titles, the skill library cards, password fields, and the seeded admin password. ([details](2026-07-20-web-app.md))
- [2026-07-20] Landing site: the story it tells, section structure, animations, navigation, the install domain, and the case gallery. ([details](2026-07-20-landing-site.md))
- [2026-07-20] Skill library regrouped by audience, and the AI-app skills that turn one sentence into a running RAG app. ([details](2026-07-20-skills.md))
- [2026-07-20] The repository READMEs, the blog posts, and the docs site. ([details](2026-07-20-readme-blog-and-docs.md))
- [2026-07-20] Repository language, dev commands, the changelog layout itself, and dependency upgrades. ([details](2026-07-20-tooling.md))