Repository navigation
How the AI Panel Works
The AI panel lists the workspace's projects, their worktrees and the AI agents running in them, and starts agents in editor tabs. New Task and Finish Task are in How AI Tasks Work. The user side is AI Agents; worktrees themselves are in How Worktrees Work, terminals in How the Terminal Works.
People run coding agents (Claude Code, Codex...) beside their editor, often several at once, each in its own git worktree so they never edit the same files. The panel follows that shape: projects, worktrees under them, agent tabs under those, and a status for each agent. Nibtree already had worktrees and terminals in editor tabs, so the panel ties them together.
flowchart LR
WS["repoStore: folders, repos"] --> P["projects.ts: workspaceProjects"]
WT["aiStore: list_worktrees per repo"] --> R["projects.ts: panelRows"]
P --> R
T["terminalStore: agent tabs"] --> S["sessions: agentSessions"]
S --> R
R --> UI["AiPanel.svelte"]
UI -->|"+ / Start Agent"| ST["sessions: startAgent"]
ST -->|"run_script, location editor"| T
X["xterm title"] -->|"agentStatus.ts"| T
settings.rightPanel ("files", "ai" or "notifications", saved per window in state.json) says what the right sidebar shows; explorerOpen still says whether it is open. toggleRightPanel(panel) hides the sidebar when that panel is shown and switches to it otherwise, so the activity bar buttons (RightActivityBar.svelte) behave like the left bar's. Menus, MCP and the buttons read settings.filesPanelShown, aiPanelShown and notificationsPanelShown (notifications). Workspace.svelte mounts one panel at a time.
workspaceProjects(folders, repos) turns the workspace into projects: every workspace folder (a plain folder project, unless the folder is a repository itself), then the repositories found in it, without submodules. aiStore.loadWorktrees(roots) reads list_worktrees for each repository when the panel opens, on Refresh, after the panel's own changes and when the active repository's refs change (their fingerprint covers worktrees). Nothing polls.
panelRows(projects, worktrees, sessions, collapsed) builds the flat row list:
- One project per repository. A linked worktree the workspace opened as a folder is a repository too. Every loaded list maps its worktrees to their main worktree; a project's own list wins (a moved worktree folder is listed by its old path). Projects with the same main worktree become one, named after the main folder.
- Each worktree once. A worktree two lists name stays under the first project, so row keys never repeat.
- Agents in the deepest place. An agent tab goes under the worktree or plain folder holding its folder (the longest match); tabs outside every project come last under "Other folders".
panelView.ts draws the rows: groupRows makes a section per project with a card per worktree and its agents inside; filterRows keeps what matches every word of the filter, with the worktree and project around a matching agent; mostUrgent gives a card its mark; attentionCounts fills the "needs you" and "working" pills; formatAge writes "4m" from the agent's changedAt, refreshed every 30 s while the panel is open. AgentStateIcon.svelte draws the marks with the UI library's StatusIcon (the spinner only while an agent works). Menus and worktree actions live in panelActions.ts.
agents.ts is the catalog: id, label, program and the full-autonomy flags, taken from each agent's own documentation. These are defaults: agentConfig.ts applies the user's Settings > AI changes (aiAgentCommands). The Rust command find_agent_programs (commands/ai.rs, run_process::find_programs) resolves each program on the login shell's environment, the same one the Run tab uses, with Windows' PATHEXT. Only bare names are looked up.
startAgent(agentId, folderPath) (sessions.svelte.ts) asks the permission mode on the first start (dialogs.choose, saved as aiPermissionMode), adds the flags in full mode and the user's extra arguments (splitArguments, shell-like quoting, nothing expanded), and calls terminalStore.startAgent. That is a terminal entry with location: "editor", a run spec (so run_script starts the exact file that was found, in the worktree) and an agent record (agentId, folderPath, title, state).
EditorTabs.svelte derives agentFolder, the worktree of the agent its group shows, and draws a + after the tabs while there is one. It focuses that group and opens startMenu(agentFolder), so the new agent or Blank Terminal opens beside it.
TerminalView passes each title change to terminalStore.setAgentTitle. agentStatus.ts reads it: braille or quarter-circle spinners and Gemini's ✦ mean working; Claude's ✳ and Gemini's ◇ mean idle; ✋ or "action required" mean the agent waits for the user. nextState turns that into Starting, Ready, Working, Needs you, Done or Exited. The stored title is cleaned of spinner frames, so the store only changes when the state or the words change, not on every frame; a title that only states the status ("claude - action required") keeps the last task title (isStatusOnlyTitle). A change from Working to Done or Needs you while the tab is hidden rings the tab's bell, and the robot button shows a dot.
An agent tab survives a clean exit (shells close), shows "Agent exited" with Restart, and keeps its agent and run across Clear Cache (terminalStash.ts). Restart is a restartRequest the tab's TerminalView answers with its Retry path.
| File | What it does |
|---|---|
src/lib/ai/projects.ts |
Projects, one per repository, and the panel rows |
src/lib/ai/agents.ts |
Agent catalog, argument splitting, command line |
src/lib/ai/agentStatus.ts |
Title to status and state |
src/lib/ai/aiStore.svelte.ts |
Worktree lists, collapsed rows |
src/lib/ai/sessions.svelte.ts |
Installed agents, starting, the permission question, New AI Agent |
src/lib/ai/panelView.ts |
Sections and cards, filter, counts, ages, agent marks |
src/lib/ai/panelActions.ts |
Row menus, New Worktree, Remove Worktree |
src/lib/ai/AiPanel.svelte, AiPanelRows.svelte, AgentStateIcon.svelte
|
The panel, its tree rows and state marks |
src/lib/ai/AiAgentSettings.svelte |
Settings > AI agent list (library Card, Row, Field, Input, Select) |
src/lib/terminal/terminalStore.svelte.ts |
startAgent, restartAgent, setAgentTitle, agent menus |
src-tauri/src/run_process.rs, commands/ai.rs
|
find_agent_programs |
Agent tabs are terminals. They reuse the PTY, output flow, find, links, Clear Cache and editor tabs, so an agent behaves exactly as in a terminal.
Run the found file. The panel starts the path detection reported, so what runs is what Settings shows, and screenshots can use a stand-in agent.
Ask once, then a setting. Full autonomy is useful in a worktree but risky in a main checkout, so the user chooses it knowingly on the first start.
Titles, not hooks. Agent hooks would need installing in each agent; titles need no setup and cover the agents we list.
-
projects.test.ts: projects from folders and repositories, rows, the deepest place, collapsed rows, linked and moved worktrees, unique keys. -
panelView.test.ts: sections and cards, the filter, urgency, counts, ages. -
agents.test.ts,agentStatus.test.ts(real agents' title cases),sessions.test.ts. -
terminalStash.test.ts: agent tabs across Clear Cache. - Rust:
run_processtests find only bare executable names, and.cmdfiles with Windows extensions. - Screenshots
ai-panel,ai-new-tab,ai-permissionandai-settingsrun a stand-in agent from the demo folder (writeDemoAgentinscripts/screenshots.ts); the page answersfind_agent_programs, so a real agent never runs.
- Add an agent in
agents.ts, its name inagentStatus.tswhen its titles carry it, and the user page's list. - Retake the three screenshots when the panel's look changes.
The window stopped updating when the AI panel opened.
- The issue: with linked worktrees open as folders, the panel showed only "main" rows and the whole window stopped reacting.
- Why it happened: a moved worktree folder's list named the main worktree again, so two rows had the same key, and Svelte's keyed each block threw during an update.
- The fix and why we chose it: one project per repository, grouped by main worktree, and each worktree listed once, so keys cannot repeat whatever the lists say.
These pages are generated from docs/wiki. To correct something, open a pull request against the source file; edits made here are overwritten.
Using Nibtree
- Getting Started
- Welcome Screen
- Workspaces
- Files Panel
- File Operations
- File Icons
- Rounded Panels
- Editor and Tabs
- Pin Reorder and Wrap Tabs
- Single Tab Title
- Split Editor
- New File and Unsaved Changes
- Unload Hidden Tabs
- Editing Code
- Code Appearance
- Markdown Editor
- Image and PDF Preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and Replace
- Changes and Commits
- Sign In Prompts
- Commit Box Layout
- Repository Actions
- Commit Options
- Ignoring Files
- Diffs
- Inline Diffs
- Staging View
- Revert a Change
- Resolving Conflicts
- Merge Tool
- Blame
- History and Log
- Merge Commits
- Branches and Tags
- Branches Popup
- Remotes
- Stashes
- Shelf
- Git Menu
- Git Dialogs
- Interactive Rebase
- Worktrees
- AI Agents
- AI Tasks
- AI Usage
- Keep Computer Awake
- Submodules
- Git LFS
- GitHub
- Git Console
- Terminal
- Terminal Features
- Scripts
- Navigation
- Menus
- Settings
- Settings Search
- Color Themes
- Settings Terminal and Automation
- Settings Files
- Updates
- Status Bar and Help
- Notifications
- Memory Use
- Clear Cache
- MCP and CLI
- Git Mergetool
- Keyboard Shortcuts
- Keyboard Shortcuts Editor
- Troubleshooting
- Troubleshooting Git
Developers
- Developer Guide
- Architecture
- Project Layout
- Backend
- How Folder Watching Works
- Folder Watching Bugs We Fixed
- How Workspace Files Work
- How the Preview Scheme Works
- Backend Services
- How Terminal Features Work
- Terminal Bugs We Fixed
- Frontend
- How the Rich Markdown Editor Works
- Rich Markdown Bugs We Fixed
- Git Menu Links
- Menu Keys and Routing
- Frontend Modules
- Blame Bugs We Fixed
- Project Color And Title Bar
- One Diff View
- Diff Bugs We Fixed
- Merge Tool Layouts
- Merge Tool Bugs We Fixed
- Color Theme Bugs We Fixed
- How the Connected Diff Works
- Rounded Panels Bugs We Fixed
- Update Bugs We Fixed
- Status Bar Bugs We Fixed
- MCP and CLI Bugs We Fixed
- Repository Actions Bugs We Fixed
- How the Changes Tab Works
- CodeMirror Patterns
- How the Cursor Works
- How Editor Features Work
- How the Path Bar Works
- Commands and Events
- Settings Reference
- Commands Workspace and Changes
- Commands Branches and Remotes
- Commands History and Extras
- Commands App and Tools
- Testing
- Test Suites
- Debugging
- Debugging with MCP
- Measuring Setting Memory
- How Terminal Memory Is Measured
- How Markdown Diagrams Work
- Releases and CI
- Publishing the Wiki
- Versioning and Changelog
- Browser Version Packages
- Browser Release Checks
- Docker Image
- Platforms and Signing
- Windows Support
- Windows Bugs We Fixed
- Windows MCP and CLI
- Docs and Screenshots
- UI Library
- UI Library MCP
- UI Library Bugs
- UI Library Migration
- Contributing
How features work
- Welcome screen
- Workspaces and folders
- Files panel
- File operations
- File icons
- Editor and tabs
- Pin, reorder and wrap tabs
- Single tab title
- Split editor
- New File and unsaved changes
- Unload hidden tabs
- Editing code
- Code appearance
- Markdown editor
- Image and PDF preview
- Search Everywhere
- Recent Files
- Navigation Bar
- Find and replace
- Changes and commits
- Sign-in prompts
- Commit box layout
- Repository actions
- Commit options
- Ignoring files
- Diffs
- Inline diffs
- Staging view
- Revert a change
- Resolving conflicts
- Merge tool
- Blame
- History and log
- Merge commits
- Commit tabs
- Branches and tags
- Branches popup
- Remotes
- Stashes
- Shelf
- Git menu
- Git dialogs
- Interactive rebase
- Worktrees
- AI agents
- AI usage
- Keep computer awake
- AI tasks
- Submodules
- Git LFS
- GitHub account
- Git Console
- Back and Forward
- Integrated terminal
- Scripts tool window
- Menu bar
- Settings
- Search in Settings
- Color themes
- Rounded panels
- Updates and release channels
- Status bar and help links
- Notifications
- Memory readout and memory log
- Clear Cache
- MCP server and command line tool
- git mergetool mode