Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
9 changes: 9 additions & 0 deletions .papercuts/troubleshooting.md
Original file line number Diff line number Diff line change
Expand Up @@ -311,3 +311,12 @@ owns; reopen the terminal before judging the final live state.
platform-independent test that exercises both certificate and keychain paths.
- A changelog search conflated the stable and prerelease lines. Verify published
package code before assuming a release contains the upstream patch.

## 2026-09-04: queued composer controls
- This detached worktree had no .memory directory. Read the canonical checkout's PROJECT-CONTEXT.md and PLANNED.md before implementation; wrote scoped memory here.
- Pi harness queueSteer/queueFollowUp are not exposed through the foreground durable transcript path. Use Stop → persistence barrier → normal append for the desktop Steer action and explain its behavior in the control tooltip.
- E2E TypeScript uses an older lib target; use reverse/find rather than Array.at in new test helpers.
- The selected local Xcode began rejecting compiler/git calls for unaccepted license terms during this task. Used the installed Command Line Tools for git and rebuilt the renderer/Electron bundles with existing native helpers; native sources are unchanged and CI checks the full build.
- Appearance persistence uses the `settings` envelope in settings.json; E2E disk assertions must read `settings.appearance`, then verify the preference after an app relaunch.
- A CI navigation test raced the provider transport: queue removal confirms durable append, but does not mean the mock HTTP server has received the next generation request. Wait for that specific request before asserting its conversation history.
- The shared button radius overrides legacy per-corner utility classes. Joined actions need an explicit shared group rule: square inner seams, the common outer squircle radius, and visible overflow for focus outlines. Check hover fills and each seam's corner radius, not only the uniform outer radius.
2 changes: 2 additions & 0 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,8 @@ The current plan inventory and status live in [`docs/plans/README.md`](docs/plan

## UI design references

Follow `docs/design-guide.md` for reusable action shapes, semantic tokens, and accessibility. Reuse the shared squircle button treatment for new and existing actions rather than introducing per-screen button geometry.

Before adding or materially restyling any UI element or component, always review both `docs/chatgpt-desktop-ui-inspiration.md` and `docs/chatgpt-ui-element-specimen.html` for interaction, styling, state, motion, and accessibility inspiration. Adapt the references to Aiden's existing visual language rather than copying them blindly, and use the semantic design tokens in `renderer/styles.css` and `renderer/shared/appearance.ts` instead of introducing one-off colors.

Do not put decorative borders or outlines around radio-button choice cards. Communicate selection with the radio control and existing background-state tokens instead. Always preserve visible keyboard `focus-visible` rings or outlines for accessibility.
Expand Down
2 changes: 2 additions & 0 deletions docs/chatgpt-desktop-ui-inspiration.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ Research date: 2026-07-18

## Scope and confidence

For current reusable Aiden components and shape rules, follow the [design guide](design-guide.md). The observations below provide historical interaction inspiration.

This audit covers the installed `/Applications/ChatGPT.app`, build `26.715.31925` (`com.openai.codex`). Although the app is displayed as ChatGPT, its package and renderer identify it as the current ChatGPT-branded Codex desktop product. The findings therefore mix classic Chat, Codex agent, project, review, browser, and terminal flows.

Evidence used:
Expand Down
27 changes: 22 additions & 5 deletions docs/chatgpt-ui-element-specimen.html
Original file line number Diff line number Diff line change
Expand Up @@ -30,8 +30,9 @@
--success: #087c58;
--warning: #9a6700;
--radius-control: 10px;
--radius-button: 16px;
--radius-popover: 12px;
--radius-composer: 20px;
--radius-composer: 40px;
--radius-dialog: 16px;
--shadow-hairline: 0 0 0 0.5px rgb(0 0 0 / 0.1);
--shadow-control: 0 1px 2px -1px rgb(0 0 0 / 0.08);
Expand All @@ -45,7 +46,7 @@
--duration-relaxed: 300ms;
--ease-enter: cubic-bezier(0.19, 1, 0.22, 1);
--ease-snappy: cubic-bezier(0.23, 1, 0.32, 1);
--focus: 0 0 0 3px rgb(11 125 229 / 0.24);
--focus: 0 0 0 2px rgb(24 24 23 / 0.55);
}

html[data-theme="dark"] {
Expand Down Expand Up @@ -78,14 +79,26 @@
--shadow-composer: var(--shadow-hairline), 0 3px 12px rgb(0 0 0 / 0.46);
--shadow-toast: var(--shadow-hairline), 0 5px 16px rgb(0 0 0 / 0.5);
--shadow-dialog: var(--shadow-hairline), 0 24px 48px -12px rgb(0 0 0 / 0.72);
--focus: 0 0 0 3px rgb(75 156 242 / 0.3);
--focus: 0 0 0 2px rgb(245 245 243 / 0.55);
}

* { box-sizing: border-box; }
html { background: var(--bg); }
body { margin: 0; color: var(--text); background: var(--bg); font-size: 14px; line-height: 1.45; }
button, input, textarea { font: inherit; }
button { color: inherit; }
:root :is(button, [role="button"], .button):where(:not([role="switch"]):not([role="radio"]):not([role="checkbox"])) {
border-radius: var(--radius-button);
corner-shape: squircle;
}
:root :is(button, [role="button"], .button):focus-visible {
outline: 2px solid var(--text-secondary);
outline-offset: 2px;
}
.squircle-action-group { display: inline-flex; border-radius: var(--radius-button); corner-shape: squircle; background: var(--control); }
:root .squircle-action-group > .button { border-radius: 0; }
:root .squircle-action-group > .button:first-child { border-start-start-radius: var(--radius-button); border-end-start-radius: var(--radius-button); }
:root .squircle-action-group > .button:last-child { border-start-end-radius: var(--radius-button); border-end-end-radius: var(--radius-button); }
code { font-family: "SFMono-Regular", "SF Mono", Menlo, monospace; font-size: 12px; }

