No description
  • Swift 41.4%
  • Assembly 16.9%
  • C 12.3%
  • C++ 11%
  • Shell 7.8%
  • Other 10.3%
Find a file
Founder 41286f4fb5
All checks were successful
Release: If Needed / Check (Release Needed) (push) Successful in 5s
Deploy: API / Deploy (API) (push) Successful in 2m54s
Deploy: Web / Deploy (Web) (push) Successful in 6m54s
release: stop re-dispatching known-failing builds every 30 minutes
release-if-needed ran on a */30 cron and dispatched a full multi-platform
release build (macOS 12x28 + Linux + 16cpu + Bazel cache instances) whenever
its gate said a release was needed. That gate compares app inputs against the
last successful build tag, so once build-release started failing the tag never
advanced, every tick answered 'needed', and the same doomed build was
re-dispatched indefinitely -- burning Namespace capacity continuously. The
existing guard only skipped when a build was currently active, so a failed
build simply freed the slot for the next tick to refill.

- Back the schedule off to every 6 hours; pushes to main still trigger
  immediately, so the cron is only a safety net.
- Skip dispatch when a release build was already attempted for this exact
  commit, not merely when one is still running. Terminal (failed) runs now
  count, so a broken build waits for a new commit instead of retrying forever.
  workflow_dispatch still forces a rebuild for deliberate retries.

