28 KiB
type, title, description, tags, sources, generated, verified
| type | title | description | tags | sources | generated | verified | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
| 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/local typography, native surface identity | Ghostty Terminal Integration; Termind overrides separate iOS hooks and native macOS menus. Run MobileTerminalUploadMenuTests / TerminalContextMenuTests; package pointer/selection internals need the resolved upstream source/tests. App-owned keyword highlighting is retired in V52. |
| Ghostty dependency/API updates | Ghostty Dependency Updates; align the direct Lakr233/libghostty-spm requirement and resolved pin, then validate both host adapters. No local Ghostty maintenance submodule/fork release or override workspace remains. |
| 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. |
| Asset production, scan capture, frameit, Figma and App Store exports | Marketing Assets and App Icons is the canonical workflow: exact native iPhone Pro/Duo/iPad/Mac pixels and postures, licensed frame templates/masks, 72 four-platform JPG boards, current website compositions and SSH-first submodule publication. Use plan:true and Ruby checks without opening app windows. |
| 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 allowsSwiftUIand contains existing conditional platform helpers; its selected source-pattern/import/construction rules reject app-target, storage, concrete-service and commerce coupling. Those checks are not a blanket compiler-enforced prohibition on every platform symbol. 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.19.0underupToNextMajorVersion; 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 comes directly from
Lakr233/libghostty-spm, with an up-to-next-major requirement and resolved version2.2.2026100501at7199bd7aa3c32d0a5edcab7fe87b3c1e76f76de9. There is no local Ghostty maintenance submodule or Termind native-binary release prerequisite. Align requirement/resolution and validate both adapters; package internals require separate review. See Ghostty Dependency Updates.
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. Workspace/Transfers destinations and Connection Picker/Batch Startup sheets each use mutually exclusive optional enums with derived accessors. - 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.
- Recently closed: each app owns a device-local 15-record store, retaining eligible Workspace/window metadata across launch and grouped-window selection. Closing disconnects transports; a move does not add close history and preserves live sessions. Restore consumes records only after a viable destination is available. See Native App Responsibilities; do not confuse this with synchronized connection history or cold descriptor restoration.
- 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. Resize temporarily suspends engine search without clearing UI state, and resumes only a still-presented nonempty latest query. 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>.MobileAdaptiveLayoutTestsgates its native-window cases individually and leaves pure width logic enabled;MobileMetricsJourneyTestshas a suite-level key-window gate. Use narrow nonparallel opt-in runs for those UIKit fixtures. Check each annotation—some older connection-picker toolbar fixtures remain ungated rather than assuming the policy covers every window-creating case. 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. - Website/asset work: initialize
com.akinokaede.termindonly when needed;(cd com.akinokaede.termind && npm ci && npm run build), then inspect/,/zh-hans/,/zh-hant/and the/zh/redirect. Source assets live in the independent submodule; commit/push reviewed assets via SSH before updating the parent gitlink, keeping the public HTTPS clone URL. - Screenshot tooling stays app-owned: fastlane scan captures native sources, frameit composes staged copies with licensed templates, and Figma final artwork/website frames are distinct derived deliverables. Do not invoke capture just to validate documentation.
- 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 V52: V51 adds Snippet colors over a frozen historical model, then V52 removes retired keyword-highlighting preferences. SnippetColorTests verifies V50 upgrade/color reopen; RetiredTerminalHighlightingTests verifies V46/V51 cleanup, inactive-upload retirement and malformed legacy-record isolation. Command/SFTP history is live-session memory; connection history remains durable and synchronized. Vault Host/Snippet write 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.