- Default context panel to closed; persist open/close state per session
in chatSessionStore (in-memory, not localStorage)
- Redesign panel sections as widget cards with bordered containers and
filled headers, replacing the accordion pattern
- Show worktree list directly in workspace widget instead of count text
- Migrate icons from lucide-react to @tabler/icons-react
- Clean up placeholder section copy
* fix: refresh sidebar when project is edited from Projects page
Route loadProjects() through the Zustand projectStore instead of
calling listProjects() directly so mutations update the sidebar.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: prevent project edit dialog from resetting form fields mid-typing
The useEffect that populated form fields ran on every editingProject prop
change. Since AppShell recreated this object on every render, any parent
re-render would reset all form fields, losing user input.
- Track dialog open transition with prevOpenRef to only populate on open
- Track editingProject.id with prevEditingIdRef for project identity changes
- Memoize editingProject prop in AppShell to stabilize object reference
- Add 12 tests covering form state preservation behavior
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use stable Zustand selector to prevent fetch loop in ProjectsView
Address PR review feedback: useProjectStore() subscribed to the full
store, causing loadProjects to be recreated on every state change and
triggering repeated IPC calls. Select fetchProjects directly for a
stable reference.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* UI polish: provider icons, dynamic placeholder, sidebar refinements
- Add provider icons (Goose, Claude Code, Codex) to the provider
selector dropdown and trigger button
- Make chat input placeholder dynamic based on selected provider
("Message Claude Code, @ to mention personas")
- Lighten placeholder text color and font weight
- Update toolbar button variant to use text-foreground
- Fix dropdown icon alignment for single-line vs multi-line items
- Hide sidebar scrollbar while preserving scroll functionality
- Shrink sidebar collapse toggle button from 32px to 24px
- Add right padding to chat row for ellipsis menu breathing room
- Extract formatProviderLabel as shared utility
* fix code review issues: lint, dead code, theme token, tests
- Remove unused Plus import and onNewChat prop from Sidebar
- Fix Biome formatting in ChatInputToolbar, ProviderIcons, HomeScreen
- Fix invalid text-foreground-muted token to text-muted-foreground
- Remove dead onCreateProjectFromFolder prop chain across all components
- Fix CodexIcon hardcoded white fill to transparent
- Update tests for renamed labels (provider, project, placeholder)
- Remove extra blank line in Sidebar
* fix e2e smoke test for updated placeholder text
Update Playwright regex to match new placeholder format
"Message {name}, @ to mention personas".
* fix keyboard accessibility for show-on-hover sidebar buttons
Add group-focus-within:visible and group-focus-within:opacity-100
so the "New project" and item menu buttons are reachable via tab
navigation, not just mouse hover.
* fix: sidebar project/recent items hover text and styling
- Style project items to match recent chat row appearance (padding, gap, font-light)
- Fix hover text color on project and recent items by adding relative z-10
to the projects section so it renders above the sliding highlight overlay
- Use group-hover for consistent text color change across the full row
- Switch sidebar settings to top bar, remove overflow-hidden on main
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve biome lint errors
Replace `any` with `unknown` in debounce, remove unused biome-ignore
comments, fix exhaustive-deps warning, and suppress static element
interaction lint for hover wrapper div.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: extract useSidebarHighlight hook to stay under file size limit
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(chat): add context panel toggle to ChatView
- Introduced a context panel in ChatView that can be opened or closed via a button, enhancing the user interface by allowing users to manage context visibility.
- Updated the layout to accommodate the context panel, ensuring a responsive design that maintains usability.
- Added imports for new components and adjusted state management to handle the context panel's open/close state.
This change improves the overall chat experience by providing users with more control over the interface elements they wish to view.
* feat(chat): integrate @tabler/icons-react for context panel toggle
- Added @tabler/icons-react to the project dependencies to enhance icon usage.
- Replaced existing icon imports in ChatView with Tabler icons for better visual consistency.
- Updated the context panel toggle button to utilize the new icons, improving the user interface.
- Refactored the ContextPanel component to implement tabs for better organization of content.
This update enhances the chat interface by providing a more modern and visually appealing icon set, while also improving the overall user experience with better content organization.
* chore: transition from lucide-react to @tabler/icons-react for icon usage
- Updated AGENTS.md to reflect the migration from `lucide-react` to `@tabler/icons-react` for icon components.
- Adjusted ChatView to maintain existing `lucide-react` usage until full migration is complete.
- Enhanced documentation to guide future icon implementation.
This change ensures a consistent iconography across the project while preparing for a complete transition to the new icon library.
* refactor(git): streamline git state retrieval and improve code readability
- Consolidated the retrieval of the current repository root and branch into a more concise format.
- Enhanced the readability of the code by restructuring the way worktree paths and branches are processed.
- Improved the handling of dirty file counts by maintaining consistent function calls.
These changes optimize the git state retrieval process and enhance code clarity, making future maintenance easier.
The Tailwind v4 upgrade (#85) replaced dialog components with Radix UI
primitives that use aria-labelledby instead of aria-label. Update E2E
tests to check DialogTitle h2 text instead of missing aria-label attrs,
and use getByRole("button", { name: "Close" }) for the X close button.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Add descending updatedAt sort for project chat lists in sidebar so new chats appear at the top instead of the bottom
- Increase MAX_VISIBLE_CHATS from 3 to 5 so more chats are visible before the 'Show more' button
* feat(chat): enhance image handling in chat input and views
- Added image resizing functionality to optimize pasted images before sending.
- Updated ChatInput to utilize the new resizing feature when adding images.
- Modified ChatView and AppShell to support initial image state and handle images in message sending.
- Adjusted HomeScreen to pass images along with messages during chat initiation.
This improves the user experience by ensuring images are properly processed and displayed in the chat interface.
* refactor(chat): centralize PastedImage type definition
- Moved the PastedImage type definition from ChatInput to a shared types file for better code organization and reusability.
- Updated imports in ChatInput, ChatView, HomeScreen, and AppShell to reference the new location of PastedImage.
This change enhances maintainability by ensuring a single source of truth for the PastedImage type across the application.
* refactor(chat): extract resizeImage to lib and fix formatting
* fix(chat): enhance initial message handling in ChatView
- Updated the condition for sending the initial message to include checks for both initialMessage and initialImages, ensuring that images are also sent when available.
- This change improves the functionality of the chat interface by allowing for a more comprehensive initial message setup.
* fix(chat): fix formatting and type error in initial message handler
* feat: import boss-ui components + upgrade to Tailwind v4
- Upgrade Tailwind CSS v3 → v4 with @tailwindcss/postcss, tw-animate-css
- Replace tailwind.config.js with CSS @theme blocks in globals.css
- Import boss-ui token system (semantic backgrounds, borders, text, shadows,
shapes, typography scale, animations, layout tokens)
- Import 49 shared UI components from squareup/boss-ui
- Import 48 AI element components from squareup/boss-ui
- Import 4 hooks from squareup/boss-ui
- Install all required dependencies (Radix UI primitives, UI libs, content
libs, form/utility libs)
- Migrate all 35+ feature files from custom tokens to standard shadcn/boss-ui
tokens (bg-background, text-foreground, bg-accent, text-muted-foreground,
border-border, etc.)
- Align to boss-ui visual language: flat border-driven design, no elevation
on sidebars/inputs, shadow-popover for menus, shadow-card for dialogs
- Fix low-contrast text by removing opacity modifiers on text-muted-foreground
- Update biome.json, tsconfig.json, check-file-sizes.mjs for imported code
- Re-add custom Button variants (toolbar, xs, icon-sm, icon-lg)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: swap vanilla HTML to boss-ui components
- Replace hand-rolled dialogs with Dialog/DialogContent in
CreateSkillDialog, CreateProjectDialog, PersonaEditor
- Replace delete confirmations with AlertDialog in AgentsView,
ProjectsView, SkillsView, SettingsModal, DoctorCheckRow
- Replace raw <input> with Input component (6 instances)
- Replace raw <textarea> with Textarea component (3 instances)
- Replace raw <select> with Select/SelectTrigger/SelectContent/
SelectItem (5 instances)
- Replace raw <label> with Label component throughout
- Replace <input type="checkbox"> with Checkbox component
- Replace div border-t dividers with Separator in settings
- Fix Radix SelectItem empty-string value crash by using sentinel
- Set sidebar to bg-background
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use default Button variant for send and remove focus ring on textarea
Use the boss-ui Button default variant (bg-primary) for the send button
instead of custom bg-foreground overrides. Suppress the global
focus-visible ring on the chat textarea to prevent the black outline.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add Cash Sans Wide display font to headlines
- Download Cash Sans Wide font files (5 weights) from boss-ui
- Add @font-face declarations in globals.css
- Switch page titles, settings headings, home clock/greeting, and
chat empty state to font-display (Cash Sans Wide) with tracking-tight
- Use Badge component with secondary variant for PersonaCard pills
- Remove redundant "Personas" section subtitle
- Upgrade "Active Agents" heading to display font
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: swap remaining vanilla HTML to boss-ui components
Replace ~56 raw <button> elements across 20 files with the Button
component, hand-rolled toggle groups with ToggleGroup, img/div avatar
patterns with Avatar, animate-pulse skeletons with Skeleton, and a
raw <input> with Input.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: move ai-elements into shared/ui directory
Relocate src/components/ai-elements/ to src/shared/ui/ai-elements/
to colocate with the rest of the boss-ui component library. No import
updates needed as these components are not yet consumed.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: remove mono font from skill names
Use default sans-serif for skill names in the list and create dialog
to match persona card styling. Keep mono only for instructions textarea.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: swap chat sub-components to boss-ui ai-elements
Replace hand-rolled ToolCallCard, ThinkingBlock, and MarkdownContent
with the ai-elements Tool, Reasoning, and MessageResponse compounds.
Action buttons now use MessageAction with built-in tooltip support.
Add @source for streamdown so Tailwind generates its utility classes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: prevent whole chat pane from scrolling
Add overflow-hidden to main content area so the flex layout chain
properly constrains scrolling to the MessageTimeline, keeping the
chat input and status bar pinned at the bottom.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: prevent document-level scrolling in chat view
Two issues caused the entire page to scroll when viewing chat:
1. scrollIntoView() in MessageTimeline scrolls all ancestors including
the document. Replaced with container.scrollTo() which only scrolls
within the message timeline container.
2. Tailwind v4 preflight doesn't set height/overflow on html/body like
v3 did. Added height: 100% + overflow: hidden on html, body, #root
outside @layer base so the cascade can't override them.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: prevent tool call results from overflowing chat viewport
Add min-w-0 and w-full to message content containers so flex items
respect the max-w-[85%] boundary. Wrap tool output pre blocks with
whitespace-pre-wrap so result text flows within the code block.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use accent color for text selection highlight
The previous selection background (#1a1a1a) was nearly invisible against
the dark input background. Now uses the user's accent color at 60% opacity.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: minimize tool call UI — remove icon, borders, and completed badge
Strip visual noise from collapsed tool calls: remove wrench icon
(via optional showIcon prop), remove border/rounded container, replace
status pill with plain text, hide "Completed" status entirely, and
use inline chevron caret next to the tool name.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: center sidebar icons in collapsed state
Add gap-0 to collapsed button styles to prevent hidden text spans
(w-0 opacity-0) from creating flex gaps that shift icons off-center.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: align button, input-group, and toggle to pill shape
Restore rounded-full on button base and remove redundant rounded-md
from size variants. Update input-group container to rounded-full and
toggle to rounded-full to match the pill design language.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: override browser text-align:center default on buttons
Browsers default <button> to text-align:center. This causes short text
inside flex-1 spans to appear centered even when justify-start is set,
since justify-start controls flex child positioning but text-align
controls text within those children.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: replace main's color tokens with our theme tokens
The merge from main brought in color tokens (foreground-tertiary,
foreground-secondary, background-primary, background-tertiary, etc.)
that don't exist in our theme. Map them to our equivalents:
- foreground-tertiary/secondary → muted-foreground
- foreground-danger → destructive
- background-primary → background
- background-tertiary → accent
- background-danger → destructive
- border-border-secondary → border-border
Fixes invisible send button arrow (text-background-primary → text-background).
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add compat color scales and register brand/danger in theme
The Tailwind v4 theme resets all colors with --color-*: initial then
only declares a minimal palette. This silently broke ~120 class usages
across ai-elements that rely on standard Tailwind scales (red-400,
green-600, zinc-800, etc.).
Add compat color stops for the specific scales actually used:
- red-{50,400,500,600,700,900}
- green-{400,500,600,700,900}
- blue-{400,500,600,700,900}
- yellow-{400,500,600,700,900}
- orange-{100,400,600,700,900}
- zinc-{100,400,800,950}
- amber-500
Also register brand and danger in @theme inline so Tailwind can
generate text-brand, bg-brand, text-danger, etc. utilities.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address PR review — SidebarRail type + artifact link policy
1. Add type="button" to SidebarRail button to prevent accidental form
submissions per AGENTS.md requirement.
2. Restore artifact policy enforcement for markdown links in chat.
The switch to MessageResponse/Streamdown lost the link interception
that enforced allowed roots. Extract useArtifactLinkHandler hook
that intercepts local link clicks via event delegation and routes
them through useArtifactPolicyContext.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: restore artifact open-file actions in tool call cards
The switch from ToolCallCard to ToolCallAdapter dropped the artifact
policy integration that showed "Open file" buttons on tool results.
Add ArtifactActions component that uses resolveToolCardDisplay from
ArtifactPolicyContext to render primary and secondary open actions
with path safety enforcement.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: add confidence labels, blocked reasons, and artifact policy tests
ArtifactActions was missing "detected" labels for low-confidence
candidates and per-candidate blockedReason text. This made the
feature appear broken even though the plumbing was correct. Also
adds test coverage for ToolCallAdapter artifact integration and
useArtifactLinkHandler to prevent future regressions.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat(chat): enhance chat input components with project color and icon support
- Added optional `color` property to `ProjectOption` interface for project color representation.
- Updated `ChatInputSelectorItem` to include an optional `icon` property for enhanced item display.
- Introduced `ProjectDot` component in `ChatInputToolbar` to visually represent project colors.
- Modified `ChatView` and `HomeScreen` to utilize the new `color` property for projects.
- Improved button components to support left and right icons for better UI flexibility.
* fix: apply biome formatting and guard asChild against icon props
* fix: add new project includes to the bottom instead of the top
Previously, `buildEditorText` placed `include:` lines at the top of
the editor text, above the prompt. This meant clicking "Add directory"
would insert the new include above any text the user had already typed.
Now includes are placed at the bottom of the editor as a trailing block,
and `parseEditorText` collects them from the bottom instead of the top.
This feels more natural — the user's prompt text stays at the top and
directory includes accumulate below it.
No migration needed: workingDirs and prompt are stored separately in
project.json, and `buildEditorText` reconstructs the editor text in
the new layout when the dialog opens.
* fix: parse project includes anywhere in prompt editor
Without an explicit [[bin]] section, Cargo uses the package name 'goose2'
as the binary name. macOS uses the process/binary name for the Dock and
App Switcher labels in dev mode, so the app appeared as 'goose2' instead
of 'Goose'.
* refactor: remove top-level tabs
Replace tab-based navigation with a single active session flow in the app shell and sidebar. Remove the persisted ui_state save/load path from the frontend and Tauri backend, keeping only the unrelated home-directory command in a dedicated system command module. Update affected tests and fixtures to match the new session-only model.
* feat: restore top bar home button
* feat: add image paste support to chat input
Users can now paste screenshots and images directly into the chat input with Cmd+V. Pasted images show as thumbnails with a click-to-expand lightbox and a hover-reveal remove button. Images are forwarded to the ACP agent as base64 content blocks alongside the text prompt.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: update ChatInput tests for new images argument
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: scope object URL cleanup to unmount only
Revoke only runs on component unmount (via a ref to latest images),
not on every add/remove. Previously the effect's cleanup re-ran on
every images state change, revoking URLs that were still in use.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: render image content blocks in message timeline
Add 'image' case to renderContentBlock in MessageBubble so pasted
images appear in the chat history after sending. Base64 sources are
rendered as data: URLs; URL sources rendered directly.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* fix: handle image-only sends and clean up debug logs
- Pass a single space as prompt when images are present but text is empty,
preventing goose from rejecting empty-text ACP content blocks
- Make images in the message timeline clickable via lightbox (ClickableImage)
- Suppress Radix Dialog aria-describedby warning in ImageLightbox
- Remove temporary debug console.logs
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* feat: add drag-and-drop image support to chat input
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
* refactor: extract ClickableImage to fix file-size lint limit
MessageBubble.tsx was 516 lines (limit 500). Moves ClickableImage
into its own file to bring it under the limit.
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
Add select-none to the tab container className, consistent with
how other interactive elements like dropdown menus are styled.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
When a user sends a message from a "New Chat" tab, the session title
now updates instantly from the message text instead of waiting for the
full AI response to complete (acp:done) or the backend title generation
(acp:session_info). This gives immediate feedback in the sidebar and
tab bar.
The backend-generated title from acp:session_info will still overwrite
this initial title if it arrives later, providing the best of both
worlds: instant feedback + quality titles.
Intercepts the Cmd+W keydown event in the AppShell keyboard handler
to close the current active tab via closeAndCleanupTab. When no tab
is active, the shortcut is swallowed with no effect.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: centralize provider selection state in agentStore
Move provider discovery and selection from per-component state to a
shared store, ensuring the selected provider persists across screens
and is loaded once on app startup. Adds loading state for the provider
dropdown and removes hardcoded provider labels in favor of API data.
* fix: restore default provider after persona override
* feat: wire ACP token/context info into status bar and chat input
Surface model name and context window usage in the UI:
- Redesign StatusBar with Bot icon and model name display
- Add contextLimit to TokenState for context window tracking
- Wire tokenState from chatStore through ChatView to ChatInput
- Add acp:usage_update event listener in useAcpStream (ready for
backend plumbing)
The ContextRing in ChatInputToolbar will activate once the backend
emits acp:usage_update events with context window size data.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: show truncated session ID next to copy button in status bar
The previous change hid the session ID text and only showed the copy
icon. Restore the first 8 characters of the session ID as visible text.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: remove always-red status dot from StatusBar
The status dot was permanently red because `setConnected(true)` is
never called anywhere in the codebase. Remove the dead code: the dot,
the statusColor map, the status prop, and the connectionStatus
derivation in AppShell.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: use npx for biome in justfile fmt-check recipe
The bare `biome` command fails when invoked from lefthook's pre-push
hook because node_modules/.bin isn't on PATH. Use `npx biome` to
match the pattern used in pre-commit hooks.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: respect direct accumulatedTotal in updateTokenState reducer
The reducer always recomputed accumulatedTotal as accumulatedInput +
accumulatedOutput, silently dropping any directly-passed value. This
meant acp:usage_update events (which only provide a total used count)
were ignored, keeping the context ring at 0.
Now partial.accumulatedTotal takes precedence when provided, falling
back to the input + output sum otherwise.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
- Pin @biomejs/biome to exact version 2.4.9 (was ^2.4.6)
- Remove biome hermit package (bin/biome, bin/.biome-2.4.9.pkg)
- Update justfile fmt-check to resolve biome via pnpm exec
This ensures the VS Code extension, pre-commit hooks, and CI all
resolve biome from node_modules consistently, without relying on
hermit PATH activation.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: make personas optional — allow chatting without a persona
Adds a "Goose" / no-persona option to the persona picker so users can
chat directly with the agent without any persona system prompt injected.
HomeScreen and ChatView now default to no persona selected.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* fix: update HomeScreen test for optional persona default
The HomeScreen now defaults to no persona selected, so the placeholder
reads "Message Goose..." instead of "Message Solo...".
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Add comprehensive Playwright e2e tests for the Personas and Skills
features (34 new tests). Includes a Tauri IPC mock fixture that injects
window.__TAURI_INTERNALS__ via page.addInitScript(), enabling tests to
run against the static build without the Tauri backend.
Tests cover: navigation, card/list rendering, create/edit dialogs,
form validation, dropdown menus, delete confirmations, search filtering,
empty states, and built-in vs custom persona behavior.
Also fixes lefthook pre-commit format hook to use npx for biome.
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* Update built-in personas to Solo, Scout, and Ralph
Replace the previous 4 built-in personas (Goose, Scout, Reviewer, Architect)
with 3 new ones pulled from Sprout: Solo (default), Scout, and Ralph.
Avatars resized from 128x128 to 64x64 to match UI display sizes.
Persona constants extracted to builtin_personas.rs to stay under file size limit.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* Refactor: remove duplicated system prompts from frontend
Replace the ~300-line BUILTIN_PERSONAS array (which duplicated all system
prompts from the Rust backend) with minimal BUILTIN_PERSONA_STUBS that
only carry metadata. The backend is the single source of truth for
system prompts, served via listPersonas() on startup.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
* refactor: remove legacy frontend persona stubs
* style: fix rust formatting
---------
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
* feat: use ~/.agents/skills as standard skill storage path
Migrate skill storage from ~/.goose/skills/ to ~/.agents/skills/ to
align with the cross-agent standard (agentskills.io) convention where
global skills live at ~/.agents/skills/ and local skills at
<project>/.agents/skills/.
Changes:
- Update skills_dir() in Rust backend to use .agents/skills
- Add AGENTS_STANDARD_DIR and SKILLS_DIR constants to storage.ts
- Existing .goose/ constants preserved for other goose-specific data
* chore: remove dead storage.ts constants file
Delete src/shared/constants/storage.ts and the now-empty constants/
directory. None of the constants (GOOSE_DIR, RECIPES_DIR, AGENTS_DIR,
SESSIONS_DIR, EXTENSIONS_DIR, AGENTS_STANDARD_DIR, SKILLS_DIR) were
imported anywhere in the frontend codebase.
Storage path logic lives entirely in the Rust backend (e.g.
skills_dir() in src-tauri/src/commands/skills.rs), and the frontend
communicates through Tauri invoke() commands. Keeping unused path
constants in the frontend was misleading dead code.
The app communicates with AI backends exclusively through ACP
(stdin/stdout JSON-RPC), not through goosed's HTTP API. The sidecar
was spawned and health-checked but none of its endpoints were ever
called — apiFetch had zero callers and useSidecar had zero importers.
Removed:
- src-tauri/src/commands/sidecar.rs (SidecarState, start/stop/health commands)
- src/shared/hooks/useSidecar.ts (unused React hook)
- src/shared/api/fetch.ts (apiFetch/clearServerConfigCache, zero callers)
- reqwest and rand Cargo dependencies (only used by sidecar)
Updated AGENTS.md to document ACP
Local persona avatars now support both dropped URLs and uploaded image files. Local files are stored in ~/.goose/avatars/, exposed through Tauri's asset protocol, and rendered through shared avatar resolution helpers.
The persona editor now uses a drag-and-drop avatar picker, and all persona avatar surfaces were updated to handle local avatar sources correctly.
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add persona targeting fields to message metadata
Add target_persona_id, target_persona_name, and acp_session_key fields
to message metadata in both Rust and TypeScript types.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add composite key storage and persona-filtered messages to ACP store
Support per-persona ACP sessions via {sessionId}__{personaId} composite keys,
and add persona-based message filtering for multi-persona chat.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add catch-up context builder for multi-persona conversations
Add persona_name field to Rust MessageMetadata. Create catchup module
that builds context text from intervening messages when switching
between personas, so each persona stays informed about conversation
activity from other participants.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: wire persona params through AcpService with catch-up context
Set persona metadata on user and assistant messages. Build catch-up
context from intervening messages and include it in the effective
prompt sent to the ACP driver.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: pass persona params through frontend API to Tauri backend
Add personaId and personaName parameters to acpSendMessage so the
frontend can target specific personas when sending messages.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: set persona target metadata on user messages in useChat hook
When personaInfo is provided, set targetPersonaId and targetPersonaName
on the user message metadata so downstream systems can identify which
persona each message is addressed to.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: use composite session key in ACP registry for per-persona cancellation
Update registry register/deregister/cancel to use composite keys
({sessionId}__{personaId}) so cancelling one persona's stream doesn't
affect another persona's active session.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add persona selector UI and message attribution display
Add dropdown persona picker in chat input for selecting which persona
to address. Display persona attribution on message bubbles showing
sender/recipient persona names.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve code review issues in multi-persona chat
- Fix UTF-8 panic in truncate_text by using char_indices instead of byte slicing
- Remove dead code in catchup.rs (unreachable else branch after early return)
- Pass persona params through to acpSendMessage in useChat hook
- Deduplicate composite key logic by delegating store.effective_key to make_composite_key
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address remaining multi-persona review issues
Stabilize catch-up context by excluding the current prompt by message ID instead of array position. Preserve original persona targeting on retry, split composite registry keys in running-session payloads, keep assistant agent names visible alongside persona badges, and remove unused acpSessionKey metadata.
* fix: use per-message persona names in chat history
* fix: restore classic assistant name styling
* fix: remove user persona attribution from chat history
* fix: resolve multi-persona review follow-ups
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: change ProjectInfo working_dir to working_dirs Vec<String>
Update backend data model to support multiple working directories.
Add backward-compatible deserialization for old workingDir format.
Update create_project and update_project command signatures.
Exclude .agents from biome to fix pre-existing Markdown check errors.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: update TS API layer for workingDirs array
Change ProjectInfo.workingDir to workingDirs: string[] and update
createProject/updateProject function signatures.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: add PromptEditor component with blue capsule rendering
ContentEditable component that renders include: lines as styled
blue capsules while keeping plain text editing for other lines.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: integrate PromptEditor into CreateProjectDialog
Replace dedicated working directory input with unified prompt editor.
Add directory button inserts include: lines. Parse on save extracts
workingDirs array from include: lines.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: update chatProjectContext for workingDirs array
getProjectFolderOption returns array of folder options.
buildProjectSystemPrompt lists all working directories.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* feat: update UI components for workingDirs array
Update AppShell, ProjectsView, ChatView, and other components
to use workingDirs instead of workingDir.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resolve code review feedback for PromptEditor and CreateProjectDialog
- Revert biome.json ignoreUnknown back to false (exclude alone suffices)
- Extract shared INCLUDE_RE regex to lib/includePattern.ts
- Only parse include: lines from beginning of text, not anywhere
- Fix contentEditable cursor jumping with lastPushedValue ref
- Add onPaste handler to ensure only plain text is inserted
- Add accessibility attrs (role, tabIndex, aria-multiline, aria-label)
- Add overflow-y-auto so resize-y works on the contentEditable div
- Add dark:text-blue-400 for capsule text contrast in dark mode
- Fix biome lint warnings (useTemplate, noUselessContinue)
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: re-render PromptEditor HTML on every input to sync capsule styling
The contentEditable div was not re-rendering its innerHTML on user
input, so blue capsule styling from include: lines persisted even
after the text was edited to no longer match the regex. Now handleInput
re-renders via renderLines on every keystroke, with caret position
save/restore to avoid cursor jumping.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: use line/column caret positioning in PromptEditor re-render
The flat character offset approach (range.toString().length) did not
count implicit newlines between contentEditable <div> elements,
causing the caret to land in the wrong position after re-rendering.
Switch to line/column positioning that maps directly to the
div-per-line DOM structure.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: show instructions in edit dialog after project creation
handleSave called onClose() (the prop) instead of handleClose(),
so form state was never reset. When reopening the edit dialog for
the same project, the prompt state matched the stale value, React
skipped the re-render, and PromptEditor's innerHTML was never set.
Two fixes:
- handleSave now calls handleClose() to reset form state after save
- PromptEditor initializes lastPushedValue to null so innerHTML is
always set on mount, not just on external changes
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: stop PromptEditor from reordering characters when typing quickly
The contentEditable innerHTML was being destroyed and recreated on
every keystroke to update capsule styling, which caused the browser
to insert queued characters at wrong positions. Now only re-render
innerHTML when the set of include: lines actually changes.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address prompt editor review issues
* fix: preserve PromptEditor cursor when typing include lines
* fix: clear stale include styling in prompt editor
* fix: append selected project directories and skip duplicates
Append Add directory selections to the bottom of the prompt editor instead of inserting them ahead of the prompt body.
Skip duplicate directory insertions by normalizing include paths against the user's home directory so ~/... and absolute paths compare as the same location.
* fix: tighten project working dirs parsing
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Split the semantic "accent" color into two concepts: brand (user-customizable
accent color) and accent (shadcn's neutral hover state). This enables using
shadcn/ui components with minimal modification while preserving the existing
theming system.
* refactor: consume shared doctor crate from builderbot
Replace the local doctor module (agents.rs, checks.rs, mod.rs, resolve.rs,
types.rs) with thin Tauri command wrappers that delegate to the shared
doctor crate extracted into block/builderbot.
- Add doctor git dependency pointing to the doctor branch in builderbot
- Delete src-tauri/src/commands/doctor/ directory (5 files, ~37KB)
- Create src-tauri/src/commands/doctor.rs with run_doctor and
run_doctor_fix wrappers plus pub use re-exports of shared types
- No changes needed to commands/mod.rs (Rust resolves doctor.rs
automatically) or lib.rs (same command function names)
* build: pin doctor dependency to merged commit
Switch the doctor crate from tracking the `doctor` branch to a specific
rev pin (bfce292) now that the branch has been merged into main.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove unused doctor imports flagged by clippy
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* refactor: split doctor.rs and acp.rs into sub-modules
Split two large files into directory modules to remove file size
exceptions from check-file-sizes.mjs:
- commands/doctor.rs (997 lines) → doctor/{mod,types,resolve,checks,agents}.rs
- services/acp.rs (509 lines) → acp/{mod,payloads,writer,store,registry}.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: narrow acp payload struct visibility from pub(crate) to pub(super)
These structs are only used within the acp module itself, so pub(super)
is the minimal correct visibility, consistent with the doctor module.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: resume existing ACP sessions instead of always creating new ones
Each message was spawning a fresh ACP session because send_prompt always
passed None as the agent_session_id. The TauriStore already persisted
the agent-to-session mapping via set_agent_session_id, but never read it
back. Added get_agent_session_id to TauriStore and wired it into
send_prompt so subsequent messages in a chat resume the existing session.
Also excludes .agents/ from biome checks to fix pre-existing hook failure
on markdown skill files.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: address code review comments on ACP session resumption
Use a typed Deserialize struct instead of serde_json::Value for
get_agent_session_id to catch schema drift at compile time, and fix
missing space after // in section divider comments.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: fix Rust formatting and simplify get_agent_session_id
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* fix: remove unused Deserialize import in acp.rs
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
* style: restore section divider comments in acp.rs
The previous formatting commits inadvertently stripped the
`// ---------------------------------------------------------------------------`
section dividers. Restore them for all five sections and add a narrow
file-size exception (550 lines) since the dividers push the file just
past the 500-line default.
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Skills are stored in .agents/skills/ as the single source of truth,
with symlinks from .cursor/, .claude/, and .codex/ so all three
coding agents can discover them.
Made-with: Cursor