24 KiB
type, title, description, tags, verified, sources, generated
| type | title | description | tags | verified | sources | generated | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| engineering quickstart | Termind Engineering Quickstart | Route Termind coding tasks to system owners, focused workflows, and safe validation commands. Start with the changed boundary, then follow its guide to authoritative source and behavioral tests. |
|
|
|
|
Termind Engineering Quickstart
Termind is one Xcode project with native TFM (macOS) and TFI (iPhone/iPad) app targets over shared frameworks, plus separate test, widget, and macOS MCP bridge products. Platform UI and lifecycle remain app-owned; source and tests are authoritative. Before changing an ownership boundary, read Engineering Invariants, then the narrowest guide below.
1. Find the owner
Architecture and native UI
| Task | Guide and focused check |
|---|---|
| Module placement, imports, nested directories, shared resources | Module and Product Map → System Boundaries. For placement, use Shared Module Ownership, Native App Responsibilities, or Supporting Systems. Run ArchitectureBoundaryTests for dependency changes. |
| Composition, startup failure, window/scene state, backgrounding, quit | Platform Startup and Runtime Composition; choose AppTerminationTests, MobileAppTests, MobileWorkspaceSessionTests, or MobileForwardingLifecycleTests. |
| Desktop Navigator, sidebar, workspaces, Vault, Assistant layout | macOS UI and Workspace Ownership; use the relevant window/navigation or layout tests. |
| Desktop Workspace/Pane sorting, merging, drag-out windows, Assistant reordering | TFM Drag and Drop; preserve native Workspace List source and live receiver contracts. Start with WorkspaceNavigatorDropTests, WorkspaceLayoutDropTests, WorkspaceWindowMoveTests, or AssistantConversationListDropTests, then the guide's source/cancellation/animation suites. |
| Mobile tabs, scene routes, cards, editors, terminal continuity | iOS and iPadOS UI and Scene Ownership; use MobileWorkspaceSessionTests for window-owned connections/routes, MobileAdaptiveLayoutTests or MobileNavigationParityTests for UI, and MobileMetricsJourneyTests for metrics authentication/navigation. |
| Shared UI conventions, fields, tokens, accessibility | UI Design and Shared Presentation; check platform renderings and ArchitectureBoundaryTests. |
| File drops, Assistant attachments, terminal/SFTP uploads, remote-file dragging, Key import | File Drag and Drop; trace native routing, payload priority, staging and transfer lifetimes. Use FileURLDropTargetTests, MobileDropTests, and the guide's upload/attachment/import suites; it also locates shared Overlay UI. |
Terminal, connection journeys, and remote services
| Task | Guide and focused check |
|---|---|
| Mobile terminal Find, SFTP filtering, native search dismissal | Mobile UI and Ghostty Terminal Integration. Start at MobileWorkspaceSearchModifier and MobileToolbarSearch; use TerminalFindControllerTests for shared Find policy and MobileTerminalSearchIntegrationTests in TFITests/MobileTerminalSearchTests.swift for repeated close/reopen, retained queries, empty queries, and native/programmatic dismissal. |
| Connection-journey surface retention | The same Mobile UI and Ghostty integration guides: keep the search modifier outside journey-dependent content and hide, rather than replace, the terminal surface. MobileTerminalSearchIntegrationTests.connectionJourneyKeepsSearchAndTheTerminalMounted checks search-controller identity for SSH/SFTP and attached terminal identity for SSH. |
| Ghostty menus, touch selection, themes, highlighting, native surface identity | Ghostty Terminal Integration; Termind overrides separate unselected/selected iOS touch hooks, while macOS composes its secondary-click menu through AppKit hooks. Run MobileTerminalUploadMenuTests and TerminalContextMenuTests. Inspect the resolved package or initialize the maintenance checkout before investigating package-owned pointer/selection behavior; do not infer it from the touch adapters. |
| Ghostty fork, Swift hooks, native patches, XCFramework, dependency pin | Ghostty Fork Maintenance; coordinate the pushed fork, submodule gitlink, project minimum version and resolved pin. Native patches require publishing a new XCFramework with matching package URL/checksum first. |
| SSH/Telnet, credentials, routes, trust, session cleanup | SSH, Telnet, Trust, and Workspace Session Lifecycle; select connection, trust, authentication and session tests. Shared journey state uses ConnectionJourneyTests; native mobile rendering uses MobileConnectionJourneyRenderingTests. For admission/backpressure, see SSH Multiplexing and I/O Scheduling. |
| SSH Security Key registration, FIDO2/WebAuthn, Vault metadata, forwarding restrictions | SSH Security Key Authentication; use WebAuthnVaultMetadataTests for destination/jump metadata resolution without Keychain, V45/V2 metadata, compatibility normalization and rollback; WebAuthnSSHTests for registration/assertion parsing and SSH wire fields; SSHInteractionPolicyTests for silent-connection restrictions. These synthetic fixtures do not replace hardware-key/native-prompt checks. |
| Terminal services, metrics, forwards, shell hooks, forwarding pools | Remote Services and Forwarding, Shell Integration, and Port Forwarding Dispatch; choose service/pump tests. Metrics keyboard-auth presentation uses MetricsJourneyRenderingTests on desktop and MobileMetricsJourneyTests on mobile. |
| Tailscale groups, login/Save/logout, stable peer IDs, routing, SSH approval, profile cleanup | Tailscale Groups, Embedded Nodes, and SSH; trace TailscaleModel, group editor, group-scoped Host identity, native node and local profile store. Use group-editor, identity, integration, cleanup, Metrics and sync-safety tests. |
| SFTP browsing, scheduling, external edit | SFTP Transfer, Scheduling, and External Edit; select transfer, conflict or edit tests. Native filter presentation also follows the mobile search route above. |
Data, Assistant, and product operations
| Task | Guide and focused check |
|---|---|
| Assistant turns, approvals, host tools, skills, memory | Assistant and Agent Runtime; target preparation, cancellation, persistence, tools or memory tests. |
| SwiftData, secrets, migrations, settings, CloudKit | Persistent Data, Migrations, and Secrets, Settings and Cloud Sync, and CloudKit Release Readiness. Select repository/migration tests or CloudSyncLifecycleTests, CloudSyncSafetyTests and coordinator tests for sync changes. |
| MCP server, external upload/download, stdio bridge | MCP Server, Transfers, and Stdio Bridge; run token, server-session, transfer or bridge tests. |
| Commerce, localized copy, widgets, screenshots, website | Commerce, Localization, and Product Surfaces, Storefront Commerce Release Checks, Marketing Assets and App Icons, and Build, Test, and Release. Choose bilingual catalog, app/language, screenshot, StoreKit or website checks. |
| Deterministic fixture or test seam | Behavioral Tests and Fixtures; run the narrow behavioral regression before the affected target suite. |
2. Preserve the changed boundary
These are routing reminders, not replacements for the detailed guides.
Dependency direction and release source
TermindDomaindefines portable rules;TermindApplicationowns ports/use cases;TermindPersistenceowns SwiftData models, repositories and container construction; infrastructure implements services;TermindPresentationowns reusable SwiftUI content/copy. Apps assemble concrete dependencies and native UI.ArchitectureBoundaryTestsenforces root-specific restrictions, not an all-UI-framework ban. Its five non-presentation shared-framework rule rejects app targets andAppKit,UIKit,IOKit,ServiceManagement. Presentation allowsSwiftUIbut rejects app targets, native UI, storage, concrete infrastructure andStoreKit. Shared Application cannot import Infrastructure, Persistence or SwiftData. Desktop Application/Features and mobile layers have their own checks; selected roots also guard concrete construction, AgentKit type duplication and SwiftData ownership. Fix the boundary rather than bypassing the test; see System Boundaries.- AgentKit is a separately versioned, host-neutral remote package owning the loop, approvals, providers, MCP client and built-in tools. Termind owns SSH/SFTP tools and registers them additively. Xcode's requirement starts at
0.18.1underupToNextMajorVersion; the sibling working tree is not the resolved build. Cross-repository work means test/release../AgentKit, updateminimumVersioninTermind.xcodeproj/project.pbxproj, and re-resolveTermind.xcodeproj/project.xcworkspace/xcshareddata/swiftpm/Package.resolvedtogether. - Ghostty has a different maintenance boundary:
libghostty-spm/is a maintenance submodule, not Xcode's build source. The remote fork requirement starts at2.2.2026100303, and the resolved pin selects that release. Package changes require pushing the fork and aligning the gitlink, project requirement and resolved pin; native patch changes additionally require a new XCFramework and manifest URL/checksum. See Ghostty Fork Maintenance. The maintenance directory is empty in this checkout; no package view implementation was inspected here.
Native lifetimes and presentation
- Desktop:
TermindAppcreates the container and sharedAppModelat launch, using in-memory stores for XCTest/debug screenshot demos. Database-open failure fails startup instead of replacing the store. Each mainWindowGroupowns aWindowModel;RootViewregisters the window, publishes its focused scene value and preserves mounted workspace views across destinations. The external-authenticationWindowshares the app environment/container but removes its manual Window-menu command; it is not another main workspace. - Mobile:
TermindIOSAppmigrates language preferences and creates one live/testingMobileAppModel;MobileStartupViewinjects its container on success or shows unavailable data on failure. Startup waits for the native scene delegate's session ID;MobileBoundSceneRootcreates/retainsMobileSceneModelin a task and binds the delegate on appearance. Scene-local navigation/Assistant presentation sits over a persistent UIKit-session-ownedMobileWorkspaceSessionModel, not one interchangeable cross-window workspace pool. - Restoration: cold launch consolidates saved descriptors into the first bound mobile session without connecting; restore failure reports an error rather than letting another scene claim them. Selecting a descriptor publishes the owner's workspace before connecting and repeated selection reuses it. A link in another window activates the owner. Backgrounding/removal alone does not discard workspaces: reconciliation can transfer a disappeared session's live workspaces to an active session without reconnecting; explicit discard closes them. Descriptors must not persist transports, secrets, one-shot commands or initial paths. Desktop session/pane and mobile workspace owners end their connection-history entries on close. Follow Mobile UI and Session Lifecycle.
- Search: SSH/Telnet binds the workspace's
TerminalFindControllerto Ghostty binding actions; SFTP binds search text tosftpChannel.query.MobileToolbarSearchgives UIKit ownership of search presentation and fences SwiftUI synchronization during dismissal. Native terminal-search dismissal ends Find without requesting terminal focus; queries survive closing and reopening. Journey presentation retains the search attachment; the terminal remains mounted but hidden and noninteractive. See the focused tests above rather than replacing this native lifecycle with SwiftUI search-focus state. - Menus:
MobileTerminalViewcustomizes bothtouchMenuItems(for:)andtouchSelectionMenuItems(for:), grouping/localizing editing actions before uploads and remaining system items. Desktop usesselectionMenuPoint(at:),selectionContextMenu()andmenu(for:). The app adapters/tests establish these seams; package-owned indirect-pointer behavior needs separate package inspection.
Shutdown, sync, and authentication safety
- Mobile phases aggregate across scenes: pause background services only when all registered scenes background. Expiration suspends workspaces, stops forwards, pauses transfers and expires Assistant work; an active scene resumes monitoring, memory, workspaces, eligible sync and metrics. Use Platform Runtime.
- Closing the last macOS window never terminates the Debug test host; otherwise menu-bar metrics preferences and running metrics decide. Quit rechecks unuploaded SFTP edits and permits cancellation. Confirmed termination fences new Assistant work, drains cancellation/persistence, stops transfers/MCP and closes agent resources. AppKit receives one reply after cleanup or a three-second fallback; the fallback bounds the reply, not asynchronous cleanup completion.
CloudSyncLifecycleowns a separate engine/account scope per category: persist a recovery fence before automatic syncing, fetch before authorizing uploads, and reconcile pending changes against the durable journal. Pause, account changes and non-cancellation persistence failures retire/cancel the engine outside delegate context; late completions cannot update its replacement. A build is not a sync migration check: use CloudKit Release Readiness and the lifecycle/safety/coordinator tests.- Shared
ConnectionJourneytracks route progress and authentication/host-key checkpoints;ConnectionJourneyRouteViewdraws the common route, while apps own prompts/navigation. Use shared state tests, then affected native rendering/metrics fixtures; rendering is not a live SSH test. - Security Key references remain external Vault metadata with compatibility normalization; failed metadata writes/deletes roll back, and software keys cannot use external storage. A forbidden SSH interaction policy blocks destination/jump security-key credentials even with optional user presence. Keep silent auxiliary connections from triggering hardware prompts.
3. Validate narrowly, then validate the product
Keep -onlyUsePackageVersionsFromResolvedFile so ordinary builds cannot silently move the dependency graph:
xcodebuild -project Termind.xcodeproj -scheme TFM -destination 'platform=macOS' -onlyUsePackageVersionsFromResolvedFile build
xcodebuild -project Termind.xcodeproj -scheme TFM -destination 'platform=macOS' -onlyUsePackageVersionsFromResolvedFile test
xcodebuild -project Termind.xcodeproj -scheme TFI -destination 'generic/platform=iOS Simulator' -onlyUsePackageVersionsFromResolvedFile build
xcrun swift-format lint --strict --recursive Frameworks TFM TFI FrameworkTests TFMTests TFITests TermindMCPBridge
Scripts/check-zh-localization.sh
Use an installed iPhone/iPad simulator for TFI tests. For the search integration regression, replace the destination below with one installed locally:
TEST_RUNNER_TERMIND_MOBILE_UI_TESTS=1 xcodebuild -project Termind.xcodeproj -scheme TFI -destination 'platform=iOS Simulator,name=<installed simulator>' -onlyUsePackageVersionsFromResolvedFile -parallel-testing-enabled NO -only-testing:TFITests/MobileTerminalSearchIntegrationTests test
Native presentation gates
- Visible-window macOS tests require
.requiresVisibleWindowandTEST_RUNNER_TERMIND_WINDOW_TESTS=1(orTERMIND_WINDOW_TESTS=1in the Xcode test action), preferably with-only-testing:TFMTests/<Suite>. Debug XCTest still launches the real desktop app, but automatic main/external-auth windows and main-scene restoration are suppressed by default. The opt-in or an active screenshot demo lifts window suppression; demos also disable restoration. Host suppression complements, not replaces, the test trait. - Mobile key-window integration suites require
TEST_RUNNER_TERMIND_MOBILE_UI_TESTS=1,-parallel-testing-enabled NO, and a narrow-only-testing:TFITests/<Suite>.MobileAdaptiveLayoutTestsandMobileMetricsJourneyTestsare serialized but not environment-gated; use narrow nonparallel runs for their process-wide UIKit fixtures. Keep presentation gates off for routine checks; offscreen tests remain enabled. - Mobile journey screenshot export remains entirely opt-in under
TERMIND_JOURNEY_SCREENSHOTS. Follow Behavioral Tests and Fixtures for fixture limits.
Copy, web, and release checks
- Define app copy in shared
TermindPresentation/Strings; new/changed English text needs finishedzh-Hansandzh-Hanttranslations inFrameworks/Resources/Localizable.xcstrings. Catalogs are manually managed: after edits runScripts/normalize-string-catalogs.py --write,Scripts/check-appstrings.sh, andScripts/check-zh-localization.sh(requiresjq). Run the Chinese check even without intended copy changes; useAppLanguageTestsfor language behavior. - Web changes:
cd LandingPage && npm ci && npm run build, then check English and/zh/routes. - Initialize
libghostty-spm/withgit submodule update --init libghostty-spmonly for maintenance inspection; routine pinned builds do not use it. - Before submitting, inspect the diff for secrets, generated artifacts, cross-layer imports and accidental
Package.resolvedchurn. Use Build, Test, and Release and the routed operations pages for CloudKit deployment, StoreKit/Sandbox validation, marketing assets and forwarding benchmark measurement. Former StoreKit trial/catalog test files are removed; live purchases require Sandbox validation.
Data reminders
Current local schema is V50. Command/SFTP history is live-session memory; connection history remains durable and synchronized. Vault Host writes V2; HostGroup/SSHKey write V3; Metrics writes V2 and reads V1/V2. Keep metadata in persistence and secret values behind Keychain references. Assistant read_pane requires a captured explicit pane ID. Follow the data/Assistant guides for changes rather than using these reminders as migration or tool-policy specifications.