Scripts/forgejo-active-release-runs-via-host.sh gains
KEYSTORE_RELEASE_INCLUDE_TERMINAL=1 to answer 'was one attempted?' alongside
the existing 'is one running?'.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-07-25 20:03:50 -07:00
.agents/plugins Package key.store meta-MCP as Codex plugin 2026-05-03 02:37:46 -07:00
.codex key.store: rebase on key.store-9 and integrate codex + Sparkle + F-Droid 2026-01-19 05:52:44 -08:00
.forgejo release: stop re-dispatching known-failing builds every 30 minutes 2026-07-25 20:03:50 -07:00
Android key.store: add JMAP, WebDAV, and push support 2026-06-18 22:34:26 -07:00
API Implement JMAP push fetch and app-group persistence 2026-06-27 23:10:34 -07:00
Apple Implement JMAP push fetch and app-group persistence 2026-06-27 23:10:34 -07:00
bazel Implement JMAP push fetch and app-group persistence 2026-06-27 23:10:34 -07:00
config Add OpenBao runtime secret migration 2026-06-13 14:56:32 -07:00
docs release: fetch Windows signing certificate material 2026-06-14 01:37:38 -07:00
evolution flake: disable Fil-C by default until horizontal build capacity (KSE-0184) 2026-07-19 20:18:06 -07:00
finances key.store: repair android, linux swift, and finance workflow inputs 2026-02-20 20:10:20 -08:00
Firmware/Nordic/MDBT50Q-CX firmware: add Nordic passkey RTOS image target 2026-06-14 01:17:19 -07:00
fleet Add Authentik-backed mail stack 2026-05-17 04:36:31 -07:00
forgejo Align secret tiers and email tooling 2025-12-24 18:09:27 -08:00
gradle Add key.store Android account pairing 2026-05-16 23:55:09 -07:00
infra tofu: use public Garage endpoint for state (jobs run in containers) 2026-07-25 20:01:10 -07:00
Linux/App fix: Loki plaintext Garage S3 + rclone flatpak install glob 2026-07-18 01:11:13 -07:00
nix release: wire full-surface artifacts 2026-06-13 18:43:48 -07:00
nixos garage: surface missing GCS archive + add sovereign OpenTofu state bucket 2026-07-25 15:50:07 -07:00
notes Fill business metadata and wire Fava decrypt 2026-01-20 01:32:53 -08:00
ops/namespace infra: avoid source churn in namespace images 2026-06-13 20:05:41 -07:00
org evolution: record Namespace residencies (KSE-0181) and OpenBao revival (KSE-0182) 2026-07-17 22:26:12 -07:00
Packages Implement JMAP push fetch and app-group persistence 2026-06-27 23:10:34 -07:00
patches Fix Apple rcodesign entitlements 2026-05-26 23:48:54 -07:00
plugins/key-store-forge-control-plane Remove Quo-facing agent interfaces 2026-05-23 15:38:42 -07:00
Protos Implement key.store local agent management 2026-05-26 04:12:06 -07:00
records Update nix cache, identities, and governance terms 2026-02-01 01:29:14 -08:00
Redis Move API edge coordination to Fly Redis 2026-05-10 16:06:45 -07:00
Scripts release: stop re-dispatching known-failing builds every 30 minutes 2026-07-25 20:03:50 -07:00
secrets api-worker: split node and worker roles 2026-06-18 22:34:26 -07:00
services observability: KSE-0183 phase A — span metrics, health/API/CI dashboards 2026-07-18 01:43:16 -07:00
skills Remove Quo-facing agent interfaces 2026-05-23 15:38:42 -07:00
store-metadata Wire Lately App Store release and cloud signing imports 2026-05-24 04:43:30 -07:00
ThirdParty/sqlite Add SQLite core and cross-platform unlock models 2026-06-13 14:59:50 -07:00
Tools/LibraryMockSnapshot/Sources/LibraryMockSnapshot Remove first-party Swift package builds 2026-06-13 15:28:05 -07:00
Web key.store: add JMAP, WebDAV, and push support 2026-06-18 22:34:26 -07:00
Windows/App Remove first-party Swift package builds 2026-06-13 15:28:05 -07:00
.bazelignore Add SQLite core and cross-platform unlock models 2026-06-13 14:59:50 -07:00
.bazelrc release: restore apple deployment floors 2026-06-13 20:42:37 -07:00
.bazelversion Refine Nix release impact lanes 2026-05-24 22:23:29 -07:00
.editorconfig Bring Android library screen to typography system 2026-05-03 02:28:29 -07:00
.envrc key.store web: product branding page 2026-02-06 18:44:55 -08:00
.git_allowed_signers Update nix cache, identities, and governance terms 2026-02-01 01:29:14 -08:00
.gitattributes key.store: store web fonts directly in git 2026-04-05 17:17:30 -07:00
.gitignore android: build native swift hardware bridge 2026-06-14 00:45:00 -07:00
.gitmodules Add Sparkle + F-Droid release infrastructure 2026-01-17 22:41:34 -08:00
.lfsconfig key.store: let Git LFS use remote URL 2026-02-07 18:35:58 -08:00
.swiftlint.yml Prefer Swift 6.3 for Apple release tooling 2026-05-23 00:03:39 -07:00
AGENTS.md Remove first-party Swift package builds 2026-06-13 15:28:05 -07:00
biome.json Update Biome config and fix Linux workflow 2025-11-27 02:21:06 -05:00
BUILD.bazel Implement JMAP push fetch and app-group persistence 2026-06-27 23:10:34 -07:00
build.gradle.kts remove unused Android KSP plugin 2026-05-11 03:45:33 -07:00
bun.lock Update web Bun lock for OHTTP analytics 2026-05-10 17:23:08 -07:00
bunfig.toml wip 2025-11-27 01:24:26 -05:00
CODEOWNERS Gate app releases with Nix impact policy 2026-05-24 22:07:27 -07:00
CONSTITUTION.md Add key.store constitution 2025-12-24 18:09:26 -08:00
CONTRIBUTORS.md key.store: finish Huly cutover and retire Plane ops 2026-03-09 00:34:13 -07:00
contributors.nix Avoid security mailbox principal conflict 2026-05-17 13:05:12 -07:00
flake.lock Move dispatch services into pinned repos 2026-06-13 14:57:57 -07:00
flake.nix flake: disable Fil-C by default until horizontal build capacity (KSE-0184) 2026-07-19 20:18:06 -07:00
gradle.properties key.store: fix blob endpoint + increase gradle heap for android release 2026-02-08 18:37:54 -08:00
gradlew Add Android app scaffolding and Swift bridge 2025-12-21 10:50:35 -08:00
gradlew.bat Add Android app scaffolding and Swift bridge 2025-12-21 10:50:35 -08:00
Makefile Add key.store Flatpak testing repo 2026-06-13 14:54:34 -07:00
MODULE.bazel Add SQLite core and cross-platform unlock models 2026-06-13 14:59:50 -07:00
MODULE.bazel.lock Add SQLite core and cross-platform unlock models 2026-06-13 14:59:50 -07:00
package.json key.store web: product branding page 2026-02-06 18:44:55 -08:00
README.md key.store: remove stale Huly and Plane operator references 2026-03-09 02:53:24 -07:00
secrets.nix fix: repair apple workflows and secrets 2025-12-08 01:25:27 -08:00
settings.gradle.kts Add Android app scaffolding and Swift bridge 2025-12-21 10:50:35 -08:00

