Technical Requirements
This document defines implementation requirements for the first version of YAAW - Yet Another Agent Wrapper.
Requirements use:
- MUST: required for the first shippable version.
- SHOULD: expected unless cost or platform constraints make it impractical.
- MAY: allowed but not required.
Platform
- The app MUST target Apple Silicon Macs.
- The app MUST target the latest macOS release only.
- The app MUST be distributed as a native macOS app.
- The app MUST NOT require Intel Mac support for the first version.
- The app SHOULD use platform-native windowing, keyboard handling, focus behavior, menus, and accessibility hooks.
Application Stack
- The app SHOULD be implemented with Swift as the primary application language.
- The app SHOULD use SwiftUI for high-level app structure, sidebar lists, modal sheets, simple controls, and static layout.
- The app SHOULD use AppKit where SwiftUI is not sufficient for terminal embedding, split-view behavior, focus routing, or lower-level macOS window control.
- The app MUST use SQLite for app-owned structured state such as projects, threads, indexes, archives, and layout state.
- The app MUST use a YAML file for user-editable or portable configuration.
- The app MUST keep project metadata in app-owned storage rather than writing metadata into project directories.
- The app MUST keep live terminal process state in memory while running and MUST NOT require restoring live PTY processes after restart.
- The app MUST persist the agent CLI session metadata needed to resume each thread’s bound CLI agent session after the app or thread is reopened.
- The app MUST assume agent CLIs, agent CLI harnesses, authentication, and model configuration are user-owned external tools.
- The app MUST remain a desktop wrapper around local CLIs and MUST NOT become an agent harness, prompt orchestrator, or tool-call proxy.
- The app MUST NOT include telemetry, analytics upload, crash-report upload, or remote diagnostics.
Storage
SQLite
The SQLite database MUST store:
- Projects.
- Project pin state.
- Project manual sort order.
- Threads.
- Thread pin state.
- Thread-to-project relationships.
- Thread working directories.
- Thread agent CLI selection.
- Thread agent CLI session identity.
- Thread canonical CLI session name.
- Thread pending CLI-confirmed rename intent.
- Thread latest activity status, unread flag, and sanitized notification preview.
- Archive state.
- Last selected project.
- Last selected thread.
- Right-panel mode per thread.
- Panel collapsed states.
- Panel sizes.
- Sidebar project expansion state.
- Sidebar per-project archived-thread expansion state.
- File index metadata.
- Durable file index cache entries when caching is enabled.
The database SHOULD store enough metadata to restore the app layout and navigation context after restart.
YAML Configuration
YAML configuration MUST be used for settings that should remain easy to inspect or edit outside the app.
YAML configuration MUST live in app-owned storage by default at ~/Library/Application Support/YAAW/settings.yaml.
YAML configuration MUST include comments that show defaults and identify settings that are represented but not changeable yet.
YAML configuration SHOULD include:
- Theme selection, defaulting to System mode with built-in
macos-lightandmacos-darkpairing plus Dracula and other light, dark, and high-contrast options. - File indexing ignore rules.
- Keyboard shortcuts.
- Default agent CLI.
- Per-agent launch defaults, including permission mode and additional launch arguments.
- Interface, editor, embedded terminal, and file-browser font families and sizes, plus ligature preference.
- Editor, Git, diff, and per-agent command overrides.
- User-level app preferences.
The app MUST expose a settings action in the window title bar that navigates to an in-app YAML editor for the app-owned settings file.
The settings editor MUST validate YAML before saving and MUST NOT overwrite the last saved settings file when validation fails.
Projects
- A project MUST represent a named local directory.
- The built-in
globalproject MUST be scoped to a configurable global chats directory, defaulting to~/yaaw. - The app MUST create the configured global chats directory when it is missing.
- The built-in
globalproject MUST sort below user projects. - Startup and implicit new-thread actions MUST NOT open or create a global chat by default; the user MUST select a project or explicitly create a chat from the global project row.
- Each project MUST have a stable id, display name, root directory, created timestamp, and last opened timestamp.
- Each project MUST have durable pin state and manual sort order.
- Each project MUST have archive state.
- A project MAY have multiple threads.
- A project MAY have threads that point at different worktrees.
- Pinned projects MUST sort before unpinned projects.
- Users MUST be able to drag and drop projects to manually reorder them within pinned and unpinned groups.
- Archived projects MUST move out of the active project list and remain reachable from the combined Archived section at the bottom of the sidebar.
- The built-in
globalproject MUST NOT be archivable.
Threads
- A thread MUST belong to one project.
- A thread MUST be bound to exactly one managed agent CLI session.
- A thread MUST store
agent_clias the selected CLI family. - The product direction MUST include
codex,claude,copilot, andopencodeas CLI families. - The currently implemented adapter set MAY be smaller than the full product direction while adapters are added incrementally.
- A thread MUST store the CLI session identity needed to resume the exact bound agent CLI session.
- A thread MUST have a stable id, display name, project id, working directory,
agent_cli, CLI session identity, created timestamp, last opened timestamp, and archive state. - A thread MUST have durable pin state.
- A thread display name MUST be derived from the bound CLI session’s reported name, title, or id.
- A thread rename MUST be sent to the selected CLI through the adapter and MUST update the visible thread name only after confirmed CLI metadata reports the new name.
- Manual CLI rename commands such as
/renameMUST be reflected in the project/thread panel when metadata confirms the changed name. - A thread working directory MAY be the project root or a separate worktree directory.
- A thread MUST NOT switch from one CLI family to another after it is created.
- New thread creation MUST ask the user which available CLI family to start.
- New thread creation MUST let the user optionally name the thread before launch.
- New thread creation MUST launch the selected agent CLI in the thread working directory.
- Creating a thread from a project row MUST create the thread under that project, even when another project was previously selected.
- Reopening a thread MUST invoke the matching CLI resume behavior for the stored session identity.
- Reopening a thread that has no stored CLI session identity MUST first auto-link a unique exact local CLI catalog match by pending rename, canonical name, or visible display name.
- Reopening a thread that has no stored CLI session identity and no unique exact local CLI catalog match MUST require an explicit link-to-existing-session or start-new-session choice.
- Each thread MUST own one agent CLI session terminal while the app is running.
- Live thread terminal sessions MUST NOT be required to persist after app restart.
- Thread terminal/session state MUST be preserved while the app process is running.
- Archived threads MUST move out of the primary active thread list.
- Archived threads MUST remain reachable from the combined Archived section at the bottom of the sidebar.
- Archived threads MUST retain the agent CLI selection and CLI session identity required for later resume.
- Thread lists MUST sort pinned threads before unpinned threads, then sort by most recently opened.
- Each active thread SHOULD show whether the bound CLI is working, needs input, complete, or inactive.
- Thread activity previews MUST be sanitized and app-owned; YAAW MUST NOT store full terminal scrollback as activity history.
Terminal Requirements
- Every embedded terminal surface MUST use
libghostty. - The app MUST provide one agent CLI session terminal per active thread.
- The app MUST provide one selected-thread bottom terminal.
- The app MUST provide a right-tool-panel terminal for
nvim, falling back tovimand thenvi. - The app MUST provide a right-tool-panel terminal for
lazygit, falling back togit diff. - Agent CLI session terminals MUST launch in the selected thread’s working directory.
- Agent CLI session terminals MUST invoke the selected local CLI according to the selected thread’s stored
agent_cli. - Agent CLI session terminals MUST apply the thread’s captured per-agent launch defaults, including executable command override, permission mode, and additional launch arguments.
- Agent CLI session terminals MUST resume the selected thread’s stored CLI session identity when reopening an existing thread.
- Agent CLI session terminals MUST NOT silently start a fresh agent session for a loaded thread whose stored CLI session identity is missing unless the user explicitly chooses start-new recovery.
- The bottom terminal MUST launch in the selected thread’s working directory.
- The
nvimterminal MUST launch in the selected thread’s working directory. - The
lazygitterminal MUST launch in the selected thread’s working directory. - Terminal sessions MUST preserve runtime state while the app is open.
- Live PTY processes MUST NOT be restored after app restart for the first version.
- SQLite MUST persist terminal metadata, agent CLI resume metadata, and layout state, not live PTY process state.
- Agent CLI terminals SHOULD expose a YAAW-owned
yaaw-notifyhelper onPATHwithYAAW_THREAD_ID,YAAW_PROJECT_ID, andYAAW_EVENT_LOGenvironment variables. - The app SHOULD treat OSC terminal notifications as thread activity events when the terminal surface reports them.
App Layout
- The app MUST have a left project/thread sidebar.
- The app MUST have a central agent CLI session terminal area.
- The app MUST have a right tool panel.
- The app MUST have a right-side area that can contain either the right tool panel or the agent CLI session terminal.
- The app MUST have a selected-thread bottom terminal.
- The left sidebar MUST be collapsible.
- The left sidebar MUST show project rows with nested active thread history.
- Each project row MUST expose a new-thread action that targets that project.
- Project rows SHOULD hide pin actions behind an actions menu.
- Thread rows SHOULD hide pin and archive actions behind an actions menu.
- Thread row actions menus MUST expose
Rename Thread...for CLI families that support confirmable rename. - Agent CLI identity SHOULD use accessible icon-only labels in dense sidebar rows.
- Project disclosure state SHOULD persist across app restarts.
- The right-side area MUST be collapsible.
- Users MUST be able to swap the main agent CLI area with the right-side area.
- The swapped layout MUST persist across app restarts.
- The bottom terminal MUST be collapsed by default per thread.
- The bottom terminal MUST toggle with
Cmd+J. - Toggling or resizing the bottom terminal MUST NOT mutate sidebar width, sidebar collapse state, project selection, thread selection, or left-panel content.
- Every major panel MUST be resizeable.
- Panel size and collapsed state SHOULD persist across app restarts.
Resizeable panels:
- Sidebar width.
- Main agent CLI session terminal width.
- Right-side area width.
- Bottom terminal height when expanded.
Right Tool Panel
The right tool panel MUST be scoped to the selected thread.
The right tool panel MUST keep its selected-thread state whether it appears in the main area or the physical right-side area.
The right tool panel MUST provide four modes:
- Files.
- Browser.
nvim.- Git.
Users MUST be able to switch right-panel modes by clicking mode icons or tabs.
Users MUST be able to cycle right-panel modes with:
Cmd+Shift+[Cmd+Shift+]
The selected right-panel mode MUST be stored per thread.
If two threads happen to share the same panel state because they point at the same working directory, that behavior is acceptable but MUST NOT be required.
File Browser
- Files mode MUST show the selected thread’s working directory.
- Hidden files MUST be shown by default.
- Files mode MUST support fuzzy matching.
- Files mode MUST ignore obviously heavy directories by default.
- Ignore rules SHOULD include
.git,node_modules,dist,.build, and derived-data folders. - File index entries MAY be cached durably in app-owned SQLite and shared by threads with the same canonical working directory, Git identity, ignore-rules fingerprint, and index schema version.
- File index caches MUST remain read-only with respect to user project directories and MUST NOT write app metadata into repositories.
- If a Git branch or detached
HEADidentity changes for a working directory, Files mode MUST use a different cache key to avoid showing stale branch-specific results as current. - File search SHOULD prefer exact filename matches, then prefix matches, then fuzzy path matches.
- Opening a file through the default row action MUST switch the right tool panel to
nvimmode. - Opening a file through the default row action MUST launch
nvim <relative-file-path>in the right-tool-panel terminal. - Supported preview files MUST offer an
Open in Browsercontext-menu action without replacing the defaultnvimbehavior. - Files mode MUST offer
Copy Relative PathandCopy Full Pathcontext-menu actions for files and folders. - Files mode MUST offer exactly two editor context-menu actions: the configured default external editor and the built-in right-tool-panel editor.
- The built-in editor action MUST use the existing
nvimright-tool-panel flow and MUST be omitted for folders. - External file-open actions MUST use the selected thread’s working directory for relative file targets and MUST reject escaping paths.
Browser Mode
- Browser mode MUST appear inside the right tool panel through a native WebKit surface.
- Browser mode MUST run WebKit in an isolated helper process, not in the main app process.
- A browser renderer crash MUST NOT terminate the main app.
- A browser renderer crash MUST show an inline recovery state with a reload or restart path.
- Browser mode MUST support typed web URLs and local preview files opened from Files mode.
- Browser local preview files MUST resolve under the selected thread working directory.
- Browser local preview support MUST include
html,htm,svg,pdf,png,jpg,jpeg,gif,webp,txt,json,xml,md, andmarkdown. - Browser Markdown previews MUST render as generated HTML in the isolated WebKit helper, support Mermaid fenced diagrams, sanitize raw HTML, and preserve relative image and link resolution from the Markdown file directory.
- Browser mode MUST NOT write app metadata into user project directories.
- Browser mode SHOULD keep new-window requests inside right-tool-panel browser tabs.
- Browser mode MAY omit downloads, extensions, developer tools, and profile controls for the first version.
Isolated Tool Hosts
- Risky or heavyweight right-tool-panel tools SHOULD use a reusable isolated helper-process runtime.
- Isolated tool hosts MUST communicate with the main app through a versioned command/event protocol.
- Isolated tool runtime state, helper process ids, viewport frames, and crash counters MUST remain runtime-only and MUST NOT be written into user project directories.
nvim Mode
nvimmode MUST run inside the right tool panel.nvimmode MUST use the selected thread’s working directory.nvimmode MUST NOT open a separate app window.nvimmode MUST use an embeddedlibghosttyterminal.- The app MUST NOT implement a custom text editor for the first version.
Git Mode
- Git mode MUST run
lazygitinside the right tool panel when it is available. - Git mode MUST use the selected thread’s working directory.
- Git mode MUST NOT open a separate terminal window.
- Git mode MUST use an embedded
libghosttyterminal. lazygitMUST be detected from the user’sPATH.- If
lazygitis not installed, Git mode MUST fall back togit diff. - The app MUST NOT implement a custom source control UI for the first version.
Global Navigation
The app MUST support browser-style global navigation:
- Back:
Cmd+[ - Forward:
Cmd+]
Global navigation SHOULD move across recent project/thread selections and major app locations.
Right-panel tab cycling MUST use Cmd+Shift+[ and Cmd+Shift+] so it does not conflict with global navigation.
Theme
- The app MUST default to System mode across all app surfaces.
- System mode MUST follow the current macOS appearance and resolve to the configured
theme.light/theme.darkpairing, defaulting tomacos-lightandmacos-dark. - Dracula MUST remain a built-in dark theme.
- The app MUST support built-in theme switching from Settings.
- Terminals, sidebar, right tool panel, modal sheets, split-view handles, icons, file tree, browser chrome,
nvim, andlazygitsurfaces MUST use the selected built-in visual system. - The implementation SHOULD use shared theme tokens rather than hardcoding colors throughout the app.
Settings
- Settings MUST expose General, Agents, Appearance, Keyboard Shortcuts, and Config File sections.
- General Settings MUST expose default agent selection, Markdown/HTML primary-open behavior, CLI option refresh, build information, and global chats directory.
- Agents Settings MUST expose command override, permission default, and additional launch arguments for each supported CLI family.
- Permission presets SHOULD be discovered from each CLI’s
--helpoutput when possible. - Permission preset discovery SHOULD use cached or fallback presets when a CLI is unavailable or help parsing fails.
- Appearance Settings MUST expose theme group selection, System light/dark pairing, interface/editor/terminal/file-browser fonts, font sizes, and ligatures.
- Config File Settings MUST expose the app-owned YAML, validate before saving, and avoid overwriting the last saved file when validation fails.
Agent CLI Scope
- The first version MUST manage thread sessions through terminal-backed local CLI agent processes.
- Each thread MUST be tied to exactly one CLI agent session.
- The app MUST treat the selected agent CLI or CLI harness as a user-installed executable resolved from settings or
PATH. - The app MUST ask which agent CLI to invoke when starting a new thread.
- The app MUST use the selected CLI session’s reported name, title, or id as the canonical thread display name.
- Closing and reopening a thread MUST resume the associated agent CLI session.
- The app MUST NOT require users to manually run the selected CLI or resume commands for normal thread creation or reopening.
- The app MUST NOT orchestrate multiple agent CLI sessions inside one thread for the first version.
- The app MUST NOT mediate prompts, tool calls, model behavior, or agent decisions beyond launching and resuming the user’s selected local CLI.
- The app MUST NOT replace, bundle, or reimplement the selected agent CLI’s harness, authentication flow, model policy, approval behavior, or tool execution.
- The app MAY surface CLI-agent activity notifications, but MUST keep that behavior status-oriented rather than prompt orchestration.
External Tools
nvimSHOULD be detected from the user’sPATH.codex,claude,copilot, andopencodeSHOULD be detected from the user’sPATHwhen their corresponding adapter is available.lazygitMUST be detected from the user’sPATH.- External project/file open destinations SHOULD include VS Code, VS Code Insiders, Sublime Text, Zed, Finder, Terminal, Ghostty, Xcode, and WebStorm when installed.
- The default external-open destination MUST be configurable in app-owned YAML settings.
- File context-menu default editor actions MUST use the configured external-open default when it is an editor, otherwise the first available configured editor.
- The title bar MUST provide an external-open control for the selected thread working directory, falling back to the selected project root when no thread is selected.
- External file-open actions MUST reveal files in Finder, open containing directories in Terminal/Ghostty, and open files directly in editor apps.
- External tool failures MUST be visible in the embedded terminal surface.
- Agent CLI launch or resume failures MUST be visible in the thread’s agent CLI session terminal.
- The first version SHOULD avoid bundling external CLI tools unless packaging later requires it.
Acceptance Criteria
- A user can create a project from a local directory.
- A user can create multiple threads under a project.
- Creating a thread asks the user which available CLI family to invoke.
- Each thread is bound to exactly one stored CLI agent session.
- A thread’s visible name matches the bound CLI session’s reported name, title, or id.
- Closing and reopening a thread resumes the stored CLI session identity.
- A thread can point at a project root or a separate worktree.
- Each running thread has one agent CLI session terminal.
- Each active thread shows a latest activity indicator and notification preview when available.
- The selected-thread bottom terminal is collapsed by default and toggles with
Cmd+J. - The sidebar, right-side area, and bottom terminal are resizeable.
- The right-side area can be resized across the available workspace up to the projects sidebar boundary.
- The swapped main/right layout persists across relaunch.
- The right tool panel is scoped to the active thread.
- The right tool panel can switch between Files, Browser,
nvim, and Git. Cmd+Shift+[andCmd+Shift+]cycle right-panel modes.Cmd+[andCmd+]perform global back/forward navigation.- Hidden files appear in the file browser by default.
- Supported local preview files can be opened in Browser mode from the file browser context menu.
- Opening a file launches
nvim,vim, orviinside the right tool panel. - A user can open the selected project or selected file in an installed external editor, Finder, or terminal destination.
- Opening Git mode launches
lazygitorgit diffinside the right tool panel. lazygitis resolved fromPATH, withgit difffallback when unavailable.- Project, thread, agent CLI session, index, archive, and layout metadata are stored in SQLite.
- Latest thread activity state is stored in SQLite without persisting full terminal scrollback.
- User-editable configuration is stored in YAML.