* docs: bump skill count to 137 in TL;DR and header badge
* docs: sync at-a-glance and comparison-table counts, drop broken arithmetic
* docs: sync remaining body references to 137 skills
* docs: update README skill and design system counts to 132/150
Fixes remaining 7 stale count references identified in #2186:
- Line 3: intro paragraph (31→132, 72→150)
- Line 33-34: shields.io badges (131→132, 149→150)
- Line 68: feature comparison table Skills row (31→132)
- Line 114-115: screenshot caption (72→150, ×2)
- Line 876: user templates note (31→132)
- Line 902: comparison table Skills row (31→132)
Actual counts verified:
- skills/: 132 (134 entries - AGENTS.md - README.md)
- design-systems/: 150 (152 entries - _schema - AGENTS.md)
* fix: deduplicate example cards by skill ID to prevent duplicate rendering
Fixes#2889
The ExamplesTab component was rendering duplicate task-selection cards
when rawSkills contained multiple entries with the same skill.id. This
was particularly visible in the official xhs-white-editorial example flow.
Solution: Add deduplication logic in the skills useMemo hook. After
filtering out aggregatesExamples skills, we now use a Map to ensure
each skill.id appears only once, keeping the first occurrence.
This prevents duplicate cards from being rendered while preserving the
existing filter and sort behavior downstream.
* fix: prevent cursor jumping during IME composition after @ mention
Fixes#2851
When using Chinese input method (IME) after typing @ in the chat
composer, the cursor would jump to the previous character position,
making it confusing and difficult to type Chinese text.
Root cause: The handleChange function was detecting @ mentions and
updating the mention state during IME composition events. This caused
React to re-render and reset the cursor position while the user was
still composing characters.
Solution: Skip mention and slash-command detection when composingRef
indicates an active IME composition session. The existing
onCompositionStart/End handlers already track this state; we now
respect it in handleChange.
This fix applies to all IME-based input methods (Chinese, Japanese,
Korean, etc.) and prevents cursor jumping when typing after @ or /
triggers.
* docs(README): refresh stale skills and design-systems counts
The English README still reported 31 skills / 72 design systems and a
prototype(27)+deck(4) split last accurate around v0.4.1. Counted from
SKILL.md / DESIGN.md entry files at the current HEAD: 132 skills
(32 prototype, 9 deck, plus image/video/audio/template/design-system/
utility modes) and 150 design systems.
Updates the eight inline references in README.md plus the two ASCII
tree comments under `skills/` and `design-systems/`. Adds a one-line
note that the mode taxonomy now spans more than just prototype + deck
so the description stops contradicting the visible mode chips in the
picker.
Translations (README.de/fr/es/ko/ja-JP/zh-CN/zh-TW/pt-BR/ar/ru/uk/tr)
still carry the old numbers and need follow-up PRs from their original
translators; intentionally out of scope here to keep this PR easy to
review.
Refs #2186.
* docs(README): include utility mode in catalog summary
The mode summary listed image/video/audio/template/design-system but
dropped utility. The tree comment later in the same file already
mentions utility, and one skill (pptx-html-fidelity-audit) is registered
with mode: utility. Add utility to the inline list so the README stays
internally consistent with the registry the surrounding counts cite.
* chore(landing-page): bring PR #2469 content wholesale onto post-revert main
Step 1 of replicating @pftom's #2469 work without the deploy-blocking
issues that forced #2603. This commit copies the full \`apps/landing-page/\`
diff from #2469's HEAD (`9d2a4f1`) onto current main verbatim — every
i18n bundle, every page rewrite, every \`[locale]/\` wrapper. Subsequent
commits on this branch then surgically restore the SEO fixes that
#2469 silently regressed and configure the sitemap to survive the
Cloudflare Pages 25 MiB limit, so deploy is healthy when this lands.
What's in this commit
- Tom's i18n bundle: \`i18n.ts\` (5377 lines), \`home-page-i18n.ts\`,
\`info-page-i18n.ts\`, \`landing-ui-i18n.ts\`, \`content-i18n.ts\`
(~10K lines total of locale data)
- 18 landing-page locales: en, zh, zh-tw, ja, ko, de, fr, ru, es,
pt-br, it, vi, pl, id, nl, ar, tr, uk
- All existing pages rewritten to consume the new i18n bundle
- Full \`[locale]/<route>/\` wrapper tree for every catalog page
- \`plugin-registry.ts\` rewrite, \`catalog.ts\` adjustments
- \`astro.config.ts\` route + sitemap reconfiguration
- \`public/_headers\`, \`public/_redirects\`, \`public/favicon.svg\` adds
- \`_components/locale-switcher-script.astro\` add
What's intentionally NOT done in this commit (handled in follow-ups
on this same branch):
- Restore brand mark 44px + rounded corners (was lost from #2588)
- Restore HA SoftwareApplication \`alternateName\` array (was lost from #2566)
- Restore HA \`url\` canonical pointing at the landing page (was lost from #2586)
- Restore Product/Library/Tutorials/Blog nav grouping (was lost from #2588)
- Restore catalog-card padding 24px (was lost from #2600)
- Configure sitemap to filter \`[locale]/\` routes so the generated XML
stays under 25 MiB and Cloudflare Pages accepts the deploy
- Add \`/zh-CN/* → /zh/*\` redirects for backwards-compatibility with
any externally-linked OD-canonical locale URLs
Validation so far
- \`pnpm --filter @open-design/landing-page typecheck\` — 0 errors
* fix(landing-page): unblock deploy + restore SEO regressions on top of #2469
Step 2 of replicating @pftom's #2469. The previous commit on this
branch brings #2469's content wholesale; this commit applies the
surgical fixes that make the result actually deploy and preserves
the SEO improvements that #2469 silently regressed.
Fix 1 — sitemap stays under Cloudflare Pages 25 MiB upload limit
- `astro.config.ts` `filter` now drops every `/{locale}/...` route
so the sitemap only emits canonical English URLs.
- Locale variants are still discoverable via the
`<xhtml:link rel="alternate" hreflang="...">` annotations the
`namespaces.xhtml: true` option emits inside each canonical entry.
This is Google's recommended pattern for a multi-language site.
- Verified: post-fix `out/sitemap-0.xml` = 179 KB (was 38.4 MiB
on the prior attempt that forced #2603's revert).
Fix 2 — header brand block restored to the polished version
- Logo `width/height` 36 → 44 (matches PR #2588's brand-mark refresh
for visual weight against the new black speech-bubble glyph)
- `.brand-meta` block ("Studio Nº 01 · Berlin / Open / Earth") removed
from the header bar; the same editorial flourish still lives on the
rotated `.side-rail .rail-text` pseudo-elements at page edges.
Fix 3 — header nav grouped into Library + standalone Tutorials/Blog
- Skills / Systems / Templates / Craft are now children of a Library
dropdown (matches PR #2588's grouping). Each row keeps its count
badge inline; the trigger highlights when any of the four facet
pages is active.
- Tutorials and Blog stay as standalone top-row items (PR #2588's
original decision after Joey's review on the Learn dropdown).
- Contact removed from the header — it was a same-page anchor that
the footer already surfaces.
- Hardcoded "Library" / "Tutorials" labels match the brand-name
pattern: unlocalized across all 18 landing-page locales.
Fix 4 — HA SoftwareApplication entity canonicalized on the LP again
- `alternateName` is back to an explicit array of real query
variants `["html anything", "html-anything", "htmlanything",
"HTML Anything Editor", "The agentic HTML editor"]`. #2469
re-routed it through `copy.schemaAlternateName` which dropped
the literal alias declarations Google needs for spaced-vs-
hyphenated-vs-joined matching. (Restores PR #2566.)
- `url` flips back from `HA_URL` (the GitHub repo) to the LP URL
itself, matching the `BreadcrumbList` block on the same page.
GitHub repo lives in `sameAs` as a peer surface. (Restores PR
#2586. Without this, Google credits the GitHub repo as canonical
for the entity, which is the opposite of what this surface
exists for.)
Fix 5 — catalog-card horizontal padding unified at 24 px
- featured-card 22 → 24, template-card 20 → 24,
system-card 18 → 24, source-card 28 → 24.
- For template-card, also moved horizontal padding into the group
rule exclusively so future siblings join without re-asserting
margin shorthands. (Restores PR #2600.)
Fix 6 — `_redirects` for the locale-code rename
- This bundle uses `zh` / `zh-tw` / `pt-br` / `es` (the codes Tom's
i18n.ts ships). The previous OD landing-page used `zh-CN` /
`zh-TW` / `pt-BR` / `es-ES`. Externally-indexed and inbound-linked
URLs against the old prefixes now 301 to the new canonical.
Validation
- `pnpm --filter @open-design/landing-page typecheck` — 0 errors
- `pnpm --filter @open-design/landing-page build` — completed
successfully; 18,204 pages built; sitemap-0.xml is 179 KB
(well under the 25 MiB Cloudflare Pages limit).
* docs: promote 'open-source alternative to Claude Design' to README H1
Brings the missing README and .gitignore changes from #2469 that the
first wholesale-checkout in this branch missed (the auto-pulled diff
scope was filtered to apps/landing-page/ initially).
What
- Every README.*.md (13 locale variants) now leads with the
"open-source alternative to Claude Design" tagline as a subtitle to
the project name in the H1 / first paragraph. This was @pftom's
brand-positioning commit (`ee851dc`) on the original #2469 branch.
- `.gitignore` adds `growth/**` to keep growth-research scratch out of
the repo.
Why
- The README is one of the highest-PageRank surfaces a GitHub project
exposes to Google. Promoting the "alternative to Claude Design"
framing into the H1/subtitle position makes the project surface for
exactly the query the SEO work in this PR is trying to capture.
- Without this commit, the replicated #2469 in this branch would still
rank against the previous H1 ("Open Design") on GitHub crawls,
letting the SEO win at the LP fall short on the GitHub surface.
This is a strict subset of #2469's content — pure docs, no code,
no behavior change beyond what GitHub renders on the repo overview.
---------
Co-authored-by: Joey-nexu <joeylee12629@gmail.com>
* Enhance landing page with SEO-focused content and FAQ section
- Updated `.gitignore` to include growth directory.
- Modified `astro.config.ts` to prioritize high-intent landing pages for SEO.
- Added new FAQ styles and layout in `globals.css` for better user experience.
- Implemented FAQ section in `page.tsx`, ensuring it aligns with structured data requirements.
- Created dedicated pages for agents and alternatives to Claude Design, enhancing SEO and user navigation.
- Introduced comparison page for evaluating Open Design against competitors.
- Added favicon links component for consistent branding across all pages.
* Add SVG favicon and update favicon links for improved branding
* Enhance landing page with official source pillars for improved branding and navigation
- Added five canonical "official source" pillars to the homepage, reinforcing key links: official site, GitHub repository, releases, documentation, and Discord community.
- Updated URLs for releases, issues, documentation, and license to streamline access and improve user experience.
* Add locale support and enhance landing page with language switcher
- Introduced locale management with a new i18n module, defining multiple languages for the landing page.
- Implemented a locale switcher in the topbar and header, allowing users to select their preferred language.
- Updated global styles for the locale selector and adjusted layout for better responsiveness.
- Enhanced SEO by ensuring localized content is served based on user selection.
- Added a script for automatic locale detection and persistence in local storage.
* Implement localized routing and enhance navigation with href utility
- Added `stripLocaleFromPath` and `localizedHref` functions to manage locale-based URL paths.
- Updated `localePath` to normalize paths based on the detected locale.
- Refactored links in the header, footer, and main page components to utilize the new `localizedHref` function for improved navigation.
- Introduced locale-aware routing for new pages, ensuring consistent user experience across different languages.
- Enhanced SEO with alternate links for localized content in the sub-page layout.
* Update header component to use new logo format
- Replaced favicon image with a new logo in WebP format for improved performance and quality.
- Ensured consistent branding across the landing page with the updated logo.
* Enhance landing page with localization and new UI components
- Introduced a comprehensive localization schema for content management, allowing for multilingual support across various sections.
- Updated the blog and collection schemas to include internationalization (i18n) fields for better content localization.
- Implemented a new official source strip for improved navigation and branding, linking to key resources like the official site and documentation.
- Enhanced the locale switcher functionality, allowing users to select their preferred language with improved UX.
- Updated styles for the locale switcher and added new components for better responsiveness and accessibility.
- Refactored existing components to utilize localized URLs, ensuring a consistent user experience across different languages.
* Implement comprehensive localization and enhance landing page UI
- Introduced new localization features, including `EXTRA_LOCALIZED_HOME_BODY_COPY` and `EXTRA_LOCALIZED_LANDING_UI_COPY`, to support multilingual content across the landing page.
- Updated `astro.config.ts` to integrate internationalization (i18n) settings for the sitemap, improving SEO for localized content.
- Created new files for home page and info page internationalization, defining structured content for various languages.
- Enhanced the locale switcher functionality with improved UX, allowing users to easily select their preferred language.
- Refactored existing components to utilize localized content and URLs, ensuring a consistent experience across different languages.
- Made CSS adjustments for better responsiveness and accessibility in the UI components.
* Enhance landing page with new design templates and localization improvements
- Added support for design templates in the content management system, allowing for better organization and access to design resources.
- Implemented comprehensive localization for blog topics, enhancing multilingual support across various sections of the landing page.
- Updated the header component to include new product menu items, improving navigation and user experience.
- Refactored CSS for improved responsiveness and accessibility, including a new sticky chrome bar for better navigation.
- Enhanced the locale switcher functionality, ensuring a seamless experience for users selecting their preferred language.
* docs(readme): promote 'open-source alternative to Claude Design' tagline to subtitle across locales
* feat(senseaudio): BYOK chat with image + video generation tools
Adds SenseAudio as a first-class BYOK chat protocol and wires the daemon's
chat proxy with a tool loop so BYOK users can generate images and videos
without dropping to a CLI agent.
- BYOK protocol: new senseaudio tab + /api/proxy/senseaudio/stream route +
connection-test + provider-models discovery (OpenAI-compatible wire)
- Tool loop: generate_image (synchronous /v1/image/sync) and generate_video
(async /v1/video/create + 5s polling /v1/video/status, 10-min ceiling,
periodic progress log every 30s)
- Settings dropdown + chat-composer dropdown for the BYOK image model
default; generate_image's model enum lets the LLM override per call
- Seed-on-success: a successful BYOK chat call idempotently mirrors the
key into media-config (preserves env-resolved + already-stored keys)
- Generated artifacts land in <projectsRoot>/<projectId>/ so FileViewer,
DesignFilesPanel, and project export pick them up automatically;
legacy /api/byok-image/:id route kept for old conversation links
- Markdown renderer learns  image syntax with a scheme
allowlist (http(s) / data:image/ / blob: / relative paths)
- i18n key settings.byokImageModel across all 19 locales
- 3 SenseAudio image models registered (2.0, 1.0, doubao-seedream-5.0);
1 video model (doubao-seedance-2.0)
- Tests: byok-tools (29), media-senseaudio-image (8), media-config seed
(7), proxy-routes (47), markdown image rendering (8)
* fix(senseaudio): unblock image gen + design file preview switching
- SenseAudio /v1/image/sync rejected the previous size mapping with
`参数错误:size` (1664x936, 936x1664, 1280x960, 960x1280 are not in
the gateway's accepted set). Switched to standard HD / SD sizes that
every aspect bucket can hit: 1024×1024, 1280×720, 720×1280,
1024×768, 768×1024. Kept the byok-tools and media.ts tables in sync
so the BYOK chat tool and the CLI agent path both stop failing on
non-square aspects.
- DesignFilesPanel's <DfPreview> was missing a key prop, so React
reused the same iframe DOM node when the user picked a different
file — the src prop changed but the iframe never navigated. Added
key={previewFile.name} so the previous preview unmounts cleanly.
- Updated byok-tools + media-senseaudio-image tests for the new size
expectations.
* docs(senseaudio): clear stale provider hint + update README
- Settings → Media → SenseAudio: clear the auto-promoted
"Image · TTS · 70+ voices · clone" hint; the provider label alone is
enough now that the BYOK chat surface covers image + video tooling.
- README: list the new senseaudio (and missing ollama) proxy routes so
the BYOK section reflects what the daemon actually serves, and
mention the generate_image / generate_video chat tools that ship
with the SenseAudio path.
* fix(senseaudio): address PR #2065 review feedback
Three non-blocking review notes from @PerishCode on PR #2065:
1. Drop the dead /api/byok-image/:id route. The PR description claimed
it was "legacy fallback for old chat history" but that storage
layout never existed on main, so the route can only ever 400 or
404 — never 200. Removed the handler, the isSafeByokImageId
export, the unused createReadStream / stat / path / Request /
Response imports, and the two byok-image regression tests.
2. Add rejectProxyPluginContext guard to the senseaudio proxy
handler so it matches the invariant the other five proxy paths
already enforce (plugin runs must go through /api/runs for
snapshot pinning). Extended the existing "API fallback rejects
plugin runs" describe to also cover /api/proxy/senseaudio/stream
with the 409 PLUGIN_REQUIRES_DAEMON expectation.
3. Wrap the secondary image / video downloads (the URLs the
SenseAudio gateway hands back in /v1/image/sync .url and
/v1/video/status .video_url) in validateBaseUrlResolved so a
malicious gateway can't point us at 169.254.169.254 (AWS / Azure
metadata) or RFC1918 hosts via the response payload. Also passed
`redirect: 'error'` on both fetches to match the SSRF posture
the primary proxy fetch already uses. The new
assertExternalAssetUrl helper lives next to executeGenerateImage
so future tool downloads can reuse it.
Tests: 120/120 daemon tests pass; guard + typecheck green.
* fix(senseaudio): mirror SSRF guard onto renderSenseAudioImage CLI path
Follow-up to 01b1260a — the chat-tool fix in byok-tools.ts wasn't
mirrored onto the parallel renderSenseAudioImage path in media.ts.
Same attacker-controllable shape (gateway-returned `data.url`),
same one-line fix.
- Hoist assertExternalAssetUrl from byok-tools.ts into
connectionTest.ts next to validateBaseUrlResolved so both call
sites (the BYOK chat tool loop AND the CLI agent media dispatcher)
share one helper. Made the error strings provider-agnostic so a
future caller doesn't get a misleading "senseaudio" attribution
for a Volcengine / Grok / etc. download.
- renderSenseAudioImage now runs the response url through
assertExternalAssetUrl before fetching bytes, and passes
redirect: 'error' to block a 3xx hop into private space.
Scope intentionally limited to the senseaudio path PerishCode
flagged; the other unguarded fetch(entry.url) call sites in
media.ts (OpenAI / Volcengine / Grok / Nano-Banana) are pre-existing
patterns and belong in a separate follow-up if the daemon wants
defense-in-depth across every provider.
Tests: 127/127 daemon tests pass; guard + typecheck green.
---------
Co-authored-by: unknown <mazeliang@sensetime.com>
The 12 locale READMEs (+ root English README) each carry two
shields.io inventory badges:
https://img.shields.io/badge/design%20systems-72-orangehttps://img.shields.io/badge/skills-31-teal
The actual counts on `main` today (verified):
find skills -maxdepth 2 -name SKILL.md | wc -l → 131
find design-systems -maxdepth 2 -name DESIGN.md | wc -l → 149
This commit updates the badge URLs to reflect the actual inventory.
This is the conservative "inventory-only" shape proposed in #1890 —
prose strings like "72 out of the box" or "X systems available" are
left alone in this PR because they carry historical / launch
context the badge URLs don't, and the right shape there is a
maintainer call. The badges themselves are unambiguously a current
inventory signal, so they're safe to sync without taking sides on
the policy question.
`README.fr.md` is intentionally skipped: it already replaced both
numeric badges with `catalogue` generic placeholders, so the
French README needs no update.
Refs #1890.
Co-authored-by: nicejames <nicejames@gmail.com>
* docs(readme): add 0.8.0-preview banner pointing to Discussion #1727
Adds a single-line block-quote banner at the top of the English and
Simplified Chinese READMEs inviting visitors to try the 0.8.0 preview
and participate in shaping it.
The banner is intentionally short — all details (installer downloads,
contribution paths, Discord, scope, what we want feedback on) live on
the announcement thread at Discussion #1727 so the README stays
maintainable as a single source of truth.
Other language READMEs (es, pt-BR, de, fr, zh-TW, ko, ja-JP, ar, ru,
uk, tr) can adopt the same pattern via follow-up community PRs.
* docs(readme): punch up 0.8.0-preview banner to match announcement rally tone
Echo the signature lines from the announcement thread (Discussion #1727):
- "Design's old world ends here"
- "40k stars in two weeks got us this far"
- "We need you to push the rest of the way"
CTA link copy also reframed from generic "Discussion #1727" to action verbs:
"Read the announcement, grab the installer, join the movement" — matches
the rally-style framing of the announcement itself instead of reading
like a flat reference link.
* docs(readme.zh-CN): fix awkward Chinese phrasing for 40k stars line
"两周 40k stars 把我们送到这里" reads stilted in Chinese — the
number-as-subject construction is more English-like. Replace with the
phrasing already used in the announcement thread (Discussion #1727):
"上线两周,40k stars 在身,且仍在加速。剩下的路,需要你和我们一起推完。"
Maximum consistency with the Chinese announcement copy that's already
been reviewed and shipped.
* docs(readme): use GitHub Alert + H3 for higher-contrast 0.8.0 banner
A plain block-quote banner blended into the existing tagline and got
lost. Switch to GitHub's native '> [!IMPORTANT]' alert syntax — renders
as a purple-tinted callout card with an icon, which:
- Stands out clearly from the regular tagline that follows
- Matches the preview/v0.8.0 label color (#7c3aed purple)
- Renders consistently on github.com, mobile, and GitHub Desktop
- Needs zero images / inline CSS / external assets
Bumped the headline to H3 inside the alert for further visual weight,
broke the body into separate paragraphs for legibility.
* docs(readme): move 0.8.0-preview banner below language selector
After feedback, position the rally banner between the language selector
line and the '## Why this exists' heading instead of right under the H1.
Rationale: the very top of the README is for stable identity (title +
tagline + banner image + badges). The 0.8.0 alert sits in the
transitional position between identity-block and body-content, acting as
the last hook before readers commit to reading. Keeps the foundational
tagline visually pristine while still placing the call-to-action above
the fold.
* docs(readme.zh-CN): tweak CTA wording '拿安装包' → '下载安装包'
'下载安装包' is the natural Chinese verb pairing for installer downloads;
'拿' reads slightly casual / dialectal for a public-facing README banner.
* docs(readme): add 0.8.0-preview banner to all 11 remaining language variants
Translates the 0.8.0-preview rally banner into es, pt-BR, de, fr, zh-TW,
ko, ja-JP, ar, ru, uk, tr — placed in the same position (between the
language selector and the first horizontal rule) as the English and
zh-CN versions.
Each translation preserves the signature signals from Discussion #1727:
- 'Design's old world ends here' / its local-language equivalent
- '40k stars in two weeks' (number kept literal — same data point)
- 'We need you to push the rest of the way' / equivalent rally line
- 'agent-native' kept as English (no widely-accepted translation yet)
- 'Figma' kept as proper noun
Code blocks (`0.8.0-preview`), URLs, and the `[!IMPORTANT]` alert
syntax remain unchanged across all variants for renderer consistency.
If any native speaker spots a phrasing that reads less than fluent, a
follow-up PR is welcome — these translations are AI-assisted and should
be treated as starter copy, not final.
* docs(readme): move 0.8.0-preview banner back to top of all language READMEs
After more feedback, position the rally banner right after the H1 (`# Open Design`)
instead of below the language selector. Trade-off: the banner now competes with
the foundational tagline for above-the-fold attention, but visitors see the
0.8.0 call-to-action in their first eye-fix instead of after scrolling past
badges and language picker.
Same banner content, same alert syntax, same 13-language coverage — only
position changed across all variants (en, zh-CN, zh-TW, es, pt-BR, de, fr,
ko, ja-JP, ar, ru, uk, tr).
* docs(readme): add 'actively shipping / next phase / merges to main' line
Per colleague feedback, surface that preview/v0.8.0 isn't a fork or a
side experiment — it's the next phase of Open Design, currently in fast
development, set to land on main once stable.
The new paragraph sits between the 'we need you' rally line and the
final CTA link, so readers see the momentum context before clicking
through to the announcement.
Translated in place across all 13 language READMEs.
* docs(readme): update banner — 0.8.0 is already in main now
preview/v0.8.0 has been fully merged into main (0 commits behind, 59
commits behind main). The 'will merge into main once stable' line is
out of date.
Reframe to reflect current state:
- 'Actively shipping fast → set to merge into main once stable' (old)
- 'Already in main — 0.8.0 is the next phase, in active development.
Bring your contributions, ideas, and feedback.' (new)
Translated in place across all 13 language READMEs.
* docs(readme): drop awkward '合入 main' phrasing from banner
The 'merged into main' / '已经合入 main' line reads too git-operational
for a public banner. Reframe without referencing merge mechanics:
old: 'Already in main — 0.8.0 is the next phase, in active dev. Bring
your contributions, ideas, and feedback.'
new: 'Active development, open to all — 0.8.0 is the next phase of
Open Design. Your contributions, ideas, and feedback shape what
comes next.'
Same intent — current direction, welcoming, no version-control
vocabulary that non-engineer visitors won't connect to.
Translated in place across all 13 language READMEs.
* docs(readme): tighten banner phrasing — 'iterating fast on main'
Replace 'Active development, open to all' with a more dynamic line that
brings 'main' back into the copy without the static 'merged into main'
feel:
'**Iterating fast on `main`** — 0.8.0 is the next phase of Open Design.
Your contributions, ideas, and feedback shape what comes next.'
Conveys ongoing forward motion (vs the completed-merge frame), keeps
the 'main' anchor so readers know where to look. Translated across all
13 language READMEs.
* docs(readme): amp up banner CTA — concrete actions + 'what you bring is what this movement becomes'
The previous 'Your contributions, ideas, and feedback shape what comes
next' was directionally right but soft. Swap in three concrete imperative
verbs (PR / idea / bug) plus a collective-ownership punchline:
'**Iterating fast on `main`** — 0.8.0 is the next phase of Open Design.
Ship a PR, drop a wild idea, file a bug — what you bring is what this
movement becomes.'
Reads like an invitation to act, not a thank-you-in-advance. Translated
across all 13 language READMEs.
* docs(readme): mention Claude Design alongside Figma in banner
Update paragraph 2 from 'alternative to Figma' to 'alternative to Claude
Design / Figma' across all 13 language READMEs.
Aligns the banner with the foundational tagline below it (which already
points to [Claude Design][cd]). The framing is now: Open Design competes
with both closed silos — Anthropic's Claude Design *and* Figma — by
being the open, agent-native answer to the same opportunity.
* docs: plan linux client issue 709
* fix: complete linux headless lifecycle routing
* feat: add linux packaged inspect
* test: add linux headless packaged smoke
* ci: add linux headless packaged smoke
* ci: smoke linux AppImage release artifacts
* docs: document linux packaged client status
* chore: finalize linux client audit remediation
* docs: add linux client publication packet
* test: harden linux client smoke coverage
* ci: preserve linux smoke audit evidence
* refactor: consolidate linux e2e helpers
Move pathExists and the desktop/web/daemon app-key array out of
linux.spec.ts into linux-helpers.ts, where expectPathInside and
linuxUserHome already live. Keeps the spec file focused on tests and
the helpers file as the canonical home for shared Linux e2e utilities.
* fix: move linux e2e helpers to lib
* fix: address linux release review blockers
* fix: drop npm dependency from containerized linux build
writeAssembledApp() previously called runNpmInstall() which executed
`npm install` directly. Inside the containerized build path,
electronuserland/builder:base strips npm/npx/corepack, so the inner
tools-pack build would fail at the assembled-app install step.
Route the install through OD_TOOLS_PACK_PNPM_BIN: buildDockerArgs sets
the env to the standalone pnpm binary it bootstraps, and the new
resolveProductionInstallCommand helper consumes that env to run
`<bin> install --prod --no-lockfile --config.node-linker=hoisted`.
Host invocations with no env set keep the prior npm behavior.
--config.node-linker=hoisted preserves the flat node_modules layout
that electron-builder packs the same way as npm-installed trees.
New tests cover the resolver branches and assert the docker-arg-to-
resolver chain end-to-end so reviewers can see the container's inner
build receives the env that switches its install away from npm.
* fix: harden linux container bootstrap
* fix: validate desktop marker liveness in headless cleanup
cleanup --headless previously skipped on any parseable desktop-root.json, trapping recovery when the AppImage had crashed and left a stale marker. Validate the marker the same way stopPackedLinuxApp does: if the PID is not in the live snapshot list, proceed through cleanup instead of skipping.
Extract the validation into validateDesktopAppImageMarker so the stop and cleanup paths share one definition of live and owned. Tests cover both branches: a stale marker drives cleanup to remove the runtime/output roots, while a live marker drives cleanup to skip and preserve them.
* nix: add official flake with home-manager and nixos modules
* Pin pnpm version
* Format README.md
* Populate PATH files to discover installed CLIs
* Revert "Populate PATH files to discover installed CLIs"
This reverts commit 18d88781a88b8781913cf5a8b680dfb38eabf7e4.
* Fix missing sqlite issue
* Fix system issue
* Reapply "Populate PATH files to discover installed CLIs"
This reverts commit d02ea994e6.
* Handle different ports for web frontend
* Provide documentation for getting pnpm hash
* Enable nix flake checks for code changes
* Set `OD_WEB_PORT` on daemon when declared
* fix: Fix environmentFile for macOS targets
* chore: Ignore nix and direnv related files
* fix: Read version directly from `package.json`
* feat: Make nix shell entry prettier
* chore: Update pnpm hashes
* chore: Bump `pnpm` hashes
* docs: Add blurb about dev shell in `README.md`
* Address review comments
* Add support for `OD_WEB_ORIGINS`
* Fix `isLocalSameOrigin`
* Update pnpm checksums
* docs: Update documentation on host origins
* Move allowedOrigins mapping out of the webFrontend.enable guard
* fix: Bump pnpm hashes
* Remove changes to `daemon` with `main` changes
`main` merged a feature that addressed our need for allowed origins.
Since this feature branch no longer needs it, remove any remaining
changes in `daemon` code so that this is a pure Nix change.
* Update documentation around `OD_DAEMON_URL`
* Rewrite option docs to match same-origin proxy contract
The port, webFrontend, and webFrontend.port option descriptions still
described OD_DAEMON_URL as the runtime contract for the SPA, but the
SPA issues relative /api/*, /artifacts/*, /frames/* requests and there
is no runtime daemon-URL injection. Rewrite the three blocks to
describe what the caddy / custom proxy must actually do.
* Document daemon-side requirements for custom-server proxy paths
The bring-your-own-server path in section (3) and the same-origin
contract in section (4) understated what the daemon needs: any proxy
whose origin differs from the daemon's bind (including loopback
split-port like 127.0.0.1:8080 while the daemon stays on :7457) is
403'd by the daemon's same-origin gate until told about that origin.
Add a callout under section (3)'s table, expand section (4) with a
decision table covering same-port, loopback split-port (OD_WEB_PORT or
webFrontend.allowedOrigins), and non-loopback (webFrontend.allowedOrigins)
cases, and rewrite the webFrontend.allowedOrigins option description to
enumerate the cases where it's required and surface OD_WEB_PORT as an
alternative for the loopback split-port case.
---------
Co-authored-by: lefarcen <935902669@qq.com>
* docs: fix - update prompts path from web to daemon in README files
Update all references from apps/web/src/prompts/ to apps/daemon/src/prompts/
across all README language files.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: fix - update prompts path in specs and fix French README parity
P2 — Current specs:
- specs/current/critique-theater.md
- specs/current/critique-theater-plan.md
Update prompts path from apps/web/src/prompts/ to apps/daemon/src/prompts/
to reflect daemon ownership of prompt composition.
P3 — Historical spec:
- specs/2026-04-29-live-artifacts/spec.md
Update to current path (historical snapshots kept accurate to latest codebase).
P3 — Language parity:
- README.fr.md
Fix missing prompt references in Anti-AI-slop and References sections
to match other language variants (6 refs total).
Migration context: Prompts moved from web to daemon as an ownership/boundary
change (daemon composes and injects prompts at agent spawn time), not a
mechanical rename. Web app no longer owns prompt composition logic.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: fix - update git command path in critique-theater-plan.md
Fix missed git add command example at line 1585.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
* docs: fix - update prompt test paths from web/tests to daemon/tests
Update test file paths to match daemon ownership of prompts.
Tests for apps/daemon/src/prompts/* should live in apps/daemon/tests/prompts/.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
---------
Co-authored-by: Claude <noreply@anthropic.com>
Add a one-shot OD_LEGACY_DATA_DIR migrator so packaged Desktop users can recover 0.3.x repo .od data into the 0.4.x data root. The migrator stages payloads before promotion, refuses unsafe merges and symlinks, rolls back failed promotion or marker writes, and extends packaged daemon startup handling for long migrations while failing fast on daemon exits.
Closes#710
* docs(readme): add @nexudotio X link + Stay in the loop section
- Add X/Twitter follow badge in the header next to Discord, so visitors
can subscribe to release notes and milestone threads in one click.
- Add a short "Stay in the loop" section above "Star us" pointing to
@nexudotio on X. Discord is for chat, X is for the public milestones
(releases, new skills, new design systems).
No other changes.
* feat(web): add Follow @nexudotio pill to entry sidebar foot
- Surface the official X account next to the Settings/Pet/Language pills
so users can subscribe to release notes from inside the app, not only
the README.
- Uses the existing .foot-pill style (already supports <a>, has
text-decoration: none) and the existing 'external-link' Icon — no new
CSS, no new icons, no i18n key required (single short English label).
- Opens in a new tab with rel="noreferrer noopener".
Pairs with the README badge added in this same PR.
---------
Co-authored-by: Tuola-waj <ge@nexu.io>
* docs: fix broken pi-ai links, point to correct pi-mono packages
All links to https://github.com/mariozechner/pi-ai returned 404 after
the project was restructured into the badlogic/pi-mono monorepo.
- "pi" / "Pi" (the CLI tool the daemon scans for) now points to
packages/coding-agent
- "pi-ai" (the multi-provider LLM API) now points to packages/ai
via the shared [piai] reference definitions
Closes#275.
* fixup! Merge remote-tracking branch 'upstream/main' into docs/fix-pi-pi-ai-links
Fix [piai] reference in README.ar.md and README.es.md: was incorrectly
pointing to packages/coding-agent (pi CLI) instead of packages/ai (pi-ai
provider library).
* fixup! fix row order in README.uk.md: move Pi after DeepSeek TUI to match English README
* feat: add accent color control and launcher for Open Design
* fix: remove launcher binary from PR
* test: cover accent appearance edge cases
---------
Co-authored-by: ferasbusiness666 <ferasbusiness666@users.noreply.github.com>
* feat(daemon): let Codex image projects avoid API-key setup
Codex has a built-in image generation path available inside the agent runtime, while the generic media dispatcher still routes gpt-image models through the daemon OpenAI provider. Pass the active agent id into prompt composition so Codex-only gpt-image projects can use built-in imagegen first without changing non-Codex media behavior.
Constraint: Existing media contract remains the default path for non-Codex agents and explicit provider fallback
Rejected: Add a nested daemon Codex media provider | heavier auth, streaming, timeout, cancellation, and output parsing surface for this parity fix
Confidence: high
Scope-risk: narrow
Directive: Keep this override after the media contract so it can intentionally supersede dispatcher-only wording for Codex gpt-image projects
Tested: pnpm --dir apps/daemon exec vitest run -c vitest.config.ts tests/system-prompt-template.test.ts
Tested: pnpm --filter @open-design/daemon typecheck
Tested: pnpm guard
Tested: pnpm typecheck
Not-tested: Live Codex image generation inside the Open Design UI
* fix(daemon): harden Codex imagegen prompt routing
PR review found the Codex override could be superseded by the web-supplied media contract, trusted unvalidated image model metadata, and assumed generated image paths outside the workspace were readable.
This keeps the override daemon-owned, appends it last in the live prompt, validates against registered gpt-image model IDs, allowlists only Codex's generated_images folder, and tightens copy-failure instructions.
Constraint: The web contracts composer still emits the generic media contract without agent identity.
Rejected: Mirror Codex-specific prompt logic into contracts/web | duplicates daemon model registry and still leaves final ordering fragile.
Confidence: high
Scope-risk: narrow
Directive: Keep Codex imagegen override appended after client systemPrompt so it remains the final media instruction for Codex gpt-image projects.
Tested: pnpm --dir apps/daemon exec vitest run -c vitest.config.ts tests/system-prompt-template.test.ts tests/agents.test.ts tests/chat-route.test.ts
Tested: pnpm --filter @open-design/daemon typecheck
Tested: pnpm guard
Tested: pnpm typecheck
Not-tested: Live Codex image generation inside the Open Design UI
* fix(daemon): keep Codex add-dir writable scope narrow
PR review found Codex --add-dir grants writable workspace access, so passing skill, design-system, and linked reference directories through the same chat allowlist broke their documented read-only boundary.
This routes chat extra directories by active agent: Codex receives only the validated generated_images output directory needed for built-in imagegen, while non-Codex adapters keep the existing resource and linked-directory read access behavior.
Constraint: Codex CLI treats --add-dir as writable sandbox expansion.
Constraint: The daemon still stages active skill files into the project cwd as Codex's read-safe path.
Rejected: Keep one shared extraAllowedDirs list for all agents | grants Codex write access to read-only resources.
Confidence: high
Scope-risk: narrow
Directive: Do not add read-only resource/reference directories to Codex --add-dir unless Codex gains a read-only allowlist flag.
Tested: git diff --check -- apps/daemon/src/server.ts apps/daemon/tests/chat-route.test.ts
Tested: pnpm --filter @open-design/daemon exec vitest run tests/chat-route.test.ts
Tested: pnpm --filter @open-design/daemon typecheck
Tested: pnpm guard
Tested: pnpm typecheck
Not-tested: Live Codex image generation inside the Open Design UI
* fix(daemon): validate Codex imagegen add-dir grants
PR review found the generated_images grant still trusted symlinked paths and rendered the Codex override before proving the sandbox grant would be present.
This validates the generated_images directory before prompt assembly, rejects final-component symlinks and protected-root canonical escapes, passes Codex the canonical grant path, and only appends the Codex imagegen override when that same path is in extraAllowedDirs.
Constraint: Codex --add-dir grants writable workspace access, so path aliases into read-only resource roots must be rejected.
Rejected: Keep returning the nominal CODEX_HOME path after validation | leaves Codex operating through a symlink alias instead of the audited grant target.
Confidence: high
Scope-risk: narrow
Directive: Keep Codex imagegen prompt rendering downstream of generated_images validation and grant resolution.
Tested: git diff --check -- apps/daemon/src/server.ts apps/daemon/tests/chat-route.test.ts
Tested: pnpm --filter @open-design/daemon exec vitest run -c vitest.config.ts tests/chat-route.test.ts
Tested: pnpm --filter @open-design/daemon exec vitest run -c vitest.config.ts tests/agents.test.ts tests/chat-route.test.ts
Tested: pnpm --filter @open-design/daemon typecheck
Tested: pnpm guard
Tested: pnpm typecheck
Not-tested: Live Codex image generation inside the Open Design UI
GitHub's `/contribute` page only renders the `good first issue` label,
so 12 open `help wanted` issues never reach newcomers via that entry.
Switch the link to an issues search URL covering both labels (OR), so
both pools surface from one click. Wording is unchanged across all 10
README locales.