Document and publish the ChatGPT Desktop skin Skill - #4
Draft
GiantClam wants to merge 68 commits into
Draft
Conversation
The repository now presents the current ChatGPT Desktop Skill as the primary product surface, with bilingual usage guides and a versioned distributable package. The Skill documentation covers image-to-skin workflows, five-zone composition, one-shot creation, scoped brand replacement, and LaunchAgent persistence. The persistence worker now runs from persist.mjs and reports its actual running state. Constraint: ChatGPT Desktop exposes only local renderer CDP for this MVP Constraint: Skill distribution files must remain English ASCII-only Rejected: ChatGPT Scheduled Tasks for local persistence | they do not provide a reliable macOS process or app lifecycle hook Confidence: high Scope-risk: broad Directive: Keep brand selectors scoped to the top workspace mode button; do not broaden them to project or account controls Tested: npm test (114 passing); Skill package build and unzip validation; LaunchAgent running with active slayers-xellos-night theme Not-tested: full macOS reboot and ChatGPT Desktop update lifecycle
Generated backgrounds can contain bright regions that compete with live controls, while ChatGPT Desktop retains light default tokens in menus and preview surfaces. Map the theme into opaque control tokens, derive an accent-safe foreground, and target the composer, menus, dialogs, selections, and file previews without altering the image composition contract.\n\nConstraint: The runtime remains CSS injection only and must preserve the signed ChatGPT Desktop app.\nRejected: Darken the entire hero image | reduces visual fidelity and does not fix default light UI tokens.\nConfidence: high\nScope-risk: moderate\nReversibility: clean\nDirective: Keep live control readability independent from hero brightness; add selectors only from observed stable attributes or token classes.\nTested: npm test (115 passing); npm run package:codex-skin-studio; live CDP status and computed-style verification for send button and right panel.\nNot-tested: Every future ChatGPT Desktop renderer variant and every localized file-preview selector.
The repository now has its own Codex Skin Studio identity while remaining technically inspired by the upstream heige-codex-skin-studio project. Clarify the non-parity relationship and leave room for a future skin website without changing the lightweight Skill runtime.\n\nConstraint: Preserve the upstream repository as origin and keep the existing draft PR target intact.\nRejected: Rename every legacy runtime identifier immediately | the repository still contains compatibility code outside the current lightweight Skill scope.\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep future website and product work independent from the local Skill runtime boundary.\nTested: git diff --check; GitHub repository rename and metadata verification.\nNot-tested: Full test suite not rerun because only repository documentation changed.
Users can now switch among validated local themes from an upper-right in-app menu. The menu embeds the theme inventory during injection and opens a loopback control route so each selection reuses the existing validation and CDP application path. Rebuilding the switcher on every injection also removes listeners left by older Skill versions. Constraint: ChatGPT Desktop app:// renderers could open loopback navigation but could not reliably read loopback HTTP responses or deliver beacon/form requests. Rejected: renderer fetch or beacon control calls | blocked or unreliable under the app:// network policy Confidence: high Scope-risk: moderate Reversibility: clean Directive: keep the control server loopback-only and accept theme IDs, never arbitrary paths or commands Tested: npm test (117 passing); live CDP menu discovery; live menu click switched naruto-hokage to slayers-xellos-night and auto-closed the control popup Not-tested: ChatGPT Desktop versions without the current app:// navigation behavior
The local skin switcher now observes native ChatGPT Desktop menu state and temporarily releases its hit area while a file open-method menu or other native popover is expanded. Ordinary disclosure controls are excluded so the switcher remains visible during normal workspace interactions. Constraint: native ChatGPT Desktop menus are rendered by the app and can overlap injected fixed-position UI. Rejected: move the switcher permanently farther from the conversation corner | still collides with responsive native popovers and reduces discoverability Confidence: high Scope-risk: narrow Reversibility: clean Directive: keep native overlay detection limited to menu/listbox triggers and visible popup containers; do not treat every aria-expanded control as a blocking overlay Tested: npm test (117 passing); live ChatGPT Desktop CDP simulation confirmed hide on menu trigger and restore after close Not-tested: every future ChatGPT Desktop popup implementation
The switcher was too small to target and remained above native file menus because its fixed layer outranked the app popover. Move it into a wider top-right safe slot, enlarge the hit target, lower its stacking layer, and raise native menu containers above it. Constraint: ChatGPT Desktop renders native menus outside the injected style subtree and uses responsive popover placement. Rejected: rely only on MutationObserver hiding | the first pointer event can still be intercepted before the menu state mutation Confidence: high Scope-risk: narrow Reversibility: clean Directive: preserve the native menu z-index override and keep the switcher out of the native top-right control slot Tested: npm test (117 passing); live CDP geometry showed a 104x40 hit target and the installed worker remained active Not-tested: every ChatGPT Desktop window size and future native popover implementation
The previous stacking adjustment placed the switcher beneath ChatGPT Desktop's transparent top interaction layer. Keep the wider safe-slot button above that layer while retaining the explicit native-menu layer above the switcher. Constraint: the app contains transparent native top-bar hit surfaces that are not represented by visible content. Rejected: lower the switcher below all native layers | makes the control visible but not clickable Confidence: high Scope-risk: narrow Reversibility: clean Directive: the switcher must remain above top-bar hit surfaces, while native menus must stay at z-index 1000 or higher Tested: npm test (117 passing); live CDP hit-test and mouse click opened the local skin menu with four themes Not-tested: future ChatGPT Desktop top-bar layout changes
The fixed control was still positioned inside ChatGPT Desktop's native top window bar, where real pointer events could be intercepted even though renderer hit testing found the DOM button. Place the control below the native chrome in the conversation area while preserving native menu precedence. Constraint: renderer CDP hit testing does not model every native no-drag or window-control surface. Rejected: keep tuning top-bar z-index only | does not make the control reliable across native window surfaces Confidence: high Scope-risk: narrow Reversibility: clean Directive: keep injected controls out of ChatGPT Desktop native chrome; validate with real pointer dispatch after placement changes Tested: npm test (117 passing); live CDP geometry y=88 and mouse click opened the four-theme local menu Not-tested: every window height and display scaling combination
Users can drag the local theme control within the conversation viewport without losing click-to-open behavior. The implementation distinguishes a click from movement, clamps the control to the visible window, and persists its position in Renderer-local storage. Constraint: the control must remain outside native ChatGPT Desktop chrome and must not move beyond the viewport. Rejected: make the entire switcher menu draggable | conflicts with selecting local themes and increases accidental movement Confidence: high Scope-risk: moderate Reversibility: clean Directive: preserve the five-pixel click-versus-drag threshold and local-only position storage Tested: npm test (117 passing); live Renderer pointer events moved the control and persisted coordinates; subsequent click opened the four-theme menu Not-tested: touch-specific gestures on macOS
The repository still carried the upstream full-product runtime, bundled presets, custom pet, duplicate Skill, legacy CLI wrappers, and unrelated test suites even though the maintained product is the independent codex-skin-studio Skill. Remove those artifacts and keep only the Skill source, focused packager and tests, documentation, notices, and distributable package. Constraint: generated themes and user assets belong in the local CodexSkinStudio data directory, not in the reusable repository or Skill archive. Rejected: retain the upstream runtime as a compatibility layer | it contradicts the lightweight architecture and keeps unrelated product behavior in the project surface Confidence: high Scope-risk: broad Reversibility: clean via Git history Directive: new features belong under skill/codex-skin-studio unless a documented MVP requirement proves another repository component is necessary Tested: npm test (69 focused tests passing); npm run package:codex-skin-studio; archive inspection; live installed apply/status and persistence worker verification Not-tested: the deleted legacy full-product CLI and pet workflows, intentionally outside this repository's product scope
The project uses HeiGeAi/heige-codex-skin-studio as a research and design reference only. Its maintained scope is an independently implemented lightweight Skill, not a complete fork with modifications. Constraint: preserve accurate attribution without implying feature parity or inherited full-product ownership. Rejected: describe the repository as a modified fork | inaccurate for the current minimal implementation and product boundary Confidence: high Scope-risk: narrow Reversibility: clean Directive: future documentation should describe upstream as reference material, not as the implementation base Tested: documentation diff check; repository remains at the previously verified 69 focused tests
GitHub renders README.md by default and does not automatically combine README.zh-CN.md. Add reciprocal language links so the bilingual documentation is discoverable from the default repository page. Constraint: keep README.md as the GitHub default while preserving a dedicated Chinese document. Rejected: duplicate the full Chinese README inside README.md | creates two drifting copies and makes maintenance error-prone Confidence: high Scope-risk: narrow Reversibility: clean Directive: update both language links when either README is renamed Tested: documentation diff check
Expose the provided project contact QR code at the end of both English and Chinese README files using a repository-relative image path so GitHub renders it on the default branch. Constraint: keep the contact asset in the repository because README images must resolve from a tracked GitHub path. Rejected: link to the local source image path | GitHub cannot render local filesystem paths Confidence: high Scope-risk: narrow Reversibility: clean Directive: keep the image filename stable when editing the README contact section Tested: file type check and git diff check Not-tested: QR-code scan from every GitHub client
Expose the project Discord server and X account in both README contact sections alongside the existing QR code. Constraint: keep the contact links visible in the default English and Chinese guides. Rejected: add links only to the Chinese README | GitHub defaults to the English README Confidence: high Scope-risk: narrow Reversibility: clean Directive: keep community and social links synchronized across both language guides Tested: documentation diff check
Render the contact QR code at 188px wide in both language guides, which is one fifth of the source image width while preserving its aspect ratio. Constraint: GitHub Markdown image syntax does not provide a portable display-size control. Rejected: resize the source image file | would reduce the reusable asset quality and still require a layout decision Confidence: high Scope-risk: narrow Reversibility: clean Directive: keep both language README contact sections visually consistent Tested: documentation diff check
The repository now includes the locally generated Slayers Xellos theme as a checked-in example and packages its WebP hero with the Skill. Documentation and legal notices identify it as a demonstration asset, while tests keep text distribution files ASCII-only and validate the WebP archive entry. Constraint: The default example must not auto-apply or overwrite a user theme Rejected: Keep the generated asset only in local application data | it cannot be distributed or used as a reproducible example Confidence: high Scope-risk: narrow Directive: Treat bundled character artwork as an example asset subject to third-party rights Tested: npm test (69 tests), npm run package:codex-skin-studio, example validate, git diff --check Not-tested: GitHub-rendered binary preview
The lightweight runtime now shares the loopback CDP injection path across macOS and Windows. Windows application discovery covers standard installs, where.exe, and Microsoft Store package locations; process control uses tasklist.exe and taskkill.exe; persistence uses a user-level Task Scheduler task while macOS keeps its LaunchAgent path. Constraint: Windows ChatGPT Desktop is distributed through both conventional and Microsoft Store installation paths Constraint: The runtime must not modify app.asar, the application install, or code signatures Rejected: Require users to provide a fixed executable path | it breaks Store installs and per-user locations Confidence: medium Scope-risk: moderate Directive: Verify CDP availability against each future ChatGPT Desktop Windows release before changing launch arguments Tested: npm test (73 tests), npm run package:codex-skin-studio, node syntax checks, git diff --check Not-tested: Native Windows execution and Task Scheduler registration on this macOS host Related: https://help.openai.com/en/articles/9982051-using-the-chatgpt-windows-app
The injected switcher now refreshes the loopback theme catalog when opened and while mounted, while retaining the last injected list if the control worker is unavailable. This lets a newly created local theme appear in the Skins menu without restarting ChatGPT Desktop or manually re-injecting CSS.\n\nConstraint: Theme creation and theme switching run in separate processes\nRejected: Reinject CSS after every theme creation | changes the active visual skin and adds unnecessary renderer churn\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep /themes loopback-only and validate returned theme ids and names before rendering\nTested: npm test (73 tests), npm run package:codex-skin-studio, apply active theme, status active, loopback /themes, git diff --check\nNot-tested: Renderer visual inspection of the refreshed menu after a new theme is created
Manual skin switching and the persistence worker could inject different themes concurrently. The worker now shares an apply lock with the loopback control server, preventing recovery from racing a selected theme and causing verification to observe mixed state.\n\nConstraint: ChatGPT Desktop renderer injection is asynchronous and the persistence worker runs continuously\nRejected: Disable background recovery during manual switching | would leave renderer reloads unrecovered\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep all theme application paths behind the shared worker lock\nTested: npm test (74 tests), npm run package:codex-skin-studio, macOS persistence reinstall, miku and Xellos control-route switches, active renderer status\nNot-tested: Windows runtime switching
The Patriot Gold theme used a 2 MB PNG that expanded to a 2.8 MB data URL. ChatGPT Desktop decoded the image but silently dropped the oversized root background declaration, causing injection verification to fail. The injector now compresses oversized decoded Heroes to a smaller WebP data URL before assigning the stylesheet.\n\nConstraint: ChatGPT Desktop receives a self-contained CSS injection and cannot load arbitrary local file URLs\nRejected: Reject large themes | prevents valid user-generated skins from being applied\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep the original asset on disk; only compress the runtime CSS representation\nTested: npm test (74 tests), npm run package:codex-skin-studio, Patriot GET /apply returned HTTP 200, active Renderer heroLoaded=true and rootBackground=true\nNot-tested: Windows Canvas WebP encoding
Theme creation previously copied source image files unchanged, allowing multi-megabyte PNG heroes to enter the runtime stylesheet. The creator now converts every final hero, logo, and portrait asset to WebP and writes matching manifest names, using sharp when available and ffmpeg as a fallback.\n\nConstraint: The distributed Skill must accept PNG, JPEG, and WebP inputs without retaining oversized source assets\nRejected: Keep original extensions | reproduces the stylesheet size failure for generated PNG skins\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep source images outside the final theme directory; treat WebP output as the canonical runtime asset\nTested: npm test (74 tests), npm run package:codex-skin-studio, installed create-theme conversion of Patriot PNG to hero.webp\nNot-tested: WebP conversion on a machine with neither sharp nor ffmpeg
Patriot Gold Workbench had no visible brand because its manifest omitted copy.brand and the creator treated brand copy as optional. Generated themes now default copy.brand to the theme name when no logo or explicit brand is supplied, while an explicit --brand remains the override.\n\nConstraint: The live top workspace label must be replaced without altering project sessions or account controls\nRejected: Infer a brand from image OCR | unreliable and unnecessary when the theme name is authoritative\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep explicit --brand higher priority than the generated theme-name fallback\nTested: npm test (75 tests), package verification, installed Skill sync, Patriot reapply with styled brand present in injected CSS\nNot-tested: Logo-backed themes where the logo replaces the label
All generated themes previously shared one Baskerville italic gradient treatment because the manifest stored only brand text. The Skill now records a validated brandStyle preset selected from the Hero's visual language, and the injector renders preset-specific font stacks, casing, spacing, gradients, shadows, and decorations. Legacy themes receive keyword-based fallback inference.\n\nConstraint: The renderer must use local CSS and system font stacks without downloading fonts\nRejected: OCR or pixel-level font extraction | unreliable across generated artwork and desktop platforms\nConfidence: high\nScope-risk: moderate\nReversibility: clean\nDirective: Keep brandStyle as a constrained preset, not arbitrary CSS; choose it from the inspected Hero before theme creation\nTested: npm test (76 tests), package build, installed Skill sync, Patriot apply with military font, double-line decoration, and styled brand present\nNot-tested: Visual comparison on Windows font availability
Generated brand names now remove default // separators, while explicit user text remains unchanged. Preset decorations stay outside the glyphs. Constraint: Brand text must remain readable and clean across themed navigation styles Rejected: Remove all punctuation from explicit user copy | changes user-authored brand identity Confidence: high Scope-risk: narrow Reversibility: clean Directive: Do not place decorative rules inside the brand text span Tested: npm test (77 tests), package, installed sync, Patriot active CSS with no slash separator Not-tested: Windows visual font rendering
A successful skin application must not continue reporting a previous worker failure. Clear stale failure metadata after verified injection and renderer recovery, and document that long-lived workers must be re-registered after Skill upgrades.\n\nConstraint: Renderer CSS injection is in-memory and persistence uses a separate long-lived process\nRejected: Hide the prior error only in the UI | leaves state.json misleading for CLI and worker diagnostics\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Re-register the native persistence worker after syncing Skill code\nTested: npm test (78 tests), switcher applied Slayers and Patriot, status active, five themes listed\nNot-tested: Windows visual rendering
The Pet plan separates the floating companion from the main skin runtime and makes cartoonized anthropomorphic large-head/small-body art a hard visual contract. Codex Image Generation supplies references and action frames; deterministic local tooling assembles and validates the 8x9 atlas.\n\nConstraint: ChatGPT Desktop owns the Pet Overlay and current animation row mapping\nRejected: Generate and install one opaque 8x9 image in a single model call | frame alignment and character consistency are unreliable\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep Pet generation separate from main-window CSS injection and do not modify app.asar\nTested: npm test (78 tests), git diff --cached --check\nNot-tested: Actual hatch-pet generation and Windows visual rendering
The Pet plan now separates confirmed decisions from the observed ChatGPT Desktop contract that must be frozen before coding. It defines the MVP boundary, stable CLI commands, cross-platform paths, transactional installation, machine and Vision validation, and a concrete test matrix.\n\nConstraint: Pet animation and manifest behavior remain owned by ChatGPT Desktop and hatch-pet\nRejected: Hard-code community animation rows before an observed contract | incompatible packages would appear installable\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Do not implement installers until contract.json is captured from the current app\nTested: npm test (78 tests), git diff --cached --check\nNot-tested: Actual hatch-pet contract capture and Pet overlay rendering
The Skill now assembles contract-driven cartoon anthropomorphic large-head/small-body Pet atlases, validates RGBA WebP output, installs Pet packages atomically, and creates paired theme/Pet bundles. A paired switch applies the theme and records the required official Pets Refresh action without pretending that Pet selection completed.\n\nConstraint: The current ChatGPT Desktop build exposes no observable Pets or hatch-pet contract in this environment\nRejected: Modify app.asar or automate undocumented Settings internals | unsupported and unsafe across app updates\nConfidence: medium\nScope-risk: broad\nReversibility: clean\nDirective: Replace the provisional contract only after capturing a real hatch-pet contract and verifying Refresh, selection, and /pet on macOS and Windows\nTested: npm test (82 tests), all new scripts syntax-checked, packaged Skill verified, installed Skill synced, persistence worker re-registered\nNot-tested: Native hatch-pet contract, real Pet overlay rendering, Windows manual end-to-end switch, native Image Generation output for the sample mascot
The public Web sprite-sheet dimensions are useful for deterministic validation, but the local ChatGPT Desktop build still does not expose the hatch-pet manifest or native selector. Record that distinction, enforce the published size limit, and keep paired switching truthful until a real Desktop postcondition is observed.\n\nConstraint: ChatGPT Desktop Pet selection and hatch-pet schema are not exposed by the inspected build\nRejected: Treat the public Web upload format as a frozen Desktop contract | would risk installing an unrecognized Pet\nConfidence: high\nScope-risk: moderate\nReversibility: clean\nDirective: Do not remove the provisional contract gate without capturing a real Desktop Refresh and /pet result\nTested: npm test (83/83); package:codex-skin-studio; installed Skill sync; persist status; pet status; git diff --check\nNot-tested: Native ChatGPT Desktop Pet Refresh, selection, and /pet end-to-end on macOS or Windows
Document the supported official Windows Codex and ChatGPT Desktop workflow and keep the external runner, packaging, runtime discovery, persistence, and tests aligned with that workflow. Constraint: The Codex renderer must not restart itself from the current Agent process; Windows MSIX activation must preserve loopback CDP arguments. Rejected: Direct apply.mjs restart from the Agent process | it can terminate the renderer that owns the active operation. Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep Windows apply and update operations on the external PowerShell runner and accept only applied or active as success. Tested: npm test; npm run package:codex-skin-studio; node --check scripts/package-codex-skin-studio.mjs; real Windows runner returned applied and status returned active. Not-tested: Windows symlink security test requires Developer Mode or elevated symlink privileges.
The Store Desktop E2E failure was reduced to a single JSON opening brace because the runner emitted only Exception.Message. Emit the full exception representation so external Windows failures remain actionable without weakening success checks. Constraint: The Windows runner is the only observable boundary on a remote GUI runner Rejected: Treat a scheduled or partially printed result as success | it hides the actual CDP failure Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep full exception diagnostics in the external runner Tested: npm test 86/86; npm run test:windows 3/3; package validation; prior Windows E2E failure reproduced the truncated diagnostic Not-tested: Windows E2E after diagnostic change
PowerShell converted multiline Node JSON diagnostics into separate error records, leaving the runner with only the opening brace. Capture the merged stream with Out-String and trim only after the exit-code check so validation and CDP failures remain fully actionable. Constraint: Windows runner diagnostics cross a PowerShell native-command boundary Rejected: Parse only the first error line | it loses the stable Node error code and message Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep native Node output as a complete string before checking LASTEXITCODE Tested: npm test 86/86; npm run test:windows 3/3; package validation; previous Windows E2E logs confirmed multiline truncation Not-tested: Windows E2E after stream capture correction
The Windows runner was collapsing child-process stderr into a single PowerShell error record, which hid the actual ChatGPT Desktop startup or CDP failure. Capture stdout and stderr through ProcessStartInfo and retain the full diagnostic while remaining compatible with Windows PowerShell argument handling. Constraint: The runner must support both Windows PowerShell and PowerShell 7 without editing the installed app. Rejected: Keep the PowerShell pipeline | It truncates multiline Node diagnostics in the GitHub runner. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Preserve the external AUMID launch path and do not move injection into app.asar. Tested: npm test; npm run test:windows; package and unzip validation; git diff --check Not-tested: Native Windows execution until the next GitHub Actions run
The previous Windows E2E installed ChatGPT Classic, which is a separate legacy app and does not expose the Codex Desktop renderer. Prefer the current OpenAI.Codex package and handle both Codex.exe and ChatGPT.exe process names in the external launcher. Constraint: The current ChatGPT Desktop migration separates ChatGPT Classic from the Codex-based desktop package. Rejected: Relax renderer discovery to accept arbitrary CDP pages | That would risk injecting into companion windows or unrelated browser targets. Confidence: high Scope-risk: moderate Reversibility: clean Directive: Keep the E2E pinned to the current Codex Desktop Store product and update the product ID when OpenAI changes distribution. Tested: npm test; npm run test:windows; package and unzip validation; git diff --check Not-tested: Windows native run pending GitHub Actions
AUMID activation starts the current Store app but does not reliably preserve Chromium remote-debugging arguments. Resolve the signed executable from the MSIX manifest and launch it directly so the renderer exposes the loopback CDP endpoint required by skin injection, retaining AUMID only as a fallback. Constraint: Do not unpack, patch, or replace the MSIX package. Rejected: Treat an HTTP response from the CDP port as readiness | the target list can remain unavailable while the app is starting. Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Revalidate the executable path after every Store package update; never hard-code a versioned WindowsApps path. Tested: npm test; npm run test:windows; package and unzip validation; git diff --check Not-tested: Windows native run pending GitHub Actions
The current Codex package now starts with a reachable CDP port, but renderer discovery still rejects its targets. Include a safe type/title/url summary in the external runner error so the compatibility rule can be updated from observed data instead of guesswork. Constraint: Diagnostics must never include WebSocket URLs or private renderer state. Rejected: Accept every CDP target | companion windows and browser pages must remain excluded. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Use the observed Windows target URL and DOM contract to extend discovery only after verification. Tested: npm test; npm run test:windows; package and unzip validation; git diff --check Not-tested: Windows native target summary pending GitHub Actions
The current Windows Codex Desktop can expose its CDP endpoint while its target list is still warming up. Extend target discovery to a bounded ten-second window and emit a redacted pre-apply target summary for native diagnostics. Constraint: Discovery remains loopback-only and still filters to eligible app pages. Rejected: Remove the discovery timeout | a hung renderer must fail predictably. Confidence: medium Scope-risk: narrow Reversibility: clean Directive: Keep the timeout bounded and revisit it only with measured startup evidence. Tested: npm test; npm run test:windows; package and unzip validation; git diff --check Not-tested: Windows native run pending GitHub Actions
The Windows Codex CDP listener can be reachable before the renderer publishes any page target. Gate theme application on a bounded page plus WebSocket target check and report the observed target summary when the renderer never appears. Constraint: The wait is loopback-only, bounded to 60 seconds, and does not inspect private app state. Rejected: Apply immediately after port readiness | it causes false NO_ELIGIBLE_RENDERER failures during normal startup. Confidence: medium Scope-risk: narrow Reversibility: clean Directive: Keep page-target readiness separate from renderer eligibility; the Node selector remains the final safety gate. Tested: npm test; npm run test:windows; package and unzip validation; git diff --check Not-tested: Windows native run pending GitHub Actions
The current Windows Desktop renderer is hosted at the exact app://-/index.html page and uses a Codex title while not exposing the legacy shell class names. Keep #root and add this exact app identity to the main-target probe so theme injection reaches the correct page on Windows. Constraint: Renderer selection must remain strict and must not accept arbitrary app or browser pages. Rejected: Drop the DOM probe on Windows | CDP page identity alone does not prove that the renderer has mounted the application root. Confidence: high Scope-risk: moderate Reversibility: clean Directive: Recheck this exact URL/title contract after major ChatGPT Desktop renderer updates. Tested: npm test (86); npm run test:windows (3); package and unzip validation; git diff --check Not-tested: Windows native apply and Pet selection pending GitHub Actions
Windows Codex exposes Pets inside the Appearance settings page and labels the refresh action as custom-pet refresh. Extend the visible UI adapter to recognize both settings layouts and retain the same DOM-only selection and asset-loaded postconditions. Constraint: Use only visible Settings/Pets controls; do not read private state or alter the signed app. Rejected: Add Windows-specific private-state paths | community reports show those paths are unstable across native and WSL modes. Confidence: medium Scope-risk: moderate Reversibility: clean Directive: Keep the native adapter version stable until the visible Windows contract changes. Tested: npm test (86); npm run test:windows (3); package and unzip validation; git diff --check Not-tested: Windows native Pet selection pending GitHub Actions
The current Windows desktop window is titled Codex even after the product migration to ChatGPT Desktop. Try both visible window titles before sending the supported settings shortcut so the Pet adapter targets the actual app window. Constraint: Keep settings automation limited to foreground activation and Ctrl-comma; no private state or coordinates. Rejected: Send the shortcut globally | it can change settings in an unrelated foreground application. Confidence: medium Scope-risk: narrow Reversibility: clean Directive: Keep both titles until the Windows product rename is stable across installed builds. Tested: npm test (86); npm run test:windows (3); package and unzip validation; git diff --check Not-tested: Windows native Pet selection pending GitHub Actions
Windows settings automation still times out without exposing why. Retain the last DOM-only state sample in the timeout details so future compatibility changes can distinguish an unopened settings surface from a missing Pet control without logging private application state. Constraint: Diagnostics contain only settings slugs, booleans, custom Pet ids, and asset status. Rejected: Dump document text or private state | that can expose account and conversation data in CI logs. Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep timeout diagnostics redacted and use the visible UI contract as the source of truth. Tested: npm test (86); npm run test:windows (3); package and unzip validation; git diff --check Not-tested: Windows native Pet selection pending GitHub Actions
Windows Codex did not expose the macOS Pets settings slug after the keyboard shortcut. Add a DOM-visible Settings/Preferences fallback after the foreground shortcut and keep the Pet adapter on the same renderer without private-state access. Constraint: The fallback only clicks a visible button or link whose label identifies Settings or Preferences. Rejected: Use OS-level coordinates or internal route manipulation | both are fragile and outside the supported surface. Confidence: medium Scope-risk: moderate Reversibility: clean Directive: If future Windows builds expose a stable data-testid for Settings, prefer it over text matching. Tested: npm test (86); npm run test:windows (3); package and unzip validation; git diff --check Not-tested: Windows native Pet selection pending GitHub Actions
The paired theme and Pet workflow is implemented and macOS-verified, while the current Windows renderer only has theme-injection evidence. The clean Windows runner exposes no visible Settings control for native Pet selection, so the documentation and contract now preserve that blocker instead of overstating completion. The packaged Skill is refreshed with the current implementation.\n\nConstraint: Native Windows Pet selection requires an authenticated Desktop UI with visible Settings > Appearance > Pet\nRejected: Treat local Pet installation or theme injection as native Pet selection | those are not application postconditions\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Do not mark Windows Pet selection complete until selected-row and loaded-sprite postconditions are observed\nTested: npm test (86/86); npm run test:windows (3/3); Skill package archive validation; git diff --check\nNot-tested: Authenticated Windows Desktop native Pet selection\n
Windows Pet selection now uses broader visible semantic controls and supports a dedicated evidence command. The adapter keeps local installation and theme injection separate from native selection, while the workflow and documentation preserve explicit failures for unauthenticated or UI-incomplete sessions.\n\nConstraint: ChatGPT Desktop exposes no public third-party Pet selection API\nConstraint: Clean Windows CI may not expose authenticated Settings controls\nRejected: Private state, app.asar edits, or coordinate automation | unsupported and brittle\nConfidence: high\nScope-risk: moderate\nReversibility: clean\nDirective: Require selected-row and loaded-sprite postconditions before native success\nTested: npm test (87/87); npm run test:windows (3/3); node syntax checks; deterministic Skill package and archive validation\nNot-tested: Authenticated Windows Desktop native Pet selection\n
The Windows adapter now treats visible settings headings, dialogs, and semantic panel markers as Settings evidence. This prevents a real Settings page from being rejected solely because it omits the macOS data-settings-panel-slug attribute.\n\nConstraint: Only visible DOM semantics are supported\nRejected: URL or private-state-only detection | not a stable public UI postcondition\nConfidence: medium\nScope-risk: narrow\nReversibility: clean\nDirective: Keep native selection gated by selected-row and loaded-sprite checks\nTested: npm test (87/87); npm run test:windows (3/3); package archive validation\nNot-tested: Authenticated Windows Desktop native Pet selection\n
The implementation status now reports the current regression count and the dedicated Windows acceptance evidence command. The document continues to distinguish Windows theme injection from unverified native Pet selection.\n\nConstraint: Native Windows Pet evidence remains unavailable without an authenticated Desktop session\nRejected: Claim completion from automated path tests | they do not prove native selection\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Update the Windows contract record only after selected-row and loaded-sprite evidence\nTested: Documentation consistency review; prior npm test (87/87); prior Windows tests (3/3)\nNot-tested: Authenticated Windows Desktop native Pet selection\n
The current macOS System Events environment does not expose a usable menu bar or Settings control, so Pet verification must use the application shortcut and preserve a stable diagnostic when native selection cannot be reopened. This keeps the existing confirmed local Pet state separate from a fresh UI acceptance run.\n\nConstraint: Current macOS System Events does not expose a menu bar or Settings control\nRejected: Treat existing local Pet state as a fresh live selection | it does not prove a new UI run\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep native success gated by visible selected-row and loaded-sprite postconditions\nTested: npm test (87/87); npm run test:windows (3/3); actual macOS verifier returns PET_NATIVE_UI_UNAVAILABLE with diagnostics; package archive validation\nNot-tested: Authenticated Windows Desktop native Pet selection
Some ChatGPT Desktop builds expose Settings only after opening a visible account or profile menu. Extend the Pet adapter with that bounded UI path while keeping native selection gated by the existing visible postconditions.\n\nConstraint: ChatGPT Desktop does not expose a public Pet selection API\nRejected: Read private app state or use screen coordinates | unsupported and brittle\nConfidence: medium\nScope-risk: narrow\nReversibility: clean\nDirective: Keep account-menu matching restricted to visible semantic controls or avatar-backed menu buttons\nTested: npm test (87/87); npm run test:windows (3/3); package archive validation; macOS verifier returns PET_NATIVE_UI_UNAVAILABLE with diagnostics when no Settings/account control exists\nNot-tested: Authenticated Windows Desktop native Pet selection
The Windows native UI remains dependent on an authenticated interactive desktop, but the official hatch-pet format can be proven directly from the installed ChatGPT Desktop package. Add a platform-neutral contract probe and run it before Windows Pet UI acceptance.\n\nConstraint: Windows GitHub runners do not provide an authenticated interactive ChatGPT session\nRejected: Treat local atlas installation or theme injection as native Pet selection | those are different postconditions\nConfidence: high\nScope-risk: moderate\nReversibility: clean\nDirective: Keep bundled-contract verification separate from selected-row and loaded-sprite UI verification\nTested: npm test (88/88); npm run test:windows (3/3); macOS official contract probe; package archive validation; installed Skill sync\nNot-tested: Authenticated Windows Desktop native Pet selection
The latest Microsoft Store Desktop workflow proved that the official hatch-pet contract is present and matches the v2 validator on Windows. Record that evidence separately from the still-unverified authenticated native Pet selection step.\n\nConstraint: The GitHub runner has no authenticated interactive Desktop session\nRejected: Mark native Pet selection green from contract validation alone | contract and UI postconditions are independent\nConfidence: high\nScope-risk: narrow\nReversibility: clean\nDirective: Keep run 29590065014 as contract evidence only; replace the pending selection record only after selected-row and loaded-sprite evidence exists\nTested: Windows workflow 29590065014 contract step passed; contract JSON parse; git diff check\nNot-tested: Authenticated Windows Desktop native Pet selection
Generated Pet rows were accepted when every frame reused the same image, so a valid-looking atlas could render as a static mascot. Validate adjacent-frame pixel motion during Pet creation and installation, and strengthen the Skill prompts and regression fixtures to require state-specific pose changes.\n\nConstraint: ChatGPT Desktop consumes animation semantics from the v2 atlas rows and exposes no third-party animation API\nRejected: Infer animation from manifest names or local file count | neither proves visible motion\nConfidence: high\nScope-risk: moderate\nReversibility: clean\nDirective: Keep the readable motion threshold conservative; visual QA must still judge semantic action quality after machine validation\nTested: npm test (89/89); npm run test:windows (3/3); example Pet validation reports 11 animated rows; static duplicate-row rejection; package archive validation; installed Skill sync\nNot-tested: Native Windows Pet overlay animation on an authenticated Desktop
The public archive, Cloudflare Worker application, and paired theme support now travel together from the repository. The detail route falls back to bundled catalog data when remote D1 is partially seeded, while the public interface uses theme terminology consistently. Constraint: Existing skill runtime and public /skins URLs must remain compatible Rejected: Stage .omx and Playwright artifacts | local runtime state and screenshots are not source files Confidence: high Scope-risk: broad Reversibility: clean Directive: Keep Cloudflare deployment branch wiring explicit; wrangler deployments alone do not prove Git integration Tested: Root suite 91 tests; website typecheck; website tests 17; production build; browser route and visible-copy smoke checks Not-tested: Cloudflare dashboard Git integration settings are not exposed by the local repository or Wrangler deployment history
Give the public archive a crisp identity at browser and bookmark sizes using a small native SVG mark with the existing deep-blue, cyan, and white workbench palette. Constraint: The favicon must remain legible at 16px and require no runtime dependency Rejected: Generated raster artwork | unnecessary detail and a larger asset for a tiny browser surface Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep the favicon icon-only; do not add small text that becomes unreadable at browser sizes Tested: Website typecheck; production build; HTTP 200 icon route; generated favicon link smoke check Not-tested: Native browser tab rendering on every platform
Replace the quiet orbital icon with a higher-energy Codex mark: saturated blue-violet color, an open white C silhouette, a cyan diagonal spark, and a warm yellow star. The geometry stays simple enough to remain recognizable at favicon sizes. Constraint: Preserve the native SVG favicon route and keep the asset dependency-free Rejected: More detailed illustration | it would lose brand clarity below 32px Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep future favicon changes icon-only and test at small browser sizes Tested: Website typecheck; production build; icon route HTTP 200; SVG favicon link smoke check Not-tested: Native browser tab rendering on every platform
Publish the current skin studio implementation as one coherent delivery, including the Cloudflare-backed admin flows, merged Theme Package management, shared public/admin visual system, download grants, and archive skill updates. Constraint: User requested all current code changes be published together Rejected: Split the mixed worktree into separate commits | user explicitly requested one complete submission Confidence: medium Scope-risk: broad Reversibility: clean Directive: Keep generated runtime state and temporary repair scripts out of source commits Tested: npm run test (17 passed); Next.js production compilation; Playwright admin login and Theme Package visual smoke checks Not-tested: Full typecheck/build completion is blocked by website/src/lib/download-grant.ts:58 BufferSource typing error; npm run lint is stale under Next 16
Align the remote skin installer with the short-lived download grant flow so catalog entries cannot expose direct archive URLs and installs verify the granted checksum before extraction. Constraint: Published skin downloads now require server-issued grants Rejected: Preserve direct archive URLs in catalog metadata | bypasses explicit confirmation and grant expiry Confidence: high Scope-risk: narrow Reversibility: clean Directive: Keep grant URL validation and package checksum verification together Tested: Staged diff whitespace check; existing skin installer test suite Not-tested: Full TypeScript verification remains blocked by the known BufferSource typing error
Keep the distributable Skill and website deployment guidance aligned with the short-lived download grant flow introduced by the archive implementation. Constraint: Package archives are private and require a single-use grant Rejected: Leave generated Skill output and deployment docs stale | would advertise direct downloads and omit the required secret Confidence: high Scope-risk: narrow Reversibility: clean Directive: Regenerate the distributable Skill whenever remote download security changes Tested: npm run test (95 passed); staged diff whitespace check Not-tested: Full TypeScript verification remains blocked by the known BufferSource typing error
Keep the download-grant verifier safe for malformed payloads and align remote installer tests with the no-permanent-URL contract. Constraint: Grant tokens are untrusted input at the Worker boundary Rejected: Assume decoded payloads are objects and retain direct catalog URLs | malformed tokens and permanent URLs weaken the download boundary Confidence: high Scope-risk: narrow Reversibility: clean Directive: Treat decoded grant payloads and signature lengths as untrusted until validated Tested: npm run test (95 passed); staged diff whitespace check Not-tested: Full TypeScript verification remains blocked by the known BufferSource typing error
Make the short-lived package grant contract executable by covering successful verification, secret mismatches, tampering, expiry, and malformed tokens. Constraint: Download authorization must remain bound to the skin and package checksum Rejected: Rely only on route-level smoke checks | token validation needs direct regression coverage Confidence: high Scope-risk: narrow Reversibility: clean Directive: Extend these cases when grant claims or expiry semantics change Tested: npm run test (95 passed); staged diff whitespace check Not-tested: Direct website test runner configuration is not present in the current package scripts
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What changed
persist.mjsinstead ofapply.mjs; expose accuraterunningstatus.Why
The previous README described the legacy Codex Desktop product and did not explain the current ChatGPT Desktop Skill or persistence lifecycle. The new docs and package make the current implementation installable and verifiable.
Validation
npm test-> 114 passingnpm run package:codex-skin-studio-> passedunzip -tq output/codex-skin-studio.skill-> passedslayers-xellos-nightNotes
The Skill distribution remains English ASCII-only. GIF and video backgrounds are documented as future work; the MVP supports PNG, JPEG, and WebP. Full macOS reboot and ChatGPT Desktop update lifecycle testing remain outstanding.