key.store

key.store is an autonomous, open-source password manager that treats its codebase, build farm, and infrastructure as a single sovereign kernel. The long-term goal—spelled out in the recorded genesis message and transcribed in genesis.txt—is to let a self-hosted forge nurture a “crystalline artifact”: a Swift-based password manager with transparent provenance, reproducible builds, and agents that can evolve it safely. The intent is codified in the key.store constitution; every plan or proposal should trace back to it.

Genesis at a Glance

  • Own the forge. We use Nix to define everything from the application stack to the forge OS image so the project can build and host itself on Hetzner (or any sovereign compute with dispatchable runners).
  • Treat infrastructure as part of the artifact. Secrets, DNS, TLS, runners, and cron-based automation live in-repo so the forge can bootstrap, repair, and extend itself.
  • Grow via agents, not commits alone. Scheduled jobs can spawn agents that open PRs, review each others work, and keep the system coherent without depending on centralized SaaS for CI/CD.
  • Capture context for future models. Decisions, prompts, and architecture notes must live beside the code so the next generation of agents (and humans) can read them.

If you want the full stream-of-consciousness origin story, start with genesis.m4a (22 minutes) or the generated captions in genesis.srt.

Mission

  1. Deliver a production-quality, cross-platform password manager written in Swift, with first-class Apple, Web, and backend experiences.
  2. Maintain a self-hosted forge that can provision its own infrastructure, secrets, and runners via Nix, Hetzner, and Cloudflare DNS automation.
  3. Iterate safely by letting autonomous agents do the rote work while humans (or higher-level agents) set direction through the key.store evolution process.

System Pillars

  • Crystalline Artifact: The password manager plus every prompt, script, and policy required to rebuild it. Nothing critical should live outside the repository (or its declared state stores).
  • Sovereign Kernel: A minimal pool of trusted machines that can bootstrap new services, rotate credentials, and recover after failure using only the contents of this repo.
  • Autonomous Evolution: Cron jobs and runners schedule agents that implement and review key.store evolution proposals, ensuring growth is intentional rather than chaotic.

Repository Tour

  • API/ — Rust services and workers that back the product experience.
  • Apple/ — Native Swift code, likely the home of the flagship client.
  • Web/ — Web front-end assets and tooling.
  • nixos/ — Hosts, modules, and images used to spin up the forge and related services.
  • Packages/ & Scripts/ — Shared tooling, Swift packages, agent helpers, and secret-management scripts.
  • Makefile — Shortcuts for nix build, nix develop, and agenix-backed secret handling.

Bootstrapping the Stalwart directory

Stalwart expects a SQL directory with accounts, emails, and group_members tables (the schema in tests/src/directory/mod.rs mirrors what we use). Two helper scripts keep those tables aligned with the constitution:

# emit bootstrap.sql based on contributors.nix
python Scripts/generate-stalwart-sql.py > bootstrap.sql

# or stream it straight into psql (DATABASE_URL is optional if you source config/databases/stalwart-socket.env)
nix develop .#tools --command Scripts/apply-stalwart-sql.sh bootstrap.sql

# shorthand: auto-generate SQL and run it
nix develop .#tools --command Scripts/apply-stalwart-sql.sh

apply-stalwart-sql.sh reads config/databases/stalwart-socket.env (or respects DATABASE_URL/STALWART_DATABASE_URL) and runs the SQL with psql -v ON_ERROR_STOP=1, so rerunning it is idempotent. The generator now reads each secrets/identity/<slug>-password.age, hashes it (SHA-512 crypt), and stores the result in accounts.secret, so Stalwarts internal directory always mirrors the canonical password list without ever writing plaintext into SQL output (run it on a host whose Age identity is in forgeAutomation).

