7894d21
shelley: sort autogenerated files last in diff viewer
Click to expand commit body
Prompt: In the diff viewer in shelley, use https://github.com/boldsoftware/sketch/blob/ae3a8f22f7c47f507a7a30cc31c61b80dfc3491d/claudetool/patch.go#L541-L584 (or similar) to sort files that are "auto-generated" last in the sort order. Ideally prepare the sort order on the server side and have the UI display it in that order. Fine to copy that code into our code base but look to see if it's there already
Add detection for autogenerated files based on:
- Path patterns (vendor/, node_modules/, .pb.go, .min.js, etc.)
- Go file content analysis (Code generated, DO NOT EDIT, etc.)
- Lock files (go.sum, package-lock.json, etc.)
Files are now sorted with non-generated files first (alphabetically),
followed by generated files (alphabetically). The UI displays a
[generated] indicator for these files in the file picker.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
a4a079e
shelley: union model sources and show source in picker
Click to expand commit body
Previously, if custom models were configured in the database, they would
completely replace the built-in models. Now we union all model sources:
- Gateway models (when -gateway flag is configured, shows 'exe.dev gateway')
- Env var models (shows '$ANTHROPIC_API_KEY', '$FIREWORKS_API_KEY', etc.)
- Custom models from database (shows 'custom')
The model picker button now shows the source inline, e.g.:
'claude-opus-4.5 (exe.dev gateway)' or 'claude-opus-4.5 ($ANTHROPIC_API_KEY)'
Also refactored Manager to own all model state:
- Built-in and custom models stored together in services map
- Added RefreshCustomModels() called after CRUD operations
- No more DB lookups in hot paths (GetService, GetAvailableModels, etc.)
Prompt: Let's look at the model selection again. We have three ways to configure
models: gateway, env vars, and custom. Union them all together and show source
in the model picker.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
611ee73
shelley: ui: Add a hint when no AI models are configured.
xleine
created
576da97
shelley: fix: modelList slice initialization in getModelList.
xleine
created
d563e56
shelley/ui: Add collapsible system prompt viewer at top of conversation
Click to expand commit body
Prompt: (In a new worktree) At the very top of the conversation/timeline view, add a way to "show" the system prompt, which I think the UI has. Let it be expanded to see it.
Add a SystemPromptView component that:
- Shows at the very top of the conversation/timeline view
- Displays system prompt info (line count, size in KB)
- Is collapsed by default
- Expands to show full system prompt text when clicked
The viewer uses the same styling pattern as other expandable tool components.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
243154a
shelley/ui: remove emoji rotation animations from tools
Click to expand commit body
Prompt: get rid of the animations in the patch tool (and any other tools) that rotate the emoji
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
7b5503b
shelley: upgrade modernc.org/sqlite v1.38.2 to v1.44.3
Click to expand commit body
Prompt: TestCancelAfterToolCompletesCreatesDuplicateToolResult failing; HEAD^ broke it somehow; fix it. Instead of changing to background context, upgrade modernc.org/sqlite to latest version.
Fixes test flakiness in cancel tests by upgrading to a version that
includes the fix for gitlab.com/cznic/sqlite issue #241 ("fix TOCTOU
interrupt race"). The race condition caused "Tx LEAK sql: connection
is already closed" errors when cancelling conversations mid-operation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Philip Zeyliger
and
Claude
created
9e9f2aa
shelley/server: replace sleeps with polling in cancel tests
Click to expand commit body
Prompt: We have a test (server_test) that sleeps. That's no good; tests shouldn't sleep. Avoid this!
Replace fixed time.Sleep() calls with polling that waits for specific
conditions:
- Add Server.IsAgentWorking(conversationID) method to check if a
conversation's agent is actively processing
- Add waitFor() test helper that polls a condition with 10ms intervals
- Update TestCancelWithPredictableModel to wait for tool use message
and agent idle state instead of fixed sleeps
- Update TestCancelDuringTextGeneration to poll for agent working state
- Update TestCancelAfterToolCompletesCreatesDuplicateToolResult to poll
for agent idle state
This makes tests more reliable and faster by waiting only as long as
needed rather than fixed durations.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
06de5d6
shelley: send x-session-affinity header to Fireworks for prompt caching
Click to expand commit body
Prompt: In a new worktree make the fireworks client send th conversation id as the session hint to enable prompt caching.
Add the conversation ID as x-session-affinity header when making requests
to Fireworks. This enables Fireworks' prompt caching feature which reduces
time to first token by up to 80% and reduces costs for cached prompt tokens.
The header is only added when:
1. A conversation ID is present in the context
2. The provider is 'fireworks'
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
a683fea
shelley: Fix scrollbar appearing in empty message input
Click to expand commit body
Prompt: See that scroll bar in the message input box? It shouldn't be there!
Follow-up: can we just make the initial content better?
Increase min-height from 44px to 46px to properly fit single line
of text (16px font × 1.5 line-height = 24px + 20px padding) with
a small buffer to prevent scrollbar.
Co-authored-by: Shelley <shelley@exe.dev>
a830125
shelley/ui: reflect subagent conversations in URL
Click to expand commit body
Prompt: In a new worktree, fix https://github.com/boldsoftware/shelley/issues/36
When navigating to a subagent conversation (via drawer or SubagentTool link),
the URL now updates to /c/<subagent-slug>. Reloading a page with a subagent
URL preserves the state.
Changes:
- Add viewedConversation state to track subagents (not in main list)
- Change selectConversation to accept Conversation object (needed for slug)
- Update URL/title effect to use viewedConversation
- Add popstate handler for SubagentTool navigation
- Pass viewedConversation to drawer to expand parent when viewing subagent
Fixes: https://github.com/boldsoftware/shelley/issues/36
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
452c9d0
shelley: don't auto-start agent on 'continue in new conversation'
Click to expand commit body
Prompt: When we click on 'continue in new conversation', we send the
message right away to the agent. The user often wants to add extra
instructions. What would be a good way to get the conversation created,
but not call the agent? Propose a solution for me.
Follow-up: What do you think of option C where we just don't send the
message? It's not really pending, and it's not really editable, but the
user can add another message and hit send, and both will get sent.
Follow-up: Yes, let's do it.
When users click 'Continue in new conversation', they often want to add
extra instructions before the agent starts working. This change:
1. Records the conversation summary as a user message
2. Does NOT start the agent loop automatically
3. Returns status 'created' instead of 'accepted'
The user sees their summary message displayed and can then type additional
instructions before sending. When they send a message, the agent will
receive both the summary and their new instructions in context.
This gives users control over when the agent starts, rather than
immediately kicking off a potentially long-running task.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
0975bf1
shelley: bashtool: block dangerous rm -rf commands and warn about destructive ops
Click to expand commit body
Prompt: update bashtool to find "rm -rf" commands that seem to delete .git directories or ~ or $HOME and require those to be explicitly spelled out, and mention that the agent might want to confirm with the user before such destructive commands. Update the bashtool description to also mention avoiding overly destructive cleanups.
Add safety check to detect rm -rf commands that could delete:
- .git directories (direct or via wildcards like .*)
- Home directories (~, ~/, ~/path, $HOME, ${HOME})
- Root directory (/)
- Broad wildcards (*, /*)
The check requires both -r/-R (recursive) and -f (force) flags
to trigger, allowing safe variants like 'rm -r .git' (which
prompts for confirmation) or 'rm -f file.txt'.
When blocked, the error message suggests:
1. Spelling out the full path explicitly (no wildcards or ~)
2. Confirming with the user before destructive operations
Also update bash tool description to mention avoiding overly
destructive cleanup commands.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
5ce42b6
shelley: replace model select with custom dropdown widget
Click to expand commit body
Prompt: make the model picker a custom widget instead of a selection box,
and have one of the options be the add/remove custom models, so that users
can find that menu directly.
Replace the native <select> element for model selection with a custom
dropdown widget (ModelPicker). The new widget:
- Shows all available models with checkmarks for the selected one
- Opens upward when there's not enough space below
- Includes an 'Add / Remove Models...' option that opens the models modal
- Provides better discoverability for the custom models feature
Co-authored-by: Shelley <shelley@exe.dev>
* Fix Android keyboard covering chat input on Firefox
When the virtual keyboard appears on Android Firefox, it can cover
the chat input field, making it impossible to see what you're typing.
This fix adds two mechanisms to ensure the input stays visible:
1. On focus: scroll the input into view with a small delay to let
the keyboard animation start
2. On viewport resize: use the visualViewport API to detect when
the keyboard changes the viewport size and scroll the input
into view if it's focused
Fixes #47
Co-authored-by: Shelley <shelley@exe.dev>
* Drop the onFocus handler
The visualViewport API should be sufficient
* Restore previous comment
---------
Co-authored-by: Shelley <shelley@exe.dev>
1236452
shelley: use Cmd+K on macOS, Ctrl+K elsewhere for command palette
Click to expand commit body
Prompt: Fix https://github.com/boldsoftware/shelley/issues/52
This preserves the native Ctrl+K (kill to end of line) emacs-style
shortcut on macOS.
Fixes https://github.com/boldsoftware/shelley/issues/52
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Philip Zeyliger
and
Claude
created
80cffd4
shelley: use instant scroll behavior for chat messages
Click to expand commit body
Prompt: Make " messagesEndRef.current?.scrollIntoView({ behavior: "smooth" });" scroll instantly not slowly
commit, mentioning thiat this fixes https://github.com/boldsoftware/shelley/issues/35
Fixes https://github.com/boldsoftware/shelley/issues/35
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Philip Zeyliger
and
Claude
created
c681197
shelley: pass working directory to xterm terminal URL
Click to expand commit body
Prompt: Change the Shelley.json file generation to include this flag with a placeholder WORKING_DIR and change Shelley to have replacement for this parameter in its menu handling.
The terminal_url in shelley.json now includes '?d=WORKING_DIR' placeholder.
When the user clicks the Terminal button in Shelley's menu, the WORKING_DIR
placeholder is replaced with the current conversation's working directory
(URL-encoded), so the terminal opens in the correct directory.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
35d47fa
shelley: add inline shell command execution with !prefix
Click to expand commit body
When a chat message starts with '!', instead of sending to the LLM,
execute the command on the server and display output in an embedded
xterm.js terminal widget.
Features:
- Commands executed via bash -c in a PTY with real-time streaming
- Terminal embedded in chat timeline (resizable, not full height)
- Exit code displayed (green for 0, red for non-zero)
- Copy buttons for screen/scrollback buffer
- Insert buttons to paste terminal content into message input
- Light/dark theme support
- Shell mode visual indicator (terminal icon + yellow background)
- Terminals are ephemeral (not saved to database)
Backend:
- New websocket endpoint /api/exec-ws
- Uses creack/pty for PTY allocation
- Handles resize and input events
- Tests for all major functionality
Frontend:
- New TerminalWidget component using @xterm/xterm
- ChatInterface intercepts !prefix messages
- Auto-sizing based on output content
- Descriptive button tooltips
Prompt: add inline shell command execution with ! prefix, with visual
indicator, auto-sizing terminal, and proper tests
Co-authored-by: Shelley <shelley@exe.dev>
Co-authored-by: Shelley <shelley@exe.dev>
Three improvements:
1. Include hidden directories (starting with '.') in directory listing
Previously these were filtered out, but they're useful for accessing
.config, .local, .git subdirectories, etc.
2. Show git HEAD commit subject for git repository roots
When a directory contains a .git subdirectory or .git file (worktree),
we run 'git log -1 --format=%s' to get the HEAD commit subject and
display it. Git repos get an orange folder icon and show the subject
on the right side (truncated with ellipsis if needed).
The current directory also shows its git subject if it's a repo.
3. Use current conversation's cwd when starting new conversation
When clicking '+' to create a new conversation, we now save the current
conversation's cwd to localStorage so the new conversation inherits it.
This avoids having to re-select the directory for related work.
4. Fix race condition in directory loading
Added tracking of expected path to prevent stale directory data from
being displayed when navigating quickly.
Prompt: In the "dir selection" box in shelley, let's (a) include "hidden" dirs
that start with dot, and (b) indicate git repo roots by including the subject
of their HEAD commit if we can get it. In addition, when a user clicks "+"
for "New Conversation", let's use the dir of the conversation they're on as
the starting point.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
6e43d91
ci: add Go and pnpm caching, upgrade to Node 24
Click to expand commit body
- Enable Go module caching via setup-go cache option
- Add pnpm caching via setup-node cache option
- Upgrade Node.js from 20 to 24 (current LTS)
- Reorder pnpm setup before node setup for cache detection
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Philip Zeyliger
and
Claude
created
d440d26
Shelley: Add continue conversation feature for long contexts
Click to expand commit body
We've had a spirited conversation in Discord about how to
do compaction. This is one possible approach, which I'm sure
needs some fine-tuning, but is harmless in that it's opt-in.
Prompt: In addition to the warning sign about high context, when the
user hits 100k tokens, open the little window up, and add a button there
to "continue in new conversation". When that is pressed, start a new
conversation. The initial user prompt should be: "Continue the
conversation with slug <x>. Here are the user and agent messages so far
(including tool inputs up to ~250 characters and tool outputs up to ~250
characters); use sqlite to look up additional details." I want the
munging to happen on the server side, so create a new endpoint that
creates a new conversation, but references a pre-existing one, so this
works.
When a conversation reaches 100k tokens:
- The context usage popup auto-opens (once per conversation)
- Shows a 'Continue in new conversation' button
- Clicking it creates a new conversation with a summary of the
previous one as the initial prompt
The summary includes:
- Reference to the source conversation slug
- User and agent messages (text content)
- Tool calls with inputs truncated to ~250 chars
- Tool results truncated to ~250 chars
- Instruction to use sqlite for additional details
Server changes:
- POST /api/conversations/continue endpoint
- db.ListMessages() function to get all messages
UI changes:
- ContextUsageBar auto-opens at 100k tokens
- Continue button in the popup
- App.tsx handler to navigate to new conversation
Co-authored-by: Shelley <shelley@exe.dev>
Prompt: Continue the work of debug-llm-requests-ui-improvements, but just
finish it up. I don't want the fancy JSON viewing component. Just give me
a nice clean commit with the better debug view.
- Switch from dark mode to light mode for better readability
- Show both request AND response side-by-side when expanding a row
- Add 'Show Full' button for requests with prefix deduplication to
reconstruct the complete request body
- Add new endpoint /debug/llm_requests/{id}/request_full that follows
the prefix chain to return the complete request
Co-authored-by: Shelley <shelley@exe.dev>
Prompt: Sometime in the last ~10 commits, the "usage bar" in the chat
window has broken/disappeared. That wasn't intentional. Figure it out and
restore it. Tell me what happened too.
The CSS for the context usage bar (.context-usage-bar-container,
.context-warning-icon, .context-usage-bar, .context-usage-fill) was
accidentally replaced with an unused .context-usage-indicator class
in commit 6c20eec2 (output_iframe changes).
This restores the original CSS so the context window usage bar is
visible again in the chat interface.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
bd4bc1b
shelley: improve Monaco diff view in PatchTool
Click to expand commit body
Prompt: When the patch tool uses monaco views to put in the conversation view, the monaco view needs to be collapsed to just "edited" sections (not expanded). And the monaco view needs to be exactly the height to show all the code but no higher. We're also having issues with too many monaco editors making things slow. Activate the monaco editors only when they're on screen for the user. Have a toggle between side-by-side and inline diff modes for the monaco thing, and have that affect the default by using local storage.
Follow-up: The toggle is ugly. We don't need the text "Diff:" or how long the tool took; maybe we can put the toggle up in the tool header thingy? When the diff is long, the monaco thing doesn't expand to fit it all. I think this isn't interacting well with scroll to bottom behavior as things are being added.
- Add lazy loading via IntersectionObserver - Monaco editors only
initialize when scrolled into view, improving performance with
many patches in a conversation
- Collapse to edited sections by default using hideUnchangedRegions
option - shows only changed lines with 2 lines of context
- Auto-size editor height to fit content exactly (no max height cap)
- Only set height once after diff computes to avoid scroll disruption
- Add toggle button for side-by-side vs inline diff modes in header
- Persist diff mode preference in localStorage
- Remove "Diff:" label and execution time display from Monaco view
- Add placeholder UI for lazy-loaded state
Co-authored-by: Shelley <shelley@exe.dev>
This is iteration on https://github.com/boldsoftware/shelley/issues/15.
How to handle truncation is tricky; we observed it was still keeping the
agent as "running" and was confusing with the error. Let's see how this
goes.
When an LLM response is truncated due to max_tokens:
1. The truncated message is preserved in the database with excluded_from_context=true
for cost/billing tracking, but not sent back to the LLM (partial tool calls confuse it)
2. A system error message is recorded with ErrorType set, stored as message type 'error'.
This properly signals end of turn so the UI updates the agent working state.
3. Error messages are identified by the ErrorType field on llm.Message, not by
fragile text prefix matching on message content.
Changes:
- Add excluded_from_context column to messages table (migration 014)
- Add ListMessagesForContext query to filter excluded messages
- Add ErrorType field to llm.Message (truncation, llm_request)
- Handle max tokens BEFORE adding response to history (prevents double recording)
- Record truncated message (excluded) + error message on truncation
- Check ErrorType in getMessageType() to return db.MessageTypeError
- Skip error messages when building LLM context
- Update isAgentEndOfTurn to handle error messages
- Add test for max tokens truncation handling
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
dadd06c
sheley: Add create directory feature to Select Directory modal
Click to expand commit body
Prompt: Add a way to create a directory in the "Select Directory" modal
- Add POST /api/create-directory endpoint that creates directories with proper error handling
- Add createDirectory() method to frontend API service
- Add inline create form in DirectoryPickerModal with:
- New Folder button in footer
- Input field with submit/cancel buttons
- Error message display
- Auto-navigation to newly created folder
- Add CSS styles for the create form and related elements
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
74ed109
output_iframe: read from file path, support bundled files, add download
Click to expand commit body
I'm still figuring out the ergonomics for this tool, but there's
something here, so I'm continuing on it. The alternative is to
support output Mermaid or vegalite or whatever, but that's too limited.
Prompt: the tool to produce an iframe output: instead of taking a
string, have it take a file. And also add a download button so it's easy
to download the produced visualizations. [Support multiple files with
zip download]
Changes the output_iframe tool to read HTML from a file path instead of
accepting raw HTML strings. Also adds support for bundling additional
data files and a download button in the UI.
Backend:
- Tool now takes 'path' parameter pointing to an HTML file
- Add optional 'files' parameter to bundle additional files (JSON, CSS, JS)
- CSS files injected as <style> tags, JS as <script> tags
- Data files (JSON, CSV, text) accessible via window.__FILES__['filename']
- Supports both relative and absolute paths
Frontend:
- Add download button next to 'open in new tab' button
- Single HTML: downloads the file directly
- Multiple files: creates ZIP with original HTML + all bundled files
- Add JSZip dependency for zip creation
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
249a8e3
subagent: add progress summary on timeout and stop on subsequent message
Click to expand commit body
Prompt: in a new worktree, reset to origin/main, let's fix
https://github.com/boldsoftware/shelley/issues/41. When we're using
subagents, if the subagent takes longer than the timeout, I want it to
give a progress report to the parent. To do this, let's do a
non-conversation LLM call to the same model and ask the LLM for a
summary of current progress, and send that back to the parent.
Separately, when the parent calls the child on a subsequent call, it
should issue, effectively, a "stop" first, and then send its message.
When a subagent times out while waiting for a response:
- Instead of returning a static message, makes a non-conversation LLM call
to summarize the current progress based on the conversation history
- The summary tells the parent what was accomplished, what's being worked on,
and whether progress is being made
When a parent sends a subsequent message to a subagent that's already working:
- Cancels the subagent's current work before sending the new message
- Re-hydrates the manager after cancellation to load the updated history
Fixes #41
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
9c4a302
shelley: run schema migrations in a transaction
Click to expand commit body
Prompt: exed now runs its schema migrations in a transaction; we should do the same for shelley.
Each migration now runs within a single transaction that:
1. Executes the migration SQL
2. Records it in the migrations table
If either step fails, the entire migration is rolled back.
This matches the pattern used by exed's migration system.
Co-authored-by: Shelley <shelley@exe.dev>
88a10b2
shelley: store model in conversation table
Click to expand commit body
Prompt: Fix https://github.com/boldsoftware/shelley/issues/29
Since a conversation only has one model, and it's in the database,
presumably, the ambiguity just shouldn't exist.
Add a model column to the conversations table to ensure conversations
always resume with the correct model, even after server restarts or when
accessed from different browsers.
Changes:
- Add 011-add-model.sql migration to add model column
- Update CreateConversation to accept model parameter
- Load model from conversation in Hydrate()
- Backfill model for legacy conversations on first message
- Add Model field to ConversationState and broadcast to clients
- Update UI to set selected model from ConversationState
- Add test for model restoration after server restart
Fixes https://github.com/boldsoftware/shelley/issues/29
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
c1466e5
shelley: fix agent still showing working after LLM error
Click to expand commit body
Prompt: when the API errors out though, the agent is still listed as working; is that a bug?
The error message recorded when an LLM request fails was missing
EndOfTurn: true. This meant the server never called SetAgentWorking(false)
and the agent stayed in the "working" state indefinitely.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Philip Zeyliger
and
Claude
created
741e277
shelley: add custom model management with UI
Click to expand commit body
Prompt: Add custom model management UI with support for multiple providers
- Add custom models database table and CRUD API
- Add ModelsModal UI component for managing custom models
- Support provider types: anthropic, openai (Chat API), openai-responses (Responses API), gemini
- Use native gem.Service for Gemini (supports thought signatures for Gemini 3)
- OpenAI Chat API always uses max_completion_tokens
- Add model testing before save
- Add model duplication
- Add display names and tags for models
- Move Add Model button to modal header
- Fix tooltip positioning
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Philip Zeyliger
and
Claude
created
addac5b
shelley: update Gemini models and add thought signature support
Click to expand commit body
Prompt: I think using Gemini isn't really working with shelley. Use the gemini key to see if you can get it to work. Use the pointers to the gemini3 series models to add to the model drop down etc.
Related to https://github.com/boldsoftware/shelley/issues/42
- Update default model from gemini-2.5-pro-preview-03-25 to gemini-2.5-pro
(the preview model is no longer available)
- Add Gemini 3 models: gemini-3-pro and gemini-3-flash
- Add Gemini 2.5 Flash model
- Update context window size mappings for new models
- Add thought signature support required by Gemini 3 for function calling:
- Added ThoughtSignature field to gemini.Part struct
- Capture thought signature when receiving function call responses
- Pass thought signature back when building requests with function calls
- Update tests to use current model names
Gemini 3 models require thought signatures to be passed back during function
calling workflows, otherwise they return a 400 error. All models have been
tested and work with both simple text completion and multi-turn tool usage.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
829febb
shelley: truncate long lines in large output summaries
Click to expand commit body
Prompt: In a new worktree, reset to origin/main after fetching, and look at https://github.com/boldsoftware/shelley/issues/37. I think 0bbdde76269d93170ba27ef88f1a3d034468ac75 is buggy, because if the output is binary or has really long lines, we end up putting a lot in the context. Fix it by either reverting that change or by presneting somethign much shorter if the lines are long.
When bash output exceeds 50KB, we save to a file and show first/last
lines. However, if those lines are very long (e.g., binary data or
minified JS), we could still blow up the context.
Fix by truncating each displayed line to 200 characters.
Fixes https://github.com/boldsoftware/shelley/issues/37
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
507852a
shelley: Add LLM request tracking with prefix deduplication
Click to expand commit body
So, storing LLM messages for debugging/history turned out to be
accidentally quadratic. This tries to fix it.
The debug page is still not usable, but that's ok.
Prompt: Track LLM HTTP requests in database with prefix deduplication for space efficiency, then add a /debug/llm_requests page to view the data
- Track LLM HTTP requests in database with custom headers
- Add prefix deduplication for llm_requests table to reduce storage
- Reorder Anthropic and Gemini request struct fields for better prefix matching
- Pass conversation ID through context for prefix dedup (was missing)
- Add /debug/llm_requests page with:
- Table showing recent requests with size info
- Lazy loading of request/response bodies
- Collapsible JSON viewer with syntax highlighting
- Prefix deduplication info display
Tested: prefix deduplication working for both Anthropic and OpenAI providers
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
b07d9f4
shelley: set SHELLEY_CONVERSATION_ID for bash commands
Click to expand commit body
Prompt: Make the bash tool set SHELLEY_CONVERSATION_ID for things it invokes.
Add ConversationID field to ToolSetConfig and BashTool. When
ConversationID is set, the bash tool will expose it to invoked
commands via the SHELLEY_CONVERSATION_ID environment variable.
This allows scripts and commands run by Shelley to know which
conversation they're being invoked from, enabling things like
logging, debugging, or conversation-aware behaviors.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
5513fb1
bash: save large output to file, show first/last lines
Click to expand commit body
Prompt: Let's make it so that if the output is greater than 50kb, we send back the first 2 lines and the last five lines, and tell the agent where the output file is for the rest. If this output didn't have lines, just tell the agent about the output file. Number the lines that you're outputting. Show me an example of the agent outputs.
When bash output exceeds 50KB:
- Save full output to a temp file
- Return first 2 lines and last 5 lines (numbered)
- Tell agent where to find the full output
For binary-like output (fewer than 3 lines), just indicate the file path.
Falls back to old middle-snip truncation if temp file creation fails.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
3a95fc6
shelley: support auto-upgrade when binary is owned by root
Click to expand commit body
Fixes https://github.com/boldsoftware/shelley/issues/34
Prompt: Shelley's auto-upgrade isn't working when /usr/local/bin/shelley
is owned by root. It needs to work, and it could work, since shelley has
sudo. In a new worktree, fetch, get the latest exe.git repo
(origin/main), and make `mux.Handle("POST /upgrade",
http.HandlerFunc(s.handleUpgrade))` handle the case where
/usr/local/bin/shelley isn't owned by the current user.
When /usr/local/bin/shelley is owned by root, the normal selfupdate.Apply
fails with a permission error. This change detects that situation and falls
back to using sudo to perform the upgrade.
The sudo-based upgrade:
1. Writes the new binary to a temp file
2. Copies the old binary to a backup
3. Copies the new binary to the target location
4. Restores the original ownership and permissions using --reference
5. Cleans up the backup
This preserves the original file's ownership and permissions, which is
important when the binary is owned by root.
Co-authored-by: Shelley <shelley@exe.dev>
Fixes https://github.com/boldsoftware/shelley/issues/10
Prompt: Implement skills for Shelley. See https://agentskills.io/home
Add support for the Agent Skills specification (https://agentskills.io),
an open format for giving agents new capabilities and expertise.
Skills are directories containing a SKILL.md file with YAML frontmatter
(name, description) and markdown instructions. Shelley discovers skills
from:
- All subdirectories of ~/.config/shelley/ that contain skills
- All subdirectories of ~/.shelley/ that contain skills
- .skills/ directories walking up from working dir to git root
Discovered skills are included in the system prompt as XML, allowing
the agent to activate skills by reading the SKILL.md file when a task
matches the skill's description.
New package: skills/
- Parse SKILL.md frontmatter (simple YAML parser, no dependencies)
- Validate skill names per spec (lowercase, hyphens, no consecutive --)
- Discover skills in configured directories
- Walk up directory tree to find project .skills directories
- Generate <available_skills> XML for system prompt
Changes to server/:
- Add SkillsXML field to SystemPromptData
- Call collectSkills() during prompt generation
- Update system_prompt.txt template with skills section
Co-authored-by: Shelley <shelley@exe.dev>
Lighter weight, smaller security surface.
Long term, we should compartmentalize Shelley vs exe a little better,
and we could make this into a skill if there was more content to it...
but for now, just ship it.
Josh Bleecher Snyder
created
ec92290
shelley: improve conversation history queries in system prompt
Click to expand commit body
Prompt: The Shelley system prompt has some SQLite stuff to see history. Can you review it and make it more focused on the agent and user messages. I think Shelley has to do too much json parsing after the fact.
The old query did naive JSON extraction that required post-processing.
The new query directly extracts user and agent message text using proper
JSON path queries, filtering for text content (Type=2) and non-empty
messages. Output is cleaner with User/Agent labels instead of raw type.
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
df4b156
loop: process user messages immediately after tool completion
Click to expand commit body
Prompt: Somewhere in history we fixed how Shelley deal with interruptions. They should enter the conversation as soon as possible. Find the old conversation and reimplement the same. (Or pull the change from git if that makes sense.)
Previously, user messages queued during tool execution would wait until the
entire turn completed (all tool calls finished). This could be frustrating
when an agent was in a long chain of tool calls and the user wanted to
interrupt or provide additional guidance.
Now, after each tool completes, the loop checks for queued user messages and
adds them to history before the next LLM request. This means:
- User messages are visible to the LLM after the current tool completes
- The LLM can choose to stop the chain or adjust based on user input
- Tools that were already invoked still complete (no mid-tool cancellation)
Added tests:
- TestInterruptionDuringToolExecution: verifies interruption is seen after tool
- TestInterruptionDuringMultiToolChain: verifies chain can be stopped early
- TestNoInterruptionNormalFlow: verifies normal behavior is unchanged
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
ba54593
ui: add attachment button and responsive placeholder text
Click to expand commit body
Prompt: I don't like that the placeholder text wraps on a small screen.
Shorten it if the screen is small. Also add an 'add attachment' button to
let the user upload files / photos on both mobile and desktop.
Paper clip should be next to the microphone and up arrow send button.
If you select multiple files, it doesn't seem to include both of them in
the thing added to the text. Fix that.
Fixes https://github.com/boldsoftware/shelley/issues/22
- Add paperclip attachment button next to mic and send buttons
- Shorten placeholder to 'Message...' on screens < 480px to prevent wrapping
- Full placeholder 'Message, paste image, or attach file...' on larger screens
- Fix multiple file uploads: use functional setMessage to avoid stale state
- Hidden file input accepts images, videos, code files, and common formats
Co-authored-by: Shelley <shelley@exe.dev>
Philip Zeyliger
and
Shelley
created
3dd644a
shelley: add version checker with self-update capability
Click to expand commit body
Prompt: In shelley, unless SHELLEY_SKIP_VERSION_CHECK=true is set in the environment, let's have a VersionChecker component as part of the server. When /version-check is retrieved by the UI, it should, at most once every six hours, look at the github api for releases to boldsoftware/shelley, and place a little red indicator dot on the top-right dot-dot-dot menu if there's a newer version of shelley. There should also be a "Check for New Version" menu item in that menu. In this case, "newer" means both that the X in v0.X.Y is greater and the new build is at least 5 days newer than the current build. When Check for New Version is clicked, the current and new versions are displayed, along with a "changelist" retrieved from the github API of the commits in between the two endpoints. There should be an "upgrade" button that uses fynelabs/selfupdate to upgrade the executable with a newly downloaded one. And a "restart" button that exits the shelley process (assuming that systemd will restart it).
Follow-ups:
- Can you add an env variable that lets me override the version I'm running with?
- let's do checksum verification
- UI cleanup: use red dot instead of badge, commits link to GitHub, wrap text, show build time, remove last checked/check again
Add a VersionChecker that checks GitHub releases for updates:
- Caches results for 6 hours (skip entirely with SHELLEY_SKIP_VERSION_CHECK=true)
- Red dot on menu when update available (newer minor + 5 days apart)
- "Check for New Version" menu item opens modal with version info
- Changelog shows commits as links to GitHub with wrapped text
- Current version shows build time
- Upgrade button downloads binary, verifies SHA256 checksum, applies update
- Restart button exits process for systemd to restart
SHELLEY_VERSION_OVERRIDE env var allows testing with fake version.
Related: https://github.com/boldsoftware/exe.dev/issues/126
Fixes https://github.com/boldsoftware/exe.dev/issues/56
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>