Keydex tells the truth about where your developer credentials live. It inventories macOS Keychain items, shell profiles, environment variables, and local config files, then shows which credentials are registered, missing, duplicated, orphaned, expiring, or still falling back to plaintext. No secret values stored. No vault. Just the map.
git clone https://github.com/jazz1x/keydex.git
cd keydex
swift run keydex --help
swift run keydex list --metadata Tests/Fixtures/metadata.json
swift run keydex reminders --metadata Tests/Fixtures/metadata.json --now 2026-07-01Or run the local gates:
make guard
make quality
make release-smokeRequires macOS 15+, Swift 6.0+, Xcode Command Line Tools,
make, andrgfor the quality scripts. Release smoke also uses macOS signing/image tools such ascodesign,plutil,hdiutil,tar, andshasum.
First-run success means:
swift run keydex --helplistslist,where,doctor,reminders, andscan.swift run keydex list --metadata Tests/Fixtures/metadata.jsonprints fixture credentials with status symbols and without secret values.swift run keydex reminders --metadata Tests/Fixtures/metadata.json --now 2026-07-01reports the expired fixture reminder.make guardpasses format, tests, app build, and forbidden-pattern checks.make qualitypasses command inventory, docs drift, loop/project contracts, CLI smoke, app accessibility/design/UX contracts, evidence scenario SSOT, accessibility/signing evidence template contracts, and menubar smoke script checks.
- Inventories credential sources - Keychain, environment variables, shell profiles, and config files become typed observations.
- Reconciles registered vs live state - metadata references are compared with live Keychain observations so missing and orphaned items become visible.
- Explains unhealthy states - doctor findings include severity, cause, and action.
- Tracks expiry metadata -
expiresAtandnotifyBeforeDaysproduce scheduled, due, and expired reminder states without storing secrets. - Keeps CLI and Mac app aligned - both surfaces are backed by the same domain labels, graph projection, and design contracts.
Keydex deliberately does not become a password manager. Secret values stay in Keychain or another explicit secret store. Keydex owns references, metadata, graph edges, and findings.
Credential data moves one way: source parsing creates observations, reconciliation builds the graph, doctor/reminder logic projects actionable state, and CLI/UI display the result.
flowchart LR
subgraph SRC [sources]
KC([macOS Keychain])
SH([shell profiles])
ENV([environment])
CFG([config files])
META([metadata JSON])
end
subgraph CORE [typed core]
OBS["typed observations"]
GRAPH["inventory graph"]
DOC["doctor findings"]
REM["expiry reminders"]
end
subgraph OUT [surfaces]
CLI([keydex CLI])
APP([SwiftUI Mac app])
end
KC --> OBS
SH --> OBS
ENV --> OBS
CFG --> OBS
META --> GRAPH
OBS --> GRAPH
GRAPH --> DOC
GRAPH --> REM
DOC --> CLI
DOC --> APP
REM --> CLI
GRAPH --> APP
- Source boundary - raw strings are parsed once into typed services, accounts, locations, and states.
- Graph boundary -
registered,missing-keychain-item,orphan,plaintext-fallback,duplicate,expiring, andexpiredare facts to show, not shortcuts to hide. - Secret boundary - metadata and fixtures never store credential values.
Metadata is safe-to-commit inventory data. It points at secret stores and records operating facts such as owner, purpose, expiry, and notification lead time.
{
"credentials": [
{
"id": "aws/jongyun",
"service": "aws",
"account": "jongyun",
"state": "registered",
"locations": [
{
"kind": "keychain",
"service": "aws",
"account": "jongyun"
}
],
"expiresAt": "2026-01-01",
"notifyBeforeDays": 30
}
]
}Rules:
expiresAtusesYYYY-MM-DD.notifyBeforeDaysrequiresexpiresAtand must be zero or greater.locations[].kind = "keychain"is reconciled against live Keychain only when--include-keychainis passed.- Metadata stores references and state, never the secret value.
CLI output follows CLI-INTERFACE.md: ◇ for command summaries
and informational states, ✓ for clean/registered, ⚠ for warnings, ■ for errors,
and bracket scopes such as [graph], [env], [shell], and [keychain] under a │
detail rail.
ANSI color is TTY-only and respects NO_COLOR.
| Command | Description |
|---|---|
swift run keydex list |
List indexed credentials. |
swift run keydex list --metadata PATH |
List metadata-backed credentials. |
swift run keydex list --metadata PATH --include-keychain |
Reconcile metadata with live Keychain observations. |
swift run keydex where SERVICE |
Show where a credential resolves from. |
swift run keydex doctor |
Diagnose inventory drift. |
swift run keydex doctor --metadata PATH --include-keychain |
Diagnose metadata vs live Keychain drift. |
swift run keydex reminders --metadata PATH |
Show configured expiry reminders. |
swift run keydex reminders --metadata PATH --now YYYY-MM-DD |
Run reminder planning at a fixed date for deterministic checks. |
swift run keydex scan env |
Scan process environment names for credential hints. |
swift run keydex scan shell |
Scan shell profile files for credential hints. |
swift run keydex scan config --path PATH |
Scan one config file for credential hints. |
swift run keydex scan keychain |
Scan live macOS Keychain references. |
swift run KeydexApp |
Launch the SwiftUI Mac app from SwiftPM. |
swift run keydex doctor \
--metadata Tests/Fixtures/metadata.json \
--include-keychainWhen live Keychain scanning is enabled:
- matched metadata-Keychain pairs become
registered - metadata references that point at nothing become
missing-keychain-item - live Keychain references with no metadata become
orphan
swift run keydex reminders \
--metadata Tests/Fixtures/metadata.json \
--now 2026-07-01Expected fixture output:
■ expired: aws/jongyun expires 2026-01-01
│ notify: 2025-12-02 (30d before)
The app is native SwiftUI. It is built as a SwiftPM executable product:
swift build --product KeydexApp
swift run KeydexAppDesign rules live in docs and scripts rather than screenshots alone:
- DESIGN-FOUNDATION.md - product and visual principles
- DESIGN-SYSTEM.md - native controls, Liquid Glass hierarchy, inventory tables/cards, and no-theater rules
- SCREEN-VALIDATION.md - screenshot and accessibility evidence
make app-design-contract- source-level design drift guardmake app-ux-flow-contract- daily inventory UX flow drift guardmake app-accessibility-contract- accessibility identifier/label guard
| Gate | What it checks |
|---|---|
make guard |
Swift format, tests, app build, forbidden patterns. |
make quality |
CLI inventory drift, state/docs drift, loop/project contracts, CLI smoke, app accessibility/design/UX flow contracts, app evidence scenario SSOT, accessibility/signing evidence template contracts, and menubar smoke script contract. |
make loop-contract |
Clean Architecture import boundaries, package dependency boundaries, and loop documentation wiring. |
make release-smoke |
Release payload, CLI smoke artifact, ad-hoc app signing, archive, checksum, and DMG verification. |
make release-signing-readiness |
Developer ID / notarization readiness evidence. |
make app-accessibility-evidence-status |
Per-scenario manual accessibility evidence progress without converting pending work into pass. |
make evidence-status |
Current local evidence status, including pending manual accessibility counts and blocked Developer ID signing prerequisite status. |
pre-commit run --all-files |
Local hook suite before commit. |
CI runs guard, quality, release-smoke, gitleaks, and trivy. The protected
main branch accepts squash merges only after required checks pass.
Keydex follows one rule first: state must not lie.
- PHILOSOPHY.md - state honesty, typed flow, restraint
- GOALS.md - product goals, non-goals, milestones, completion gates
- PRODUCT-PLAN.md - total goal answers and milestone evidence
- FEATURE-SPEC.md - feature behavior and acceptance criteria
- SWIFT-STYLE.md - Swift conventions, typed failures, and boundary rules
- CLI-INTERFACE.md - status symbols, scope labels, and color rules
- VALIDATION-SCENARIOS.md - functional validation scenarios
- SCREEN-VALIDATION.md - screenshot and accessibility evidence
- GRAPH-WORKFLOW.md - graph traversal and workflow contract
- LOOP-CONTRACT.md - quality loop, architecture boundary, and evidence contract
- ENFORCEMENT.md - guardrail policy
- VERIFICATION.md - verification surfaces
- TESTING-STRATEGY.md - test pyramid and boundary rules
Non-goals:
- Do not build a vault.
- Do not sync secrets.
- Do not copy 1Password, Bitwarden, or Apple Passwords.
- Do not invent team administration before the personal Mac workflow is true.
- Do not make copying secrets the primary UX.
The current release smoke path produces a local payload, .tar.gz, checksum, and .dmg:
make release-smokeKnown limits are explicit:
- app bundle is signed ad-hoc for smoke verification
- DMG is unsigned
- Developer ID signing and notarization remain future gates
Readiness docs:
| Symptom | Fix |
|---|---|
swift run keydex --help fails |
Check Xcode Command Line Tools and Swift version with swift --version. |
make guard fails at format |
Run /Library/Developer/CommandLineTools/usr/bin/swift-format format --recursive --in-place Package.swift Sources Tests Apps, then rerun the gate. |
scan keychain returns less than expected |
Keydex only sees Keychain items visible to the current macOS user and access policy. |
--include-keychain marks metadata as missing |
The metadata service/account pair does not match a live Keychain item. Fix the metadata reference or create the item in Keychain. |
notifyBeforeDays is rejected |
Add a valid expiresAt date first, then use a non-negative lead day count. |
make release-smoke fails on signing/image tools |
Confirm codesign, plutil, and hdiutil are available on macOS. |
keydex/
├─ Apps/
│ └─ KeydexApp/ # SwiftUI Mac app
├─ Sources/
│ ├─ KeydexCore/ # typed domain, graph, doctor, reminders
│ ├─ KeydexKeychain/ # macOS Security framework scanner
│ ├─ KeydexSources/ # env, shell, config scanners
│ ├─ KeydexStore/ # metadata store
│ └─ keydex/ # CLI entry point
├─ Tests/
│ ├─ Fixtures/ # safe metadata/config fixtures
│ ├─ KeydexCoreTests/
│ ├─ KeydexKeychainTests/
│ ├─ KeydexSourcesTests/
│ └─ KeydexStoreTests/
├─ docs/ # goals, philosophy, design, UX flow, validation, release docs
├─ scripts/ # guard, quality, release, design/accessibility contracts
├─ Package.swift
└─ Makefile