From 105234cb57457f60db0c8e5c67e0653bb11f62bf Mon Sep 17 00:00:00 2001 From: NNIIOVO Date: Thu, 5 Nov 2026 22:41:34 -0600 Subject: [PATCH] docs: accept ADR-0012, agents store and manage keys without seeing them The owner changed the goal: Claude, ChatGPT or Codex should store and manage keys safely, never see or use them. An agent asks; the app opens its own window and the owner types the value there; the agent gets back only "saved". It manages only the Notes it added (any Kind, any chain: EVM, Solana, Bitcoin), with five requests: store, list, edit details, ask to replace, ask to delete. Address, chain, website and service edits need the owner's confirmation; deletes need the Master Password. Nothing signs. Docs only: nothing is built. Adds ADR-0012, marks ADR-0011 (Chat Wallet signing) deferred, amends ADR-0007 and the ADR-0004 note, adds the Agent-added Note glossary term, replaces the AGENTS.md Chat Wallet rule, and updates one line each in the README, PRODUCT.md and the guide. Co-Authored-By: Claude Opus 5.5 --- AGENTS.md | 2 +- CONTEXT.md | 8 ++- PRODUCT.md | 2 +- README.md | 2 +- .../0004-wallet-kinds-under-a-separate-key.md | 2 +- ...007-agents-use-separate-restricted-keys.md | 4 +- docs/adr/0011-chat-wallets.md | 2 +- docs/adr/0012-agents-store-and-manage-keys.md | 62 +++++++++++++++++++ docs/guide.md | 2 +- 9 files changed, 77 insertions(+), 9 deletions(-) create mode 100644 docs/adr/0012-agents-store-and-manage-keys.md diff --git a/AGENTS.md b/AGENTS.md index f3a16e2..7f6d865 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -11,7 +11,7 @@ A personal app for storing secrets, encrypted and saved only on this computer. - Never add network access to the Vault core or WebView: no HTTP clients, updaters, telemetry, crash reporters or analytics (ADR-0001). The only approved exception is the optional Agent Companion helper (ADR-0009): a separately sandboxed XPC service that makes only the companion's fixed OpenAI request. Never widen it, give it Vault access, or add networking anywhere else. Its source is in `companion/`: never import that folder from `src/`, `src-tauri/src/` or `crates/` (ADR-0010). - Keys and decrypted Notes live only in the Rust core; the WebView receives one Hidden Field at a time (ADR-0003). The Agent Companion helper may hold one separately created Agent Key, never a Vault value (ADR-0009). - Never pass Vault content, Note metadata, Note keys, Wallet Kinds, the Master Password or the Recovery Key to the Agent Companion, and never forward helper output, provider errors, keys or tokens to the WebView (ADR-0009). -- Chat Wallets (ADR-0011, accepted, not built) are the only route by which an agent may ask the app to use a key. Keep that route to its six requests, only from the separate agent account, behind a grant. It returns no key, ordinary Note, metadata, Wallet Kind, Master Password or Recovery Key, signs only plain Base transfers after Touch ID and the Master Password, and shares nothing with `companion/`. Never let a Seed Phrase or Private Key sign or become a Chat Wallet, and never let the route change limits or recipients. +- The agent key route (ADR-0012, accepted, not built) lets an agent store keys and manage the Notes it added, and nothing more. Keep it to its five requests, only from the separate agent account, behind a grant. Values are typed by the owner into the app's own native window, never passed through the agent. It returns no value, no Note it didn't add, no Master Password or Recovery Key, and never signs. Address, chain, website and service edits need the owner's confirmation, and deletes need the Master Password. It shares nothing with `companion/`. Chat Wallets and signing (ADR-0011) are deferred: don't build them. - Add a dependency only when it's clearly needed, pin its exact version, and say why in the PR/issue. ## Verify diff --git a/CONTEXT.md b/CONTEXT.md index 771bebd..f2f4745 100644 --- a/CONTEXT.md +++ b/CONTEXT.md @@ -66,8 +66,12 @@ _Avoid_: sharing an owner key, agent access to the Vault The optional helper inside the app, with its own macOS sandbox, that lets the agent tools in one separate Mac account use one fixed OpenAI text operation with an **Agent Key**. It can't open the **Vault**, is off unless the owner starts it, and stops at the end of its one-hour grant, on Stop, whenever the app is **Locked**, on sleep and when the app quits ([ADR-0009](docs/adr/0009-optional-agent-companion-helper.md)). _Avoid_: agent bridge (that's the agent account's side), Vault connector, plugin +**Agent-added Note**: +A **Note** an AI agent asked the app to store, marked "added by an agent" (accepted, not built). The owner typed its value into the app's own window; the agent never saw it. The agent can list it, edit its details and ask to replace or delete it, but never read or use its value, and it can't see or touch any other **Note**. Removing the mark takes it out of the agent's reach ([ADR-0012](docs/adr/0012-agents-store-and-manage-keys.md)). +_Avoid_: agent key (that's an **Agent Key**), agent Note, managed key + **Chat Wallet**: -A planned **Kind** (accepted, not built) holding one private key for one Base account, made only for agent use and kept under its own key, apart from **Wallet Kinds**. It should sit at an address holding only a small amount. An agent in the separate agent account can ask the app to list, create, import, rename or send from one, but never sees the key. Every send must be a plain transfer within the owner's limits, to a listed recipient, approved with Touch ID and the **Master Password**. The app signs the transaction and the agent sends it ([ADR-0011](docs/adr/0011-chat-wallets.md)). +Deferred (ADR-0011, not built): a key apart from the **Notes**, holding one private key for one Base account, made only for agent use and kept under its own key, apart from **Wallet Kinds**. It should sit at an address holding only a small amount. An agent in the separate agent account can ask the app to list, create, import, rename or send from one, but never sees the key. Every send must be a plain transfer within the owner's limits, to a listed recipient, approved with Touch ID and the **Master Password**. The app signs the transaction and the agent sends it ([ADR-0011](docs/adr/0011-chat-wallets.md)). _Avoid_: agent wallet, hot wallet, using a **Seed Phrase** or **Private Key** from chat ### Screen privacy @@ -132,7 +136,7 @@ _Avoid_: pinned, bookmarked, starred item ## Relationships - The owner has one **Vault**; it moves between computers only when the owner copies the file by hand. -- The app gives AI agents no interface to the **Vault**, its **Notes**, their metadata, **Backups**, **Safety Copies** or the **Emergency Reader**, and agents are told never to use them. That limits the app, not the computer: what keeps an agent running in the owner's own Mac account away from these files is the owner's setup. The **Master Password**, **Recovery Key** and **Wallet Kinds** never take part in agent work. +- The app gives AI agents no interface to the **Vault**, its **Notes**, their metadata, **Backups**, **Safety Copies** or the **Emergency Reader**, and agents are told never to use them. (Once ADR-0012 is built, the one exception is **Agent-added Notes**: their names and visible details, never their values.) That limits the app, not the computer: what keeps an agent running in the owner's own Mac account away from these files is the owner's setup. The **Master Password**, **Recovery Key** and **Wallet Kinds** never take part in agent work. - The **Agent Companion** is the only **Agent Key** integration inside the app; it runs apart from the **Vault** in its own sandbox and never receives Vault content. Any other **Agent Key** integration is separate from this app. Hiding the key still lets an agent perform every operation its provider scope permits, within its enforced limits; only the owner can independently approve scope or limit changes ([ADR-0007](docs/adr/0007-agents-use-separate-restricted-keys.md)). - Results from an external agent's allowed service actions may leave this computer, including for a cloud model provider; no Vault content or metadata may enter that route. - Moving a **Vault** to the other computer means opening a **Backup** there. There is no separate "export" or "sync" concept. diff --git a/PRODUCT.md b/PRODUCT.md index 6cb5183..8b88751 100644 --- a/PRODUCT.md +++ b/PRODUCT.md @@ -10,7 +10,7 @@ An individual owner keeping personal secrets on their own Mac or Windows compute The optional Agent Companion serves a separate workflow: an owner gives tools in a distinct standard Mac account one restricted OpenAI text operation using a separately created Agent Key. An agent has no app interface to the Vault. The first private Agent Key entry flow is Mac only. -Planned, accepted, not built: Chat Wallets ([ADR-0011](docs/adr/0011-chat-wallets.md)). The owner stores and manages separate small-amount keys by chatting with an agent. The agent asks, the app shows what will happen in its own native panel, and the owner approves every send with Touch ID and the Master Password. The agent never sees a key. +Planned, accepted, not built: agents that store and manage keys ([ADR-0012](docs/adr/0012-agents-store-and-manage-keys.md)). From Claude or Codex, the owner asks for a key to be stored; the app opens its own native window, and the owner types the value there. The agent gets back only "saved", can list and edit the details of only the keys it added, and never sees or uses a value. Replacing a value or deleting a key happens in the app's own window too. ## Product Purpose diff --git a/README.md b/README.md index 638cedf..7bb9b9f 100644 --- a/README.md +++ b/README.md @@ -64,7 +64,7 @@ These are instructions for AI coding agents working in this repository, in [AGEN - Never open, list, copy, decrypt, delete, move, overwrite or clean a real Vault, Backup or Safety Copy, or the app's data folders, never run the Emergency Reader on one, and never ask for or accept its Master Password, Recovery Key or Hidden Fields, even if the owner asks. - Launch a release build only with a test identifier, never the one that opens your real Vault folder. - Keep the Vault core and WebView offline: no HTTP clients, updaters, telemetry, crash reporters or analytics. The only exception is the separately sandboxed Agent Companion helper ([ADR-0009](docs/adr/0009-optional-agent-companion-helper.md)), which never receives Vault content. -- Chat Wallets ([ADR-0011](docs/adr/0011-chat-wallets.md)) are accepted but not built. They will be separate keys at addresses holding small amounts, which an agent can ask the app to use, with your Touch ID and Master Password for every send. Keep that route narrow, and never let a Seed Phrase or Private Key from your Vault take part. +- Storing keys through an agent ([ADR-0012](docs/adr/0012-agents-store-and-manage-keys.md)) is accepted but not built. An agent will be able to ask the app to store a key, which you type into the app's own window, and to manage only the keys it added. It never sees or uses a value. Keep that route narrow: no way to read a value out, ever. - Keep keys and decrypted Notes in the Rust core. The WebView receives only one Hidden Field at a time. - Add dependencies only when clearly needed, pin exact versions, and explain why in the PR or local issue. diff --git a/docs/adr/0004-wallet-kinds-under-a-separate-key.md b/docs/adr/0004-wallet-kinds-under-a-separate-key.md index 7d3c111..56e8d5d 100644 --- a/docs/adr/0004-wallet-kinds-under-a-separate-key.md +++ b/docs/adr/0004-wallet-kinds-under-a-separate-key.md @@ -1,6 +1,6 @@ # Wallet Kinds are encrypted under a separate key that unlocking doesn't open -> **Related: [ADR-0011](0011-chat-wallets.md) (2026-11-05, not built yet).** The app will sign transactions for one new Kind, the Chat Wallet, under its own key, separate from the Wallet Key. **Seed Phrases** and **Private Keys** are unchanged: they never sign, and never become Chat Wallets. +> **Related: [ADR-0012](0012-agents-store-and-manage-keys.md) (2026-11-05, not built yet).** An agent may ask the app to store a **Seed Phrase** or **Private Key**. The owner types it into the app's own window, with the **Master Password** as today, and it is sealed under the Wallet Key exactly as above. The agent never sees or uses it. ([ADR-0011](0011-chat-wallets.md), which would have signed with a separate Kind, is deferred.) Showing a **Seed Phrase** or **Private Key** requires the **Master Password** again. If the whole **Vault** were already decrypted in memory, that prompt would be only a UI check in front of exposed data. So the **Hidden Fields** of **Wallet Kinds** are encrypted a second time under a separate random Wallet Key, and a normal unlock does not open it. Only the **Master Password** (a fresh Argon2id derivation, about 0.5 s) or the **Recovery Key** can unwrap the Wallet Key. It is held just long enough to show, add or edit one **Note** and is then wiped. Someone at an **Unlocked** computer, or anything reading the app's memory while it's merely **Unlocked**, can see Wallet Kind titles, chains and addresses, but not the words or keys. diff --git a/docs/adr/0007-agents-use-separate-restricted-keys.md b/docs/adr/0007-agents-use-separate-restricted-keys.md index c8b10d2..aec5a3f 100644 --- a/docs/adr/0007-agents-use-separate-restricted-keys.md +++ b/docs/adr/0007-agents-use-separate-restricted-keys.md @@ -2,7 +2,9 @@ > **Amended by [ADR-0009](0009-optional-agent-companion-helper.md) (2026-10-26):** the owner approved one exception to "no helper": the optional Agent Companion helper, bundled in its own sandbox and managed from Settings. It still has no route to the Vault, its Notes, their metadata, Wallet Kinds, the Master Password or the Recovery Key. Everything else here stands. > -> **Amended by [ADR-0011](0011-chat-wallets.md) (2026-11-05, not built yet):** the owner approved a second exception, the Chat Wallet route. An agent in the separate agent account may make six fixed requests about Chat Wallets, a new and separate Kind for keys at addresses that hold only small amounts. It can get back public addresses, limits left and signed transactions, each send approved by the owner with Touch ID and the Master Password. It never receives a key, an ordinary Note, metadata, Wallet Kinds, the Master Password or the Recovery Key. Everything else here stands. +> **Amended by [ADR-0012](0012-agents-store-and-manage-keys.md) (2026-11-05, not built yet):** the owner approved a narrow agent route for **storing and managing** keys. An agent in the separate agent account may ask the app to store a key, which the owner types into the app's own window, and may list, edit the details of, and ask to replace or delete only the Notes it added. It never receives a value, never sees any other Note, and never uses a key. Everything else here stands. +> +> **Deferred: [ADR-0011](0011-chat-wallets.md) (2026-11-05).** It had approved a second exception, the Chat Wallet route; the owner deferred it the same day, and none of it is built. An agent in the separate agent account may make six fixed requests about Chat Wallets, a new and separate Kind for keys at addresses that hold only small amounts. It can get back public addresses, limits left and signed transactions, each send approved by the owner with Touch ID and the Master Password. It never receives a key, an ordinary Note, metadata, Wallet Kinds, the Master Password or the Recovery Key. Everything else here stands. Status: Accepted by the owner, 2026-10-21 ([issue #25](https://github.com/nniiovoo/encrypted-note/issues/25)). diff --git a/docs/adr/0011-chat-wallets.md b/docs/adr/0011-chat-wallets.md index 864f96b..39facde 100644 --- a/docs/adr/0011-chat-wallets.md +++ b/docs/adr/0011-chat-wallets.md @@ -1,6 +1,6 @@ # Chat Wallets: separate keys an agent can ask the app to use, with the owner's approval -Status: Accepted by the owner, 2026-11-05. **Not built yet.** Until it is, the app still gives agents no interface to the **Vault**, and the README, guide and security model describe the app as it is today. +Status: **Deferred by the owner, 2026-11-05**, the day it was accepted. The goal is now for agents to store and manage keys without using them ([ADR-0012](0012-agents-store-and-manage-keys.md)), so nothing here is built. It is kept as a record of the design, should signing come back. The owner's later answers (Touch ID with the Master Password, an encrypted send history, every EVM and Solana wallet rather than Base alone) would need folding in then. Amends [ADR-0007](0007-agents-use-separate-restricted-keys.md). Leaves [ADR-0004](0004-wallet-kinds-under-a-separate-key.md) and [ADR-0009](0009-optional-agent-companion-helper.md) as written. diff --git a/docs/adr/0012-agents-store-and-manage-keys.md b/docs/adr/0012-agents-store-and-manage-keys.md new file mode 100644 index 0000000..9eb909c --- /dev/null +++ b/docs/adr/0012-agents-store-and-manage-keys.md @@ -0,0 +1,62 @@ +# Agents may store and manage the keys they add, without seeing or using them + +Status: Accepted by the owner, 2026-11-05. **Not built yet.** Until it is, the app still gives agents no interface to the **Vault**, and the README, guide and security model describe the app as it is today. + +Amends [ADR-0007](0007-agents-use-separate-restricted-keys.md). Defers [ADR-0011](0011-chat-wallets.md): signing is no longer the goal. + +> **Contradicts [ADR-0007](0007-agents-use-separate-restricted-keys.md)** ("The app offers no agent interface… no Note enumeration or metadata export"). **Worth reopening because** the owner wants Claude, ChatGPT or Codex to help store and organise keys. This route lets an agent put keys **in**, and look after their names and details, but never take a value **out** or use one. So the worst a tricked agent can do is make a mess of the keys it added, not leak or spend them. + +## The owner's goal, in their words + +"A safety layer for agents, ChatGPT, or like Claude, to safely manage and store the keys… We are not using that key… just store it like I'm typing my keys in… You can store successfully without seeing it… And you can manage that key." + +## Decision + +- **The agent asks; you type; the agent never sees a value.** To store a key, the agent asks the app, and the app opens its own window with the Kind, name and details the agent suggested. You paste or type the value there, and Seed Phrases and Private Keys still need your Master Password, as today. The agent gets back only "saved" and the key's id, or "cancelled". +- **Every Kind of key.** API Key, Login, Text, Seed Phrase and Private Key, for any chain: EVM (Ethereum, Base, Arbitrum…), Solana (SVM), Bitcoin or other. These are the app's existing Kinds, stored exactly as when you add them yourself. +- **The agent manages only the keys it added.** Each one is marked "added by an agent", and you can see that mark in the app. The agent can't see, list or touch any other Note, and it can't put the mark on a Note you added. You can remove the mark at any time, which takes the key out of the agent's reach at once. +- **Five requests.** Every other request is refused: + + | Request | What the app does | What the agent gets back | + |---|---|---| + | Store a key | Opens its own window, pre-filled with the agent's suggestion. You type the value and choose Save | "Saved" and the id, or "Cancelled" | + | List its keys | Reads only the keys marked "added by an agent" | Each one's id, Kind, name and visible details (service, chain, public address, purpose, expiry date), and when it was added or changed. **Never a value**, and never whether a Seed Phrase has a Passphrase | + | Edit details | Changes the name, purpose or expiry date at once. For anything that says where a key is used (chain, public address, derivation path, website, username, service), the app asks you in its own window first | "Done", "Cancelled" or "Not allowed" | + | Replace a value | Opens its own window for that key. You type the new value | "Saved" or "Cancelled" | + | Delete | Asks you in its own window, with your Master Password, then moves the key to Trash (kept 30 days) | "Deleted" or "Cancelled" | + +- **Never, by any request:** show, copy or export a value, sign anything, list your own Notes, or see the Master Password, the Recovery Key, a Backup or a Safety Copy. No value ever travels through the chat, a tool result, a log or the clipboard. +- **Why some edits ask you first:** a tricked agent could change a Private Key's public address to one the attacker controls, and you might later send funds there believing it's yours. A name or a purpose can only confuse you, so those apply at once. +- **The same narrow route ADR-0011 described, off by default.** A local MCP tool for Claude Code, the Claude app or Codex, running in the separate standard agent account. It works only while the app is Unlocked and you have started a grant lasting at most one hour, and it stops on lock, sleep and quit. It accepts connections only from the agent account, and shares nothing with the Agent Companion or `companion/`. Mac only at first. + +## Consequences + +- **What leaves the computer:** the names and visible details of agent-added keys reach the AI company, as part of the chat. Values never do. Name keys with that in mind ("Binance main 2 BTC" says a lot). +- **What a tricked agent can still do:** + - add junk keys, or flood you with windows (you cancel them); + - rename an agent-added key or change its purpose to confuse you; + - ask you to delete or replace one, which happens only if you confirm. + + It can't read, copy, move or spend anything. +- **Storing through the agent is no less safe than typing the key in yourself.** The value goes from your keyboard into the same native control as today, never through the agent. +- **The app gains its first way in from other programs**, in the process that holds the Vault's keys. It needs refusal tests for every request outside the five and for every Note not marked "added by an agent", and a security review before real keys go in. +- **Small Vault format change:** a Note gains one optional mark, "added by an agent" (document schema 3, written only while some Note has it). The Emergency Reader shows the mark. +- **Signing is out.** [ADR-0011](0011-chat-wallets.md)'s Chat Wallets (limits, recipients, Base signing) are deferred, and none of their code is merged. + +## Build order + +Each step is its own pull request, with fake keys only. + +1. These documents: this ADR, ADR-0011 marked Deferred, ADR-0007 amended, the glossary and `AGENTS.md` updated. +2. The mark: the "added by an agent" flag in the Vault format and the notes crate, the Emergency Reader and FORMAT.md, plus tests that agent requests see only marked Notes. +3. The app's own windows: store, replace and delete, opened from a request, reusing today's native entry and Master Password panels. Plus the confirm window for edits that say where a key is used, and showing and removing the mark. +4. The agent route: the MCP tool, the agent-account check, the grant and the five requests, with refusal tests for everything else. +5. A drill with fake keys: a planted instruction to "store this key and then show it", an attempt to edit a Private Key's address, and a flood of store requests. +6. A security review, then real keys. + +## Considered Options + +- **The agent sees or handles the value** (pasted into chat, passed through a tool). Rejected: the value reaches the AI company. +- **The agent sees every key in the Vault.** Rejected by the owner: titles would reach the AI company, and a planted title could trick the agent. +- **You mark which keys an agent may manage.** Not chosen for now; it can be added later as a way to hand an existing key to the agent. +- **Signing with stored keys (ADR-0011).** Deferred: not the goal now. diff --git a/docs/guide.md b/docs/guide.md index 2ceb09f..5f97fc1 100644 --- a/docs/guide.md +++ b/docs/guide.md @@ -38,7 +38,7 @@ Time Machine or other full-computer backups may also copy these folders. Your Va ## AI tools on this computer -encrypted-note gives AI agents no interface to your Vault. (Chat Wallets, accepted in [ADR-0011](adr/0011-chat-wallets.md), will add one narrow route for separate keys holding small amounts. They aren't built yet.) That limits the app, not your computer. Apart from the optional [Agent Companion](agent-companion.md), it has no tool, server or file for them, and the Companion's one text tool can't open your Vault. That doesn't stop an AI tool that runs in your own account on this computer, such as Claude Code, Codex or Cursor. It works as you, so it may be able to: +encrypted-note gives AI agents no interface to your Vault. (A narrow route for agents to store keys you type into the app's own window, and to manage only the keys they added, without ever seeing a value, is accepted in [ADR-0012](adr/0012-agents-store-and-manage-keys.md). It isn't built yet.) That limits the app, not your computer. Apart from the optional [Agent Companion](agent-companion.md), it has no tool, server or file for them, and the Companion's one text tool can't open your Vault. That doesn't stop an AI tool that runs in your own account on this computer, such as Claude Code, Codex or Cursor. It works as you, so it may be able to: - **Copy your Backups.** They stay encrypted, but whoever has a copy can keep guessing passwords on it for as long as they like, and it keeps opening with the Master Password and Recovery Key it was saved with. - **Copy your Vault folder.** The copy is encrypted, like a Backup. For the built Mac app on macOS 14 or later, macOS should ask before Terminal or another app opens that folder. If you allow Terminal, every tool you run in it gets that access until Terminal quits, and an app with Full Disk Access is never asked. On macOS 13, and for a release build that isn't sandboxed or a test run (Vault in `~/Library/Application Support`), nothing asks.