Skip to content

feat(vault): store API keys and insert text into agent and terminal panes - #840

Merged
Juliusolsson05 merged 11 commits into
mainfrom
feat/api-key-vault
Sep 8, 2026
Merged

feat(vault): store API keys and insert text into agent and terminal panes#840
Juliusolsson05 merged 11 commits into
mainfrom
feat/api-key-vault

Conversation

@Juliusolsson05

@Juliusolsson05 Juliusolsson05 commented Sep 8, 2026

Copy link
Copy Markdown
Owner

Problem

Repeatedly copying low-stakes API keys from provider dashboards interrupts prompt authoring. Prompt templates also excluded raw terminals and could not serve unsupported agent harnesses.

Delivered Behavior

  • API Key Vault command with user-created providers, named keys, notes, reveal/copy/insert, and lock-now.
  • Per-key safeStorage encryption with user-presence authentication once per app launch. Pending authentication and disk reads are revoked by lock; all open windows clear revealed caches.
  • Serialized vault mutations, version/schema/id validation, exclusive random temporary files and verified 0600 permissions. Corrupt/future indexes refuse mutation instead of being overwritten.
  • Shared text insertion: rendered panes keep editable drafts; terminal panes use their mounted xterm owner with live paste-mode, replay and visibility checks. No Enter is added. Multiline text is refused without bracketed-paste support, and terminal control bytes are rejected.
  • {{key:Provider/Key}} references resolve after ordinary variables at insertion. Source-code braces in zero-variable dynamic templates remain intact. Closing a picker or locking the vault during wake cancels delivery.

Review

One Claude and one Codex reviewer ran through the Agent Code MCP orchestration service. Both initially requested changes; all concrete blockers were fixed with regression tests, and both gave final APPROVE verdicts. Rebased onto current main; the terminal-follow integration conflict was only adjacent cleanup declarations, both retained. A final targeted run includes the newer terminal-follow tests.

Verification

  • PASS: npm run typecheck
  • PASS: 142 tests across 19 focused unit/renderer files (vault, templates, text insertion, terminal owners/follow, catalog and feature ownership)
  • PASS: desktop + remote client build (repeated successfully after the terminal-follow rebase)
  • PASS: test:contract, check:keybindings, git diff --check
  • NOT GREEN: full local suite exceeded ten minutes and reported a lazy-Markdown timeout and unrelated fixture-traceability failure. No blanket full-suite success claim; CI run 34180179423 subsequently passed the complete pinned-toolchain quality gate, including all test tiers, coverage and distributable verification.
  • Local host runs Node 25; browser tests used NODE_OPTIONS=--no-experimental-webstorage to avoid its experimental global localStorage. CI uses the repository-pinned Node version.

Security Boundary and Limitations

Encryption protects stored vault values, not text deliberately inserted downstream. Composer drafts may autosave plaintext to workspace.json; terminal scrollback/provider transcripts and the system clipboard may retain it. The UI and design disclose this rather than claiming end-to-end prompt secrecy. Names and notes are plaintext metadata. No remote/MCP secret access or export/import is added.

macOS password/Touch ID dialogs on password-only and signed-release hardware still require manual verification. Live terminal smoke tests remain manual; unsupported multiline paste fails closed rather than guessing.

Fixes #830
Fixes #831

Implementation plan for #830/#831: encrypted per-key vault store with a
touch-id once-per-run gate, renderer-owned session text delivery with
bracket-paste-without-submit over any focused PTY, and named key
references in prompt templates. First file on the branch per
conventions.

Refs #830, Refs #831
Approved design: per-key safeStorage blobs over whole-vault encryption,
promptTouchID gate in main failing closed, renderer-owned text delivery,
name-based template refs resolved pre-fill.

Refs #830, Refs #831
Per-key safeStorage blobs under STATE_DIR/key-vault with a non-secret
metadata index, mirroring the dictation apiKeyStore failure discipline:
a corrupt cipher blob costs one key, never the vault. Codec injection
keeps the file discipline unit-testable outside the packaged app.

Refs #831
Every secret-leaving path funnels through one once-per-run gate backed by
an injected promptAuth (systemPreferences.promptTouchID in production),
failing closed when the platform cannot prompt. Snapshot metadata never
carries secrets; template references resolve by provider/key name.

Refs #831
Thin ipcMain handlers delegating to VaultService, a flat preload surface,
and production wiring of promptTouchID/clipboard in the composition
root. The safeStorage codec lives in its own module so vaultStore stays
unit-testable without the packaged electron module. Secrets only cross
on gated reveal/copy/resolve-ref returns.

Refs #831
One routing point for programmatic text insertion: composer draft edits
for rendered agent panes, bracketed paste without Enter over sendInput
for plain terminals and agent terminal views, with lazy-wake before PTY
writes. Consumers: prompt templates and the api key vault.

Refs #830
Terminal panes and agent terminal views become valid template targets;
insertion bracket-pastes without submitting instead of silently doing
nothing. Composer behavior is unchanged (insert modes, no submit), and
composer-draft commands (save-as-template) stay agent-only.

Refs #830
{{key:Provider/Key}} refs resolve against the gated vault before
variable fill; missing or locked refs abort insertion with a toast
naming every failure. Names over ids keep templates readable. Adds the
session-text-delivery wake caller to the lifecycle allowlist.

Refs #831
App-surface palette command opens the vault modal: provider/key CRUD,
reveal/copy/insert actions, lock-now, and an explicit unavailable-keyring
notice. Revealed plaintext stays in ephemeral component state only and
is dropped on close.

Refs #831
The api-key-vault command is the 115th governed command; bump the
characterization arithmetic (102 - 5 retired + 18 additions). Document
the key-vault feature reference and map session-text-delivery as
infrastructure owned by the prompt-templates page.

Refs #830, Refs #831
Resolve Claude/Codex review findings with cancellation-safe secret reads, serialized vault writes, damaged-index preservation, mounted-terminal paste ownership, and post-fill template resolution. Reuse the app workspace controller and clear plaintext caches on lock across windows.

Document vault-only at-rest protection and downstream plaintext draft/transcript retention rather than claiming end-to-end prompt secrecy. Add regression coverage for races, failed writes, control bytes, source braces, and modal flows.

Refs #830, #831
@Juliusolsson05

Copy link
Copy Markdown
Owner Author

Final verification: both Agent Code MCP reviewers (one Claude, one Codex) gave APPROVE after the requested follow-up fixes. CI run 34180179423 is green: minimum-node-fixture-gate and quality-gate, including core/system/renderer tests, coverage and distributable verification. The local desktop/remote build also passed after rebasing onto the terminal-follow main. Local focused verification: 142 tests across 19 files, typecheck, test contract, keybindings and diff checks passed. The earlier full local Node 25 run remains recorded as incomplete; CI on the pinned toolchain is the authoritative passing suite. Manual real-password/Touch ID hardware checks remain a disclosed limitation. Proceeding under the explicit user instruction to review and then merge.

@Juliusolsson05
Juliusolsson05 merged commit a019233 into main Sep 8, 2026
2 checks passed
@Juliusolsson05
Juliusolsson05 deleted the feat/api-key-vault branch September 8, 2026 02:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

1 participant