.topbar {
Expand Down Expand Up @@ -232,7 +245,7 @@
.approval-actions { display: flex; justify-content: flex-end; gap: 7px; margin-top: 12px; }
.composer-wrap { position: absolute; right: 18px; bottom: 16px; left: 18px; }
.context-strip { display: flex; width: fit-content; max-width: calc(100% - 20px); min-height: 28px; align-items: center; gap: 6px; margin: 0 10px -3px; padding: 4px 9px 7px; border-radius: 11px 11px 0 0; background: var(--control); color: var(--text-secondary); font-size: 11px; }
.composer { padding: 10px; border-radius: var(--radius-composer); background: var(--surface-raised); box-shadow: var(--shadow-composer); }
.composer { padding: 10px; border-radius: var(--radius-composer); corner-shape: squircle; background: var(--surface-raised); box-shadow: var(--shadow-composer); }
.composer textarea { width: 100%; min-height: 58px; padding: 4px 5px; border: 0; outline: 0; resize: none; background: transparent; color: var(--text); }
.composer textarea::placeholder { color: var(--text-tertiary); opacity: 1; }
.composer-footer { display: flex; align-items: center; justify-content: space-between; gap: 8px; }
Expand Down Expand Up @@ -439,7 +452,7 @@ <h1>Controls that feel quiet until you touch them.</h1>
<section class="section">
<div class="section-head">
<h2>Button vocabulary</h2>
<p>Neutral buttons gain only a small surface and shadow change. Primary actions carry the accent. Ghost buttons stay flat. Pressed states move inward through an inset shadow rather than bouncing or shifting layout.</p>
<p>All actions reuse the same soft squircle shape, including icon buttons. Use the shared Button and 16px button radius; the composer uses a broader 40px radius. Neutral buttons gain a small surface and shadow change. Primary actions carry the accent, ghost buttons stay flat, and keyboard focus remains visible. See the <a href="design-guide.md">design guide</a> for reuse rules.</p>
</div>
<div class="cluster">
<button class="button primary" type="button">Send message <span aria-hidden="true">↑</span></button>
Expand All @@ -448,6 +461,10 @@ <h2>Button vocabulary</h2>
<button class="button glass icon" type="button" aria-label="New chat">+</button>
<button class="button danger" type="button">Deny</button>
<button class="button" type="button" disabled>Unavailable</button>
<div class="squircle-action-group" role="group" aria-label="Joined action example">
<button class="button ghost" type="button">Open</button>
<button class="button ghost icon" type="button" aria-label="Choose destination">⌄</button>
</div>
</div>
<div class="section-spacer"></div>
<div class="state-grid" role="group" aria-label="Neutral button state comparison">
Expand Down
54 changes: 54 additions & 0 deletions docs/design-guide.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
# Aiden design guide

## Reusable action shapes

Use the shared `Button` from `renderer/components/ui.tsx` for actions, including
icon-only controls and links rendered with `asChild`. Labeled and icon-only
buttons use the same soft squircle shape. Choose the existing size and variant
for emphasis; do not add a separate pill or circular button variant.

| Surface | Reuse | Geometry |
| --- | --- | --- |
| Buttons, toolbar actions, navigation actions, and button links | `Button`, or the shared action rule in `renderer/styles.css` for existing native buttons | `--radius-button: 16px` and `corner-shape: squircle` |
| A custom visual that must follow a button's silhouette, such as its artwork mask | `.squircle-control` | The same button radius and corner shape |
| Joined actions, such as an action with a separate menu trigger | `.squircle-control.squircle-action-group` around direct `Button` children | 16px outer corners, square internal seams |
| Chat composer | `.composer-shell` | `--radius-composer: 40px` and `corner-shape: squircle` |

The renderer's action rule also covers existing `button`, `[role="button"]`, and
`[data-slot="button"]` elements, including the compact dictation window. Reuse
that rule instead of adding per-screen geometry. Radio indicators, checkboxes,
and switch tracks retain their recognizable selection shapes. Text fields keep
their existing field geometry and focus treatment.

Use native CSS geometry in the Electron renderer. Keep shadows on the shaped
element and preserve visible overflow for menus, badges, and focus rings. Apply
clipping only to an inner artwork mask that needs it, never to the whole action
or composer. No JavaScript path generation or new dependency is needed.

Joined actions reuse the group rule instead of per-corner utility overrides.
Their individual hover and focus fills meet at straight seams, while the group
and its end buttons share the outer squircle. Leave the group overflow visible
so each button's keyboard outline and portaled menus remain unobstructed.

## Color, state, and accessibility

Reuse semantic surface, text, accent, status, and elevation tokens from
`renderer/styles.css` and `renderer/shared/appearance.ts`. Shape does not change
an action's meaning: primary actions retain their accent, destructive actions
retain their semantic treatment, and transparent actions gain a soft fill on
hover. Avoid decorative borders and outlines.

Preserve neutral `focus-visible` outlines on non-text controls, accessible labels
for icon actions, disabled semantics, and existing hit-target sizes. Text-entry
focus uses fill and caret changes without a new border or ring. Reuse existing
hover and press feedback and respect Reduce Motion; do not animate the corner
shape or add layout shifts.

## Verification

Check shared and custom actions in onboarding, the chat toolbar and composer,
queued-message dialogs, Settings, and compact windows. Exercise hover, keyboard
focus, disabled states, light and dark themes, narrow layouts, and overflow
menus. The interactive [element specimen](chatgpt-ui-element-specimen.html)
demonstrates the same geometry. Extend the button appearance contract and
Electron interaction tests when these rules change.
Loading