Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -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 fixed operations the owner has approved. Today there is one, the companion's OpenAI request; ADR-0014 (not built) lets the owner add more, one at a time, each with its own record, Agent Key and PR. Never widen it beyond an approved operation, 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 separately created Agent Keys, one per approved operation, never a Vault value (ADR-0009, ADR-0014).
- 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).
- The agent key route (ADR-0012; built with fictional data, not yet checked by hand or reviewed) lets an agent in the separate agent account store keys and manage the Notes it added, and nothing more. Its code: `src-tauri/src/core/agent.rs` (the grant and the five requests), `src-tauri/src/agent_route.rs` (the Unix socket in `/Users/Shared/encrypted-note-keys`, the app's only listener), `crates/agent-keys-mcp` (the agent's tool), and the mark and edit rules in `crates/notes/src/agent.rs`. Keep it to the five requests (ten once ADR-0011's Chat Wallet requests are built), from the agent account's uid only, behind the owner's grant of at most an hour. No request field or reply may carry a value, whether a value is set, a Note not marked "added by an agent", a Note in Trash, the Master Password or the Recovery Key; replies stay fixed shapes and error codes, never free text. The owner types values into the app's own editor, never through the agent, and nothing marks an existing Note. Don't loosen `agent_edit_rule`: where-a-key-is-used edits need the owner's Allow, and every Wallet Kind edit and every delete also the Master Password. Unix sockets and peer-uid checks belong only in `agent_route.rs` and `crates/agent-keys-mcp/src/`, the tool depends on no Vault crate, and none of this code uses `companion/` (`node scripts/check-network-source.mjs` checks all three). Signing comes only with Chat Wallets (ADR-0011, reinstated 2026-11-09, not built): build it only by its build order, one PR per step, with fake keys and test funds, and never sign with a Seed Phrase, a Private Key or an Agent-added Note. Only Claude Code and Codex may use the route (ADR-0013, not built): their signature list stays fixed in code, never in anything the agent account can write.
- The agent key route (ADR-0012; built with fictional data, not yet checked by hand or reviewed) lets an agent in the separate agent account store keys and manage the Notes it added, and nothing more. Its code: `src-tauri/src/core/agent.rs` (the grant and the five requests), `src-tauri/src/agent_route.rs` (the Unix socket in `/Users/Shared/encrypted-note-keys`, the app's only listener), `crates/agent-keys-mcp` (the agent's tool), and the mark and edit rules in `crates/notes/src/agent.rs`. Keep it to the five requests (ten once ADR-0011's Chat Wallet requests are built), from the agent account's uid only, behind the owner's grant of at most an hour. No request field or reply may carry a value, whether a value is set, a Note not marked "added by an agent", a Note in Trash, the Master Password or the Recovery Key; replies stay fixed shapes and error codes, never free text. The owner types values into the app's own editor, never through the agent, and nothing marks an existing Note. Don't loosen `agent_edit_rule`: where-a-key-is-used edits need the owner's Allow, and every Wallet Kind edit and every delete also the Master Password. Unix sockets and peer-uid checks belong only in `agent_route.rs` and `crates/agent-keys-mcp/src/`, the tool depends on no Vault crate, and none of this code uses `companion/` (`node scripts/check-network-source.mjs` checks all three). Signing comes only with Chat Wallets (ADR-0011, reinstated 2026-11-09, not built): build it only by its build order, one PR per step, with fake keys and test funds, and never sign with a Seed Phrase, a Private Key or an Agent-added Note. Only Claude Code and Codex may use the route (ADR-0013; built with fictional data, not yet checked by hand): `judge_programs` and `check_program` in `agent_route.rs` let in only the tool with the owner's approved code hash, started by an `ALLOWED_STARTERS` entry validated as Developer ID, both with hardened runtime. Keep that list fixed in code, never in anything the agent account can write; read programs only through the kernel (`csops_audittoken`, `csops`, `sysctl`), never their files; and keep `ProgramCheck::Off` debug-only.
- Add a dependency only when it's clearly needed, pin its exact version, and say why in the PR/issue.

## Verify
Expand Down
2 changes: 1 addition & 1 deletion CONTEXT.md
Original file line number Diff line number Diff line change
Expand Up @@ -138,7 +138,7 @@ _Avoid_: pinned, bookmarked, starred item
- 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. (The one exception is **Agent-added Notes**, through a local route only the separate agent account can use while the owner's grant runs: 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** and **Recovery Key** never take part in agent work, and a **Wallet Kind**'s value never does: an agent may only ask to store one, which the owner types in with the **Master Password**, and, for one it added, ask to edit its visible details (the owner's Allow, then the **Master Password**), replace its value (typed by the owner, with the **Master Password**) or delete it (the **Master Password**) ([ADR-0012](docs/adr/0012-agents-store-and-manage-keys.md)).
- 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)).
- Only Claude Code and Codex, started in the separate agent account, may use the agent routes; the app checks their Apple code signatures ([ADR-0013](docs/adr/0013-only-claude-code-and-codex-use-the-agent-routes.md), not built). That check is a speed bump: the separate account is the boundary, so it holds only those two.
- Only Claude Code and Codex, started in the separate agent account, may use the agent routes; the app checks, through the kernel, that the approved tool was started by one of them, signed by Anthropic or OpenAI ([ADR-0013](docs/adr/0013-only-claude-code-and-codex-use-the-agent-routes.md); built on the agent key route with fictional data, not yet checked by hand). That check is a speed bump: the separate account is the boundary, so it holds only those two.
- 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.
- The app nudges the owner when changes have gone 7+ days without a **Backup**, and warns if a **Backup** is saved into a cloud-synced folder.
Expand Down
2 changes: 1 addition & 1 deletion crates/agent-keys-mcp/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
//! `enote-agent-keys`: the MCP tool an agent (Claude Code, the Claude app, Codex) runs in its own
//! `enote-agent-keys`: the MCP tool an agent (Claude Code or Codex, ADR-0013) runs in its own
//! Mac account to ask the encrypted-note app to store and look after keys (ADR-0012).
//!
//! What it guarantees:
Expand Down
26 changes: 25 additions & 1 deletion docs/adr/0013-only-claude-code-and-codex-use-the-agent-routes.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Only Claude Code and Codex may use the agent routes

Status: Accepted by the owner 2026-11-09 (merged in PR #111). **Spike done 2026-11-09** (see [Spike result](#spike-result-2026-11-09)); the owner then decided the two questions it raised. **The check itself is not built.**
Status: Accepted by the owner 2026-11-09 (merged in PR #111). **Spike done 2026-11-09** (see [Spike result](#spike-result-2026-11-09)); the owner then decided the two questions it raised. **Step 3 built 2026-11-09** on the ADR-0012 route, checked with fictional data and stand-in programs only (see [As built](#as-built-2026-11-09)). Steps 4 and 5 are still to do.

Amends [ADR-0012](0012-agents-store-and-manage-keys.md) ("It accepts connections only from the agent account"). Applies equally to the Chat Wallet requests ([ADR-0011](0011-chat-wallets.md)) and to the Agent Companion's agent entry ([ADR-0014](0014-agent-key-operations-through-the-companion.md)).

Expand Down Expand Up @@ -77,6 +77,30 @@ A throwaway Swift program, signed ad-hoc with this app's exact `Entitlements.pli
- **Works:** adding one `temporary-exception.sbpl` rule allowing `network-bind` and `network-inbound` on Unix sockets in that folder only. The owner approved that rule on 2026-11-09 ([ADR-0012](0012-agents-store-and-manage-keys.md), As built).
- **Still to confirm:** the rule in a Developer ID-signed, notarized build.

## As built (2026-11-09)

- **Where it lives.** In `src-tauri/src/agent_route.rs`:
- `judge_programs` decides from what the kernel said, on every platform;
- on a Mac, `check_program` gathers it for each connection, after the account check.
- **What it reads.**
- **The tool:** read through the connection's audit token (`csops_audittoken`): code hash, signature status, identity, team, validation category and entitlements.
- **Its starter:** found by process number from `sysctl` (`kinfo_proc`, whose size and fields are checked), and read by `csops`.
- **Afterwards:** the tool must still answer through its token, with the same starter, or it is refused.
- **What must match.**
- **The tool's code hash:** the one approved in Settings.
- **The starter:** Claude Code or Codex, by identity, team and validation category "Developer ID".
- **Both programs:** hardened runtime, not debuggable or debugged, and neither `allow-dyld-environment-variables` nor `get-task-allow` named in their entitlements.
- **The tool's code hash.** The owner pastes it into Settings (**The agent tool's code hash**), and it is kept in `settings.json`.
- **Where it comes from:** `scripts/agent-keys-setup.sh` prints it, and refuses a tool not signed with hardened runtime.
- **Without it, Start refuses** ("not_set_up").
- **Changing it** ends a running grant.
- **The Start dialog** now says that Claude Code or Codex in that Mac user can ask.
- **Developers only:** `ENOTE_DEV_AGENT_ANY_PROGRAM` turns the check off in debug builds, beside the existing `ENOTE_DEV_AGENT_UID`. Release builds have no way to turn it off.
- **Tests** (`src-tauri/tests/agent_route.rs`):
- every branch of the decision;
- the kernel readers against a running `/bin/sleep`;
- on a real socket, Apple's `nc` as the tool and `bash` as its starter: answered when both are on the list; closed without a reply for the real list, a wrong tool hash, and a program connecting by itself.

## Considered Options

- **The agent account alone (as built):** the owner asked for more.
Expand Down
Loading
Loading