Aizen is a macOS developer tool for managing Git worktrees with integrated terminal, file browser, web browser, and AI agent support via the Agent Client Protocol (ACP).
Aizen is migrating incrementally from top-level technical buckets toward a feature-first architecture.
Target direction:
aizen/
├── App/
├── Features/
│ ├── Chat/
│ ├── Worktree/
│ ├── Repository/
│ ├── Browser/
│ ├── Files/
│ ├── Terminal/
│ ├── Workspace/
│ ├── Settings/
│ └── Search/
├── Platform/
├── Integrations/
├── Persistence/
├── Shared/
├── Assets.xcassets/
├── Resources/
└── cli/
Each migrated feature should use:
FeatureName/
├── Domain/
├── Application/
├── Infrastructure/
├── UI/
└── Testing/
This is an incremental migration, not a single rewrite. Legacy folders still exist during transition, but new substantial work should prefer the target feature structure instead of deepening the old buckets.
See:
docs/specs/feature-first-architecture-migration-spec.md
- MVVM: Views observe @ObservableObject models (e.g., AgentSession, ChatSessionViewModel).
- Actor model: Thread-safe services (ACPClient, Libgit2Service, XcodeBuildService).
- Delegation: Request handling (AgentFileSystemDelegate, AgentTerminalDelegate, AgentPermissionHandler).
- Domain services: Git operations split by domain (GitStatusService, GitBranchService, etc.).
- Core Data: 10 persistent entities with relationships.
- Modern concurrency: async/await, AsyncStream.
Agent Client Protocol (ACP)
- ACPClient (actor): Subprocess manager with JSON-RPC 2.0.
- ACPProcessManager: Process lifecycle management.
- ACPRequestRouter: Request/response routing.
- AgentSession (@MainActor): Observable session state wrapper.
- AgentInstaller: NPM, GitHub, Binary, UV installation methods.
- Supports Claude, Codex (OpenAI), and Gemini.
Git Operations
- RepositoryManager: CRUD for workspaces, repos, worktrees.
- Libgit2Service: Native libgit2 wrapper for git operations.
- Domain services: GitStatusService, GitBranchService, GitWorktreeService, GitDiffService, etc.
- GitDiffProvider + GitDiffCache: Diff fetching with caching.
- ReviewSessionManager: Code review sessions.
Terminal Integration
- GhosttyTerminalView: GPU-accelerated terminal with Metal rendering.
- Split pane support via TerminalSplitLayout.
- Terminal presets and session management.
- Shell integration with Ghostty resources.
Chat Interface
- ChatSessionView + ChatSessionViewModel: Full session UI.
- MessageBubbleView: Message rendering with markdown, code blocks.
- ToolCallView + ToolCallGroupView: Tool call visualization.
- Voice input with waveform visualization.
- File attachments and inline diffs.
File Browser
- FileBrowserSessionView: Tree view with file operations.
- FileContentView: File content display with syntax highlighting.
CI/CD Integration
- WorkflowSidebarView: GitHub Actions / GitLab CI display.
- WorkflowRunDetailView: Run details and logs.
- XcodeBuildManager: Xcode build integration.
- Treat Aizen as greenfield for internal architecture work, not as a legacy codebase that must preserve internal structure.
- Apply this policy to refactors, bug fixes, and new feature work.
- Prefer root-cause changes over local patches that merely fit the current shape.
- When adding something new, prefer the design that makes the system more scalable, maintainable, and coherent, even if that means reworking surrounding code.
- Do not preserve internal backward compatibility just to avoid touching call sites.
- Do not add shims, adapter layers, parallel code paths, or temporary wrappers unless there is a real external compatibility requirement.
- When a design is wrong, replace it from the ground up so the resulting code is simpler and more maintainable.
- Keep compatibility only at genuine external boundaries:
- persisted Core Data / on-disk data
- user-visible behavior that must intentionally remain stable
- external protocols, CLIs, APIs, and integrations
- Remove dead code when changing systems instead of leaving legacy paths in place.
- If improving a feature or fixing a bug requires breaking internal structure to make the system better, prefer the cleaner break.
- New substantial feature work should land in
Features/<FeatureName>/whenever the ownership boundary is clear. - For migrated features, keep all new code inside that feature subtree.
- Do not add new broad top-level
Managertypes unless they are truly app-global. - Do not place non-view feature orchestration in
Views/. - Do not place feature-specific orchestration in
Utilities/. - Prefer explicit ownership names such as
Store,Coordinator,Repository,Registry, orServicebased on actual responsibility. Domainis for pure feature types and policies.Applicationis for feature state and orchestration.Infrastructureis for Core Data, ACP, libgit2, WebKit, filesystem, and other external integrations.UIis for SwiftUI/AppKit presentation only.
-
Respect feature boundaries first:
- migrated feature code ->
Features/<FeatureName>/ - app entry/composition/window wiring ->
App/ - platform wrappers such as Ghostty/libgit2/Xcode ->
Platform/or featureInfrastructure/ - cross-feature external integrations ->
Integrations/ - persistence implementation ->
Persistence/or featureInfrastructure/
- migrated feature code ->
-
Keep files focused:
- Extract large views into components.
- Split files over 500 lines when logical.
- Put reusable components in Components/ folders.
-
Use modern Swift patterns:
- Actors for concurrent operations.
- @MainActor for UI state.
- async/await over completion handlers.
- AsyncStream for event streaming.
- If a feature subtree exists, place new feature code there instead of legacy buckets.
- If a feature is large and scattered, prefer creating
Features/<FeatureName>/rather than adding more files underServices/,Views/, orManagers/. - Keep reusable cross-feature UI in
Shared/once that subtree exists; otherwise use the existing shared-components area until migrated. - Keep utilities generic. If logic is feature-specific, it does not belong in
Utilities/. - Use
git mvfor moves when practical to preserve history.
- Prefer atomic commits.
- Each commit should represent one coherent change with a clear purpose.
- Do not mix structural refactors, behavior changes, and incidental cleanup in the same commit unless they are inseparable.
- For feature-first migrations, prefer a sequence such as:
- compile-stable file moves
- ownership split / dependency updates
- behavior-preserving cleanup
- tests
- Before creating a commit, review the diff and exclude unrelated changes.
ACP Flow
- User input -> ChatSessionView
- -> ChatSessionViewModel.sendMessage(_:)
- -> AgentSession.sendMessage(_:)
- -> ACPClient.sendRequest(_:)
- -> Subprocess (agent binary)
- <- JSON-RPC notifications (streamed)
- -> Delegates (AgentFileSystemDelegate, AgentTerminalDelegate)
- -> Published state updates
- -> SwiftUI view refreshes
Add new agent support
- Update AgentRegistry.swift with agent config.
- Add icon to Assets.xcassets/AgentIcons.xcassetcatalog/.
- Update AgentIconView.swift for icon mapping.
- Add installer in Services/Agent/Installers/ if needed.
Add new Git domain operation
- Create service in Services/Git/Domain/ (e.g., GitNewFeatureService.swift).
- Add methods following existing patterns.
- Integrate with Libgit2Service or shell commands as needed.
Modify ACP protocol
- Update types in Models/ACP/ (split across multiple files).
- Handle in ACPClient or appropriate delegate.
- Update AgentSession if state changes needed.
- Update UI in relevant view.
- libghostty: GPU-accelerated terminal with Metal.
- libgit2: Native git operations.
- swift-markdown: Markdown parsing (Apple official).
- VVDevKit highlighting: Tree-sitter syntax highlighting.
- Sparkle: Auto-update framework.
- Minimum: macOS 13.5+.
- Xcode 16.0+.
- Swift 5.0+.
- All file paths must be absolute in tool operations.
- Use git mv for file moves to preserve history.
- Deep linking via aizen:// URL scheme.
Entities
- Workspace -> Many Repository -> Many Worktree.
- Worktree -> TerminalSession, ChatSession, FileBrowserSession, BrowserSession.
- ChatSession -> Many ChatMessage -> Many ToolCallRecord.
- Use Swift naming conventions (camelCase, PascalCase for types).
- Prefer explicit types for clarity in complex code.
- Add comments for non-obvious logic, especially in ACP protocol handling.
- Group related properties/methods with // MARK: - Section.
- Keep line length reasonable (~120 chars).
Build fails after file move
- Xcode project references must be updated manually if not using git mv.
- Clean build folder: Cmd+Shift+K.
Agent not connecting
- Check agent binary path in Settings > Agents.
- Verify agent supports ACP protocol.
- Check console logs for subprocess stderr.
Terminal not displaying
- GhosttyTerminal requires proper frame size and Metal support.
- Check terminal theme configuration in Resources/.
- Verify process spawn permissions.
- Agent Client Protocol Spec: https://agentclientprotocol.com
- Ghostty Terminal: https://github.com/ghostty-org/ghostty
- swift-markdown: https://github.com/apple/swift-markdown
- libgit2: https://libgit2.org/