Imported from CiTroNaK/Quick-Access-for-Pass (
AGENTS.md). Install upstream withnpx skills add CiTroNaK/Quick-Access-for-Pass. Copyright stays with the author.
AGENTS.md
This file provides guidance to coding agents and other automated contributors working in this repository.
Build & Test
# Build (Release)
make build
# Build + install to /Applications + launch
make install
# Build (Debug, for development)
xcodebuild -scheme "Quick Access for Pass" -configuration Debug build
# Run tests
xcodebuild -scheme "Quick Access for Pass" test
# Run a single test suite (Swift Testing)
xcodebuild -scheme "Quick Access for Pass" test -only-testing:"Quick Access for Pass Tests/SearchServiceTests"
Tests use Swift Testing (@Suite, @Test), not XCTest.
CI
.github/workflows/ci.yml— runs tests on push tomainand pull requests targetingmain(macos-26).github/workflows/release.yml— triggered byv*tag push: build, sign, notarize, package (DMG + ZIP), publish GitHub Release, update Homebrew cask
Architecture Overview
Quick Access for Pass is a macOS menu-bar app that provides quick access to Proton Pass secrets via pass-cli, plus two optional local authorization proxies:
- SSH Agent Proxy — gates SSH key signing behind Touch ID
- Run Proxy — gates command execution with secret injection behind Touch ID via the bundled
qa-runhelper
AppDelegate is intentionally a thin composition root. Cross-cutting orchestration lives in three main @MainActor coordinators:
SyncCoordinator— background sync timer, refresh, cache resetSSHProxyCoordinator— SSH proxy + daemon lifecycle, vault filtering, health recoveryRunProxyCoordinator— Run proxy lifecycle, secret resolution, auth decisions, health recovery
A separate HealthCheckCoordinator owns the probe schedule for Pass CLI, SSH, and Run.
Concurrency Model
Swift 6 strict concurrency is enforced throughout. Preserve actor and @MainActor boundaries.
- Actors for shared mutable state:
PassCLIService,SSHAgentProxy,SSHAgentDaemonManager,RunProxy @MainActorfor UI and orchestration:AppDelegate,QuickAccessViewModel,ClipboardManager,HotkeyManager,SyncCoordinator,SSHProxyCoordinator,RunProxyCoordinator, auth window controllers, health stores/coordinator- All models are
Sendableand intentionally cross actor boundaries as value types CheckedContinuationbridges blocking process/socket work into async/await inCLIRunner,SSHAgentProxy, andRunProxynonisolated(unsafe)is used sparingly and should stay justified with comments
If you add shared mutable state, prefer an actor or isolate it to @MainActor instead of weakening the model.
Main Data Flows
Quick Access panel
- Global Carbon hotkey →
AppDelegate.togglePanel()→ floatingNSPanel - Search query → debounced in
QuickAccessViewModel SearchServiceruns encrypted SQLite FTS5 query + usage ranking- Selected action fetches secret on demand through
PassCLIService+CLIRunner ClipboardManagercopies to pasteboard withorg.nspasteboard.ConcealedTypeand auto-clear- Detail rows can also be shown in Large Type through
LargeTypeWindowController
SSH Agent Proxy
SSHAgentProxy listens on ~/.ssh/quick-access-agent.sock and proxies to the Pass CLI daemon at ~/.ssh/proton-pass-agent.sock.
Key behaviors:
REQUEST_IDENTITIESis forwarded through transparentlySIGN_REQUESTis interceptedProcessIdentifierresolves the requesting PID, app, host, and BatchMode metadata- BatchMode probes are denied by default and handled through
SSHBatchModeNotifier, with decisions persisted per fingerprint + host SSHAuthWindowControllerapplies:- a session cache (3 seconds, in memory) keyed by app + fingerprint
- a persistent cache keyed by app + command + fingerprint
- Failures feed the shared health/auto-heal path
Run Proxy
RunProxy listens on ~/.local/share/quick-access/run.sock and authorizes command execution through the bundled qa-run helper.
Key behaviors:
qa-runsends a length-prefixed JSONRunProxyRequestPeerVerifierrejects unverified peers — only signed apps and the trustedqa-runhelper are acceptedRunProxyCoordinatorresolvespass://URIs throughpass-cli run --env-file ... -- qa-env-export ...- The bundled
qa-env-exporthelper writes only approved environment variables to a private FIFO channel, avoiding stdout/stderr masking and local secret persistence - Resolved secrets are cached in memory per profile using the profile
cacheDuration RunAuthWindowControllerauthorizes by app + subcommand + profile- Allowed responses return environment variables for client-side injection
Health Checks & Recovery
A shared ProxyHealthStore and PassCLIStatusStore drive the status rows in Settings and the menu-bar health badge.
HealthCheckCoordinatorprobes Pass CLI, SSH, and Run every 30 seconds- SSH health uses
SSHProxyProbe.listIdentities(at:) - Run health uses
RunProxyProbe.ping(at:) - Pass CLI login/version/identity uses
PassCLISanityCheck - Recovery uses
AutoHealStateMachinewith a two-strike policy, 120-second cooldown, and wake-aware behavior - Wake handling is coordinated via
WakeObserver/WakeHandler
Keep the dependency direction one-way: HealthCheckCoordinator owns probe scheduling and dispatches to proxy coordinators; proxy coordinators must not own the health coordinator.
Accessibility Rules
Views follow VoiceOver and Voice Control patterns throughout:
- Icon-only buttons must have
.accessibilityLabel - Decorative images next to text must use
.accessibilityHidden(true) - Selection state uses
.accessibilityAddTraits(.isSelected), not label text - Async state changes should post
AccessibilityNotification.Announcement - Focus recovery after auth failure uses
@AccessibilityFocusState - Buttons with visible text should generally not override
.accessibilityLabel - Status indicators must not rely on color alone
Security Invariants
These are core constraints, not implementation details:
- No secrets in the database — only metadata is persisted locally
- Secrets are never persisted locally; sync may temporarily load full item content from
pass-clito derive metadata, and selected actions fetch current values on demand - Database encryption uses GRDB/SQLCipher with a 256-bit passphrase from Keychain (
kSecAttrAccessibleWhenUnlockedThisDeviceOnly) - Socket permissions are strict (
0600), and socket directories are owner-only - Run proxy peer verification is mandatory — reject unverified local clients
- FTS5 queries must remain sanitized before search execution
- Clipboard concealment should be preserved when copying secrets
Database Schema
DatabaseManager currently defines 6 migrations:
- v1
vaultsitemsitems_ft(FTS5)sshAuthDecisionssshBatchModeDecisionswith fingerprint + host keying
- v2
runProfilesrunProfileEnvMappingsrunAuthDecisions
- v3
- adds
cacheDurationtorunProfiles
- adds
- v4
- adds
fieldKeysJSONtoitems
- adds
- v5
- clears remembered decisions and adds app identity metadata (
appIdentifier,appTeamID) to remembered decision tables
- clears remembered decisions and adds app identity metadata (
- v6
- makes
expiresAtnullable onsshAuthDecisionsandrunAuthDecisions(table-rewrite migration) to represent permanent (Forever) decisions
- makes
- v7
- adds
shareIdtovaultsso stablevault_idcan be used as the local identity while current session-specificshare_idis still available for Pass CLI commands
- adds
When changing schema:
- add a new migration block
- preserve existing migration history
- update docs/tests that describe the schema
- prefer additive migrations over destructive changes unless explicitly intended
Project Layout
Quick Access for Pass/
├── AGENTS.md
├── CLAUDE.md
├── CONTRIBUTING.md
├── README.md
├── SECURITY.md
├── docs/
├── Quick Access for Pass/
│ ├── App.swift
│ ├── Environment/
│ ├── Extensions/
│ ├── Models/
│ ├── Resources/
│ ├── Services/
│ │ ├── Concurrency/
│ │ ├── Health/
│ │ ├── Logging/
│ │ ├── RunProxy/
│ │ ├── SSHAgent/
│ │ └── Security/
│ ├── ViewModels/
│ └── Views/
├── Quick Access for Pass Tests/
├── qa-run/
└── qa-env-export/
Development Guidelines
- Keep
AppDelegatethin; put lifecycle logic into coordinators/services - Prefer small focused files over expanding mixed-responsibility types
- Match existing naming and file organization patterns
- Use Swift Testing for new tests
- Favor in-memory DB tests for persistence logic
- Preserve strict concurrency correctness; do not paper over isolation errors
- Keep docs in sync when architecture, schema, settings, or security guarantees change
Documentation Map
README.md— user-facing overview and setupCONTRIBUTING.md— contribution workflow and contributor expectationsSECURITY.md— vulnerability reporting + security posture summary
If a change affects agent instructions, contributor workflow, user setup, security posture, or architecture, update the relevant docs in the same change.