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

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.

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