Loop 0.5.0 · 2026-10-31
文档对应最新 npm 发布版本,保留英文原文。
Projects and Session Navigation
The sidebar groups historical sessions by project. A project represents a local directory accessible to the backend. The main area displays one selected session.
The New task (新建任务) button stays above Pinned and Projects, outside the scrolling history. Its icon aligns with the left edge of the Pinned heading, including when classic scrollbars reserve space. Clicking it opens a new empty session with the selected session's workspace already selected. Without an accessible selected workspace, it opens an independent chat with no project. Creation failures keep the current session and its draft intact and show an inline error for retry.
When sessions are pinned, a Pinned (已置顶) section appears above Projects. It lists pinned sessions with the most recently pinned first, without duplicating them under their projects. Pinning and unpinning do not switch the selected session or change drafts. Pinned sessions remain visible when Projects or their individual projects are collapsed, and use the same live titles, generation, approval and unread indicators. The section disappears when no visible pins remain.
While scrolling down the sidebar history, visible Pinned, Chats and Projects headings stick in order beneath New task as each reaches the preceding heading. All three section chevrons align at the right edge, with the Projects add action immediately before its chevron. Headings use a compact 4px gap below New task and between collapsed sections; stacked headings keep the same inset and spacing as their normal layout. Scrolling back up returns headings to their original positions. Folding a section does not trigger browser scroll anchoring; temporary bottom space keeps the current scroll position when content shrinks, preserving the stacked headings and keeping earlier lists out of view. The extra space shrinks as the user scrolls back up or expands content. Session rows are clipped as they pass behind their headings, preserving the sidebar's original background without separate solid-color blocks. Keyboard navigation and newly added projects retain scroll clearance below the headings.
Click a Pinned, Chats or Projects label or chevron to reopen a collapsed section in place without scrolling. For an expanded section, clicking scrolls its first list item to the top below the sticky headings, including when that item has scrolled out of view. When the first item is already directly below its own heading, clicking collapses the section immediately, whether or not that heading has reached its sticky position. The normal project-row margin is included in this alignment check. These actions preserve the selected session.
All projects sit beneath the Projects disclosure, expanded by default. Its label and chevron reopen in place and share the scroll-then-collapse behavior when already expanded; the chevron points down when expanded and right when collapsed. Collapsing preserves the selected session, each project's own expansion state, and the number of entries revealed through Show more. Folding an individual project or the Pinned and Chats sections also preserves their revealed entries. Add project and Settings remain available in either state.
The Projects heading uses 14px text and sits close to the first project row. Its chevron and + button appear while hovering over the heading row or navigating its controls with the keyboard. They hide when the pointer leaves, without shifting the label or layout. Devices without hover keep the controls visible. The heading's Add project button sits before the chevron; project New session and session Archive buttons share the same right edge, with consistent rounded hover styling. Project-row actions (options and New session) and session-row actions (Pin/Unpin and Archive) use compact 24px buttons with 16px icons, 4px padding and 6px hover corners. The Projects heading retains its 30px Add project button and 20px icon.
Session titles, inline rename text and the No chats placeholder align with the project name. Project and session names use 13px text, while No chats uses 14px. Project and session names share the same foreground color across default, hover, focus and selected states: soft white in Dark and dark text in Light. Projects uses a subdued gray, with No chats softer still, in both themes. Project and session row highlights share the same left and right edges, with equal gaps to the sidebar edges even when classic scrollbars are present. Text indentation stays inside each row. Adjacent session rows have a 2px gap so hover and selection highlights stay separate. Project headings are 32px tall with 2px margins between projects. Session lists start directly below the heading and use 4px bottom padding, keeping the final session or Show more close to the next project.
Usage
Project and session action menus use 13px text and 20px icons. Menu items are 28px tall with 4px vertical padding, 8px horizontal padding and an 8px icon-to-label gap. Both menus use 4px outer padding and 12px corners; the session menu is 208px wide. Keyboard navigation, hover highlights and disabled actions remain available in the compact layout.
- Click the + beside Projects to open Create project. Enter an optional Project name, then click Add under Source folders to open the system folder picker. The selected folder appears as a row with its name, a full-path tooltip and an × button to remove it. Removing it preserves the custom name and allows another selection. Create project becomes available after selecting a folder; a blank or whitespace-only name uses the folder name. Saving expands Projects and the project, scrolls it into view and focuses it. Empty projects show No chats without creating a session. Re-adding a registered folder reveals its existing node without duplication or renaming. Failed saves retain the name and folder for retry. Cancel, Close and Escape discard the unsaved selection; closing while the picker is open cancels its request.
New empty sessions show only a project capsule above the input. Hover or keyboard-focus it to reveal × in a compact 16px gray circle with a centered 14px icon; removing the selection preserves text and attachments and disables sending, including Enter. Choose project opens the registered-project menu and focuses Search projects at the top. Search filters project names immediately, ignores case and trims surrounding spaces; clearing search restores the full list, and reopening the menu starts with an empty search. Arrow keys move from search to the available choices; Escape closes the menu. Search and Add folder… remain visible while long project lists scroll. No matches shows a hint and still allows adding a folder; inaccessible folders cannot be selected. Add folder… opens the same Create project dialog, then selects the registered folder. Switching projects creates a new empty session under that folder and transfers unsent text and attachments, keeping the model, effort and permission preset. A failed switch keeps the existing draft for retry. Clearing is remembered across reloads during the server's draft lifetime. After the first submission, the session retains its project and the capsule disappears.
- Click the project row to expand or collapse its history; the folder icon opens and closes with it. Hover or keyboard focus highlights the row and reveals … and the compose pencil. Touch devices keep these actions visible. Click the pencil to open a new draft. It becomes a sidebar session only after its first user message is accepted into the conversation.
- Each project initially shows up to five history entries. If more exist, click Show more to reveal the next ten, or all remaining entries when fewer than ten remain. The button disappears when all entries are visible. Click a history entry to select it. Switch conversations through the sidebar; the folder button opens the project drawer on narrow screens.
- Hover or keyboard-focus a session row to highlight it and reveal its Pin and Archive icon buttons. Touch devices keep both visible. Pin moves the session into Pinned; its button then becomes Unpin, which returns it to its project's normal ordering. Click Archive to archive that chat immediately. Right-click the title, or press Shift+F10 while it has focus, to open Rename, Pin (or Unpin), Archive and Permanently delete without switching the selected chat.
A local macOS service opens the system folder picker. If selection fails, the dialog shows a retryable error. Cancelling selection does not create a project. Folder selection accesses the computer running the Web service.
State and Interfaces
| Operation | Request and state |
|---|---|
| Query, add, rename, or remove a project | useProjects calls /api/workspaces and refreshes the project cache on success |
| Select a source folder | useDirectoryPicker calls the system folder picker API |
| Query history | useProjectSessions and PinnedSessions share queries by workspaceId; all accessible registered projects load independently of expansion so saved pins can be discovered |
| Reveal more history | SessionList displays five unpinned summaries initially and adds up to ten per click, independently for each project; Pinned displays all pins |
| Pin or unpin | useSessionActions sends PUT /api/sessions/:id/pin with workspaceId and pinned; the server saves header pinnedAt and refreshes project summaries |
| Start a draft | Submit workspaceId and select the returned draft handle; no history file or sidebar item is created yet |
| Open an existing session | workspace-store records the selected session and its project; the view loads a snapshot and subscribes to events |
Drafts show New session in the header but do not appear under their project. Typing, adding attachments, changing models, renaming the header or clicking New session repeatedly does not create sidebar items. The first user message adds the item during the run; an image-only or file-only message also counts. Empty submissions and preflight failures do not create items. Older unarchived records without user messages are hidden without deleting their files. When no generated or manual title exists, the first eligible user text supplies the fallback title, including for restored historical sessions. New conversations also make an independent model request to generate a short title in the prompt's language. Saved titles appear in the header and sidebar rows. Failed generation keeps the existing title. Project renaming remains available through the API; the previous inline Rename/Remove links are replaced by the project menu.
The header contains only a folder icon and the session name above a single divider. Its folder icon matches the collapsed project icon in shape, size and stroke. Its background matches the conversation, with compact spacing between the left border, folder and title. The folder button and title control sit directly beside each other; their internal padding separates the icon and text while preserving both click areas. Long titles truncate to fit. Hovering or keyboard-focusing the name highlights it, with 8px padding on either side of the text. The padding stays consistent during hover and editing. Click to edit with the current text selected; Enter confirms, while Escape or clicking outside cancels. Enter during IME composition does not submit. Blank names cannot be saved; failed saves retain the draft and show an error. Successful saves pin the manual title and update the header and sidebar immediately. Editing is unavailable during another session operation or pending history save. Title regeneration remains available through the SDK/API, with no header button.
Active sessions receive title updates through SSE, including results arriving after the answer. A page-level list event stream refreshes affected project lists when background sessions change, including late titles, and resynchronizes lists on reconnect. There is no periodic list polling. Reading untitled history derives a fallback without making a model request or rewriting the session file. See list synchronization and title policy.
A small rotating ring at the far right of a session row indicates response generation, including model waiting, streaming and tool execution. Live session events update the open session immediately; background sessions refresh through list change notifications. The ring disappears when generation ends and does not appear for model changes, saves or title updates. Long titles truncate before the ring. Reduced-motion preferences keep the ring static.
While approval is pending, an 8px yellow dot appears to the left of the session title without shifting its alignment, and a static 14px clock icon replaces the right-hand generation ring. Both indicators have a Waiting for approval / 等待审批 tooltip; only the clock carries the accessible label to avoid duplicate announcements. The waiting indicators take priority over the generation ring and unread dot without changing read receipts. Waiting sessions remain selectable and can be pinned or unpinned; Rename, Archive and Permanently delete are disabled. The indicator clears when all pending requests resolve or are cancelled; generation then resumes its ring when still running.
Switching to another session preserves the previous session's latest live status in the list cache before closing its subscription. Older pending list requests are cancelled and a fresh summary is requested, keeping its ring or approval dot visible during the handoff. Background list updates clear the ring when generation finishes, including cancellation and failure.
After generation ends with new output, an 8px blue dot replaces the ring until the latest content has been viewed. Its tooltip and accessible label are Unread / 未读. Selecting a session alone does not clear it: the completed content must reach the conversation viewport in a visible, focused browser page. Scrolling to the latest content or opening a completed chat at its latest content clears the dot; staying at the submitted user message while a longer answer grows leaves it unread. Hidden pages, open dialogs and the mobile sidebar overlay do not mark messages read. Generation keeps the ring instead of the dot.
A boolean unread persists in each session header and survives browser changes, session switches, reloads and server restarts. Reading in one browser updates the other browsers through list notifications. The dot clears after the server confirms the receipt; failed saves remain unread and retry while the completed content is visible. Read requests include the displayed message count so an older page cannot clear newer output. The sidebar renders unread directly; it does not calculate completed turns or keep a read-position cache. Background sessions receive the header flag through list refreshes, including when reopening a collapsed project or reconnecting. Title/model changes and save retries do not set unread again. A cancelled or failed run with saved output can be unread; a run with only a user message cannot. Missing unread metadata defaults to false. Read receipts belong to the Loop server's data directory; separate installations do not synchronize.
Lifecycle and Errors
Revealing more entries changes only the visible portion of the cached session list; it does not make another history request. List refreshes retain the current display limit. Collapsing and reopening a project or the Projects group, or reloading the page, resets the limit to five.
The Pin icon is a diagonal outlined pushpin with a rounded head and shoulder, shared by the row button and context menu. Unpin adds a diagonal slash to the same outline.
Pin sits directly below Rename in the context menu and changes to Unpin for pinned sessions. Pins persist in the session header as optional pinnedAt timestamps, shared by browsers connected to the same server and restored after restarts. Missing pinnedAt means unpinned; the latest timestamp sorts first, with session ID as a stable tie-breaker. The sidebar loads summaries for every accessible registered project even when Projects is collapsed. A successful pin request updates the shared list cache and publishes a sessions.changed notification; other pages and reconnects refresh from the server. Pin changes preserve the current conversation, activity timestamp and drafts, and remain available during generation or approval waiting. Buttons prevent duplicate submissions while saving. Failed requests show a row error and refetch to reconcile uncertain delivery. Archived chats retain their pin for restoration; removing a project hides its pins without modifying session files, so re-adding it restores them. Permanent deletion removes the header with its history. There is no browser pin storage.
The session context menu supports arrows, Home/End and Escape, fits within the viewport and stays above sidebar scrolling. Rename edits the row inline: Enter saves, Escape or blur cancels, and failed saves retain the input. Archive immediately removes only that session from the sidebar and keeps its history, drafts and attachments for restoration from Settings. Neither action asks for confirmation. Permanently delete opens a confirmation warning that the chat and its saved messages will be deleted irreversibly. Cancel and Close do not submit; the confirmation disables closing and duplicate submission while pending. Success removes the complete session storage directory (metadata, messages and index), any retained legacy JSONL backup and associated traces, clears only that chat's local drafts, attachments and pending request, and closes it if selected. Failures retain local data. Deletion errors stay inside the confirmation dialog; closing it or choosing a new row action clears the previous error, so it does not appear under the session title or carry into a new confirmation. Known busy sessions disable Rename, Archive and Permanently delete; the backend also rejects archive and deletion while any session in the project is busy or has pending saves.
Switching sessions preserves unsent drafts and in-memory image attachments, keeps history, and does not stop backend generation. Returning retrieves current state through a snapshot. Reloading restores the selected session. An unavailable project directory shows Directory unavailable and disables new sessions for that project.
The project … button and right-clicking the project row open the same menu containing Archive chats and Remove project, separated by a divider. Both items use the same neutral text and icon color. Right-clicking does not expand, collapse or select a session. Arrow keys and Home/End navigate; Escape closes and restores focus. The menu stays within the viewport and is not clipped by sidebar scrolling.
Archive chats loads all currently unarchived chats even when the project is collapsed, then asks for confirmation with their count and project name. Archive all archives exactly that confirmed selection; chats created afterward remain visible. Archiving changes only archive membership: metadata, messages, index and any legacy backup remain in place on disk and are excluded from the sidebar. Restoring a chat reuses those same files. The selected chat closes after success, while drafts, attachments and unconfirmed requests remain intact. Open Settings → Archived → Archived chats to view and restore chats from registered, accessible projects. Unarchive returns a chat to its project list. Re-add a removed directory to access its archived chats again.
The archive page groups chats into rounded project cards, with folder icons, chat counts, titles and localized last-update timestamps. Filter by project or by all chats, chats with messages, and empty chats. There is no search field. Click a title to open the chat and close Settings. The trash button deletes one archived chat; the project menu deletes all archived chats in that project; Delete all targets every loaded archived chat, regardless of filters. Each deletion requires a second confirmation with its exact count and a permanent-deletion warning. Project files and unarchived chats are preserved. Local drafts and unconfirmed requests are cleared only for successfully deleted chats. Requests run project by project; if one fails, already completed deletions remain completed and the confirmation shows the remaining selection for retry.
Remove project requires confirmation explaining that local files and saved chats will remain. If drafts or unconfirmed requests exist, the dialog additionally warns that unsent data will be discarded. After the backend succeeds, the frontend clears that project's drafts, attachments and unconfirmed requests. If its session is selected, the main area opens a new independent chat. Busy sessions, pending creation/loading or pending saves prevent archive, restore and removal; failures retain frontend state and display an error in the dialog. Cancel, Escape and the close button do not submit changes; closing and repeat submissions are disabled during the request.
The Create project dialog uses a compact 480px width and 360px height, an 18px title, and 13px inputs, folder labels and actions to match existing dialogs. It keeps the same dimensions while selecting or removing a folder, saving and displaying errors. Longer content scrolls within its content area; the footer remains visible. Its size adapts to the viewport.
Each project has one source folder. System folder selection requires local macOS; unavailable pickers show an error in the dialog. There is no typed-path input or browser directory navigator. There is no file-tree editor, history search, or session transfer between projects. See project registration for backend path normalization and persistence.
Source and Tests
- Composer project selector / tests.
- Draft project selection / tests.
- Create project dialog / tests.
- Create project state / tests.
- Source-folder selection and folder row.
- Sidebar / tests.
- SessionItem / tests.
- Unread row indicators, read receipts / tests.
- Session actions / tests.
- ProjectItem / tests.
- ProjectActions / tests.
- Confirmation dialogs / tests.
- Pinned sessions / tests.
- Archived chats / tests.
- useProjects / tests.
- useProjectSessions / tests.
- useDirectoryPicker / tests.
- workspace-store / tests.
- SessionName / tests.
- useSessionRename / tests.
The local session context menu includes Reveal with a folder icon. It opens the saved session’s storage folder in the server computer’s file manager, including while generation is running. Unsaved sessions report an error. This action is unavailable to remote devices.
Independent conversations
The sidebar has separate Pinned, Chats and Projects sections. Chats contains unpinned conversations created with no project. Each section initially shows five entries; Show more reveals the next ten chats, while Show more projects reveals the next ten project nodes. These controls paginate independently and can both appear below the last visible project. Independent chats support the same rename, pin, archive, restore and delete actions as project chats. Project membership is fixed after the first message. See chat input.