Bootstrapping Forgejo accounts

Forgejo uses the same identity hierarchy for admin scope (governance), CI/service accounts (forgeAutomation), etc. The companion scripts follow the same pattern:

# review the generated user/email upserts
python Scripts/generate-forgejo-sql.py > forgejo.sql

# or stream directly (DATABASE_URL/forge secret is auto-resolved)
nix develop .#tools --command Scripts/apply-forgejo-sql.sh forgejo.sql
# shorthand auto-generate + apply
nix develop .#tools --command Scripts/apply-forgejo-sql.sh

The SQL upserts "user" rows for every contributor (governance identities become admins) and seeds the email_address table so Forgejo trusts their commit addresses. SSH keys still live in config/git-identities/ and are managed via Scripts/git-identity.sh per KSE-0001.

Getting Started

# drop into the reproducible dev shell
nix develop

# list or edit encrypted secrets (requires access)
make secrets-list
make secret name=cloudflare/api-token

# build everything described by flake.nix
nix build

Agents typically execute the same flows inside runners; humans can follow the steps above to reproduce their environment locally.

Commit Signing

All commits must be SSH-signed per KSE-0001. Use Scripts/git-identity.sh list to see the available identities, Scripts/git-identity.sh use <identity> (for example, agent) to configure your local git settings, and Scripts/git-identity.sh generate <identity> if you are onboarding a new signer. Public keys live in config/git-identities/, encrypted private keys now live under secrets/identity/<identity>-ssh.age, and .git_allowed_signers is regenerated by Scripts/git-identity.sh refresh. For OpenPGP/WKD publishing of identity@key.store addresses, follow docs/pgp-wkd.md and the helper script Scripts/wkd-publish.sh; the .well-known payload ships as the nix build .#wkd derivation and is bundled into the static web assets served by the API frontend. The canonical roster (with scopes, hardware key notes, and Age recipients) lives in contributors.nix; run make contributors after editing it so CONTRIBUTORS.md and downstream tooling stay in sync.

SSH defaults in the dev shell are now repo-local (config/ssh/config + .home/ssh/*) so scripts and Git do not depend on user-global ~/.ssh/config. See docs/ssh-devshell.md for the 1Password-agent flow and Codex shell behavior.

Run Scripts/generate-allowed-signers.sh whenever you add/remove identities; review the resulting .git_allowed_signers diff before committing so the signer roster always matches config/git-identities/*.pub and the WKD tree.

Scripts/git-identity.sh generate --scope <tier> <identity> now writes three assets: the SSH key (secrets/identity/<identity>-ssh.age), an Age-encrypted OpenPGP backup (secrets/identity/<identity>-openpgp.age via Scripts/export-openpgp-secret.sh), and an encrypted SMTP password (secrets/forwardemail/<identity>-smtp.age via Scripts/forwardemail-alias.sh). Use Scripts/export-openpgp-secret.sh and Scripts/forwardemail-alias.sh manually whenever you rotate subkeys so the bundles stay current.

Universal plaintext login/password pairs (used by Stalwart, Forgejo OIDC bootstrap, and Redmine bootstrap) live in secrets/identity/<identity>-password.age. Generate or rotate them with make identity-passwords (optionally slug=<identity> or ROTATE=1); the helper script shells out to openssl rand -base64 32 so every identity gets a strong random secret without manual copy/paste. See services/mail/stalwart-auth.md for the Stalwart-side OIDC runbook (client registration script, secret layout, and Forgejo wiring details).

Governance & Evolution

key.store uses a lightweight process inspired by Swift Evolution to capture architectural intent, major feature work, and agent-safe instructions. Every substantive change should be anchored by a proposal (KSE-XXXX) described in evolution/README.md and must cite the sections of the constitution it advances or depends on. Proposals live in evolution/proposals/ and act as durable context for future contributors.

Resources

When you update any of these resources (for example, regenerating the transcript with a newer model), note the change in the commit message so downstream agents know which context to trust.