An open API service indexing awesome lists of open source software.

https://github.com/numikel/kprun

Local secrets injector for developers and AI agent workflows — KeePass vault, OS keychain unlock, per-process env injection.
https://github.com/numikel/kprun

cli developer-tools environment-variables keepass keepassxc mcp model-context-protocol rust secrets-management security

Last synced: 23 days ago
JSON representation

Local secrets injector for developers and AI agent workflows — KeePass vault, OS keychain unlock, per-process env injection.

Awesome Lists containing this project

README

          

# kprun v0.2.3

[![CI](https://github.com/numikel/kprun/actions/workflows/ci.yml/badge.svg)](https://github.com/numikel/kprun/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](LICENSE)
![Rust](https://img.shields.io/badge/Rust-1.88.0-orange?logo=rust)
![Platform](https://img.shields.io/badge/platform-Linux%20%7C%20macOS%20%7C%20Windows-lightgrey)

![kprun demo](docs/kprun.gif)

**Local secrets injector for developers and AI agent workflows.** KeePass `.kdbx` vault (KeePassXC-compatible), OS keychain unlock, per-process env injection — not session-wide.

[Releases](https://github.com/numikel/kprun/releases) · [Changelog](CHANGELOG.md) · [Install](#installation) · [Quick start](#quick-start) · [Coding agents & OpenRouter](#coding-agents-and-openrouter) · [MCP integration](#mcp-integration) · [Security model](#security-model)

---

## About

kprun stores API keys and tokens in a KeePass database on your machine. It unlocks the vault via `KPRUN_KEYFILE`, the OS credential store, or an interactive prompt, then injects secrets as environment variables into **one child process** only. Nothing is exported to your shell profile, nothing lands in MCP stdout.

Typical uses:

- Run MCP servers (`npx …`) without pasting tokens into client config files
- Launch coding agents (Claude Code, Hermes, Junie, AGY, …) with OpenRouter env vars injected for one session only
- Launch dev tools with scoped secrets (`kprun run openai -- python app.py`)
- Manage a dedicated **dev-secrets** vault separate from your personal password manager

## How it works

```mermaid
flowchart LR
subgraph without ["Without kprun"]
direction TB
W1["shell exports GITHUB_TOKEN=…"]
W1 -->|"secrets in every child"| W2["all processes inherit env"]
end

subgraph with ["With kprun"]
direction TB
K1["kprun run github -- npx @mcp/server-github"]
K1 --> K2["unlock vault
(keyfile → keyring → prompt)"]
K2 --> K3["read entry 'github' custom fields"]
K3 --> K4["inject env into child only"]
K4 --> K5["inherit stdio; audit log (key names only)"]
end
```

Unlock priority: `KPRUN_KEYFILE` → OS keystore (`kprun` / `master`) → hidden stderr prompt.

## Features

- ✅ **KeePass / KeePassXC vault** — entry title = service name; custom string fields = env var names
- ✅ **Per-process injection** — `kprun run` opens the vault read-only and spawns one child with merged env
- ✅ **MCP-safe stdio** — `run` prints nothing on stdout; child owns stdin/stdout/stderr
- ✅ **Full secret lifecycle** — `init`, `set`, `get`, `unset`, `delete`, `export`, `import`, `doctor`
- ✅ **Audit log** — JSON lines with entry names and injected key names; **never values**
- ✅ **Cross-platform** — Linux, macOS, Windows (PATHEXT-aware spawn, keyring v1)
- ✅ **RTK-style install** — `install.sh` / `install.ps1` with SHA-256 checksum verify
- ✅ **CI matrix** — fmt, clippy, tests on ubuntu/windows/macos; release assets on tag `v*`

## Requirements

- **Rust**: 1.88.0+ (to build from source)
- **OS**: Linux, macOS, or Windows
- **Optional**: [KeePassXC](https://keepassxc.org/) to create or edit `.kdbx` files
- **MCP client**: Cursor, Claude Code, or any tool that spawns a subprocess over stdio

## Installation

### Quick install (Linux / macOS)

```bash
curl -fsSL https://raw.githubusercontent.com/numikel/kprun/refs/heads/main/scripts/install.sh | sh
```

Installs to `~/.local/bin` by default. Override with `KPRUN_INSTALL_DIR`. Skip PATH changes with `KPRUN_NO_MODIFY_PATH=1`.

> Add to PATH manually if needed:
>
> ```bash
> echo 'export PATH="$HOME/.local/bin:$PATH"' >> ~/.bashrc # or ~/.zshrc
> ```

### Quick install (Windows)

```powershell
irm https://raw.githubusercontent.com/numikel/kprun/refs/heads/main/scripts/install.ps1 | iex
```

Default install dir: `%LOCALAPPDATA%\kprun\bin`. Adds user `Path` unless `KPRUN_NO_MODIFY_PATH=1`.

Open a **new terminal**, then verify:

```bash
kprun --version
```

### Pre-built binaries

Download from [GitHub Releases](https://github.com/numikel/kprun/releases) (after the first tag):

| Platform | Asset |
|----------|-------|
| Linux x86_64 | `kprun-x86_64-unknown-linux-gnu.tar.gz` |
| Linux arm64 | `kprun-aarch64-unknown-linux-gnu.tar.gz` |
| macOS Intel | `kprun-x86_64-apple-darwin.tar.gz` |
| macOS Apple Silicon | `kprun-aarch64-apple-darwin.tar.gz` |
| Windows | `kprun-x86_64-pc-windows-msvc.zip` + standalone `kprun.exe` |

Verify with `checksums.txt` from the same release unless `KPRUN_SKIP_CHECKSUM=1`.

### Build from source

```bash
git clone https://github.com/numikel/kprun.git
cd kprun
cargo build --release -p kprun
# binary: target/release/kprun (or target//release/kprun)
```

Or install into Cargo bin dir:

```bash
cargo install --path crates/kprun
```

## Quick start

```bash
# 1. Create vault (master password → OS keychain by default)
kprun init

# 2. Store secrets (entry title = service; fields = env vars)
kprun set github GITHUB_TOKEN=ghp_xxx

# 3. Inject into a child process
kprun run github -- npx -y @modelcontextprotocol/server-github
```

Windows (after `install.ps1`):

```powershell
kprun init
kprun set github GITHUB_TOKEN=ghp_xxx
kprun run github -- npx -y @modelcontextprotocol/server-github
```

### Attach an existing KeePassXC database

```bash
kprun init --db /path/to/existing.kdbx
```

Verifies unlock and optionally stores the master password in the OS keychain. Does **not** recreate the database.

## Coding agents and OpenRouter

Many terminal coding agents read API keys and provider URLs from **environment variables**. Instead of exporting them in `~/.bashrc` or `~/.zshrc` (where every process inherits them), store the OpenRouter profile in your vault and launch the agent through `kprun run`.

The `--` separator is required — it marks where vault entry names end and the child command begins:

```text
kprun run -- [args...]
```

### One-time vault setup (Claude Code / OpenRouter)

Per [OpenRouter's Claude Code guide](https://openrouter.ai/docs/cookbook/coding-agents/claude-code-integration), Claude Code expects these variables. Store them under one vault entry (title = `openrouter` here; any name works):

```bash
kprun set openrouter \
OPENROUTER_API_KEY=sk-or-... \
ANTHROPIC_BASE_URL=https://openrouter.ai/api \
ANTHROPIC_AUTH_TOKEN=sk-or-... \
ANTHROPIC_API_KEY=
```

KeePass fields are literal values — set `ANTHROPIC_AUTH_TOKEN` to the same key as `OPENROUTER_API_KEY`. Set `ANTHROPIC_API_KEY` to an **empty** string to avoid auth conflicts with a cached Anthropic login (run `/logout` inside Claude Code once if you previously signed in with Anthropic).

Optional model overrides (also from the OpenRouter docs):

```bash
kprun set openrouter \
ANTHROPIC_DEFAULT_SONNET_MODEL='~anthropic/claude-sonnet-latest' \
ANTHROPIC_DEFAULT_OPUS_MODEL='~anthropic/claude-opus-latest'
```

### Launch examples

**Claude Code** — secrets stay in the child process only; your shell profile stays clean:

```bash
kprun run openrouter -- claude
```

Windows PowerShell:

```powershell
kprun run openrouter -- claude
```

Verify inside Claude Code with `/status` (auth token: `ANTHROPIC_AUTH_TOKEN`, base URL: `https://openrouter.ai/api`).

**Antigravity CLI (`agy`)** — the CLI authenticates via Google by default. If you use OpenRouter through a plugin, extension, or any workflow that reads `OPENROUTER_API_KEY` from the environment, inject it the same way:

```bash
kprun set openrouter OPENROUTER_API_KEY=sk-or-...
kprun run openrouter -- agy
```

**Hermes Agent** — Nous Research's terminal agent reads `OPENROUTER_API_KEY` from the environment (alternative to `~/.hermes/.env`). Model and provider stay in `~/.hermes/config.yaml`; see [OpenRouter's Hermes guide](https://openrouter.ai/docs/cookbook/coding-agents/hermes-integration):

```bash
kprun set openrouter OPENROUTER_API_KEY=sk-or-...
kprun run openrouter -- hermes
# or: kprun run openrouter -- hermes --tui
```

**Junie CLI** — JetBrains' terminal agent uses OpenRouter as a native BYOK provider via `JUNIE_OPENROUTER_API_KEY`; see [OpenRouter's Junie guide](https://openrouter.ai/docs/cookbook/coding-agents/junie):

```bash
kprun set openrouter \
OPENROUTER_API_KEY=sk-or-... \
JUNIE_OPENROUTER_API_KEY=sk-or-...
kprun run openrouter -- junie
```

Headless CI example (same injected env, no shell profile):

```bash
kprun run openrouter -- junie "Review and fix any code quality issues in the latest commit"
```

**GitHub Copilot CLI** — Copilot fixes the model at startup and speaks OpenAI-compatible APIs; env injection alone is awkward for live model switching. For Copilot CLI (and Codex CLI with OpenRouter), the author recommends **[copilot-cli-custom-proxy](https://github.com/numikel/copilot-cli-custom-proxy)** instead: a local tray proxy that swaps models on the fly, injects the API key from memory, and launches Copilot/Codex with the right env — without putting keys in your shell profile.

| Agent | kprun fit | Notes |
|-------|-----------|-------|
| Claude Code | ✅ Best fit | Env-based OpenRouter setup; see [OpenRouter docs](https://openrouter.ai/docs/cookbook/coding-agents/claude-code-integration) |
| Hermes Agent | ✅ Best fit | `OPENROUTER_API_KEY`; config in `~/.hermes/config.yaml`; see [OpenRouter docs](https://openrouter.ai/docs/cookbook/coding-agents/hermes-integration) |
| Junie CLI | ✅ Best fit | `JUNIE_OPENROUTER_API_KEY`; see [OpenRouter docs](https://openrouter.ai/docs/cookbook/coding-agents/junie) |
| Antigravity CLI (`agy`) | ⚠️ Partial | Default auth is Google; use kprun when the workflow reads env vars |
| Copilot CLI / Codex CLI | ❌ Use proxy | Prefer [copilot-cli-custom-proxy](https://github.com/numikel/copilot-cli-custom-proxy) |

One OpenRouter key can power every tool above; generate it at [openrouter.ai/settings/keys](https://openrouter.ai/settings/keys).

## Configuration

| Variable | Default | Description |
|----------|---------|-------------|
| `KPRUN_DB` | `~/.kprun/secrets.kdbx` | Path to the KeePass database |
| `KPRUN_KEYFILE` | — | Path to a cryptographic key file (second factor) |
| `KPRUN_LOG` | `~/.kprun/access.log` | Audit log path (JSON lines, key names only) |
| `KPRUN_INSTALL_DIR` | `~/.local/bin` / `%LOCALAPPDATA%\kprun\bin` | Install script target |
| `KPRUN_NO_MODIFY_PATH` | unset | Set to `1` to skip shell PATH updates |
| `KPRUN_SKIP_CHECKSUM` | unset | Set to `1` to skip install checksum verify |
| `KPRUN_VERSION` | latest release | Pin install script version |
| `KPRUN_TEST_MASTER` | — | Test hook (only in builds compiled with `--features test-hooks`; not present in GitHub Release binaries): fixed master password for automation |

Install script env vars are documented in `scripts/install.sh` and `scripts/install.ps1`.

## CLI reference

```
kprun init [--db PATH] [--no-store] [--keyfile PATH]
kprun run [entry2 ...] -- [args...]
kprun list [--json]
kprun get [--keys] [--reveal]
kprun set KEY=val [KEY2=val2 ...]
kprun unset KEY [KEY2 ...]
kprun delete
kprun export [--format json|dotenv] [--stdout] [--reveal]
kprun import [--merge]
kprun doctor [--mcp ]
kprun deinit
```

Notes:

- `get` and `export` show key **names** by default; use `--reveal` only when you need values (stderr warning + audit).
- `run` inherits stdio to the child and writes **nothing** to stdout (MCP-safe).
- `import` without `--merge` replaces vault content; structure-only dotenv exports are rejected to prevent accidental wipes.
- Exit codes: `1` for DB not found, entry not found, unlock failed, DB locked; child exit code propagated; empty injection → `0` with stderr warning.

### Export and import

`import` accepts JSON (`.json`) or kprun dotenv (`.env`). JSON is the structured format from `kprun export --stdout`. Dotenv is **not** a generic project `.env` file — it is the round-trip format produced by `kprun export --format dotenv`.

Each vault **entry** is a comment line with the entry title, followed by `KEY=value` lines. Separate entries with a blank line:

```env
# github
GITHUB_TOKEN="ghp_xxx"

# postgres
DATABASE_URL="postgres://local"
```

To migrate a flat project `.env` (keys only, no title comments), add one title line at the top. All following keys land in that entry until the next `# title` or blank line:

```env
# default
OPENAI_API_KEY="sk-..."
LANGFUSE_SECRET_KEY="sk-lf-..."
```

Then import:

```bash
kprun import secrets.env --merge # add/update keys; keep other vault entries
kprun import secrets.env # replace vault content with file entries
```

Inspect the canonical dotenv layout with:

```bash
kprun export --format dotenv --stdout --reveal
```

Structure-only dotenv exports (key names in `#` comments, no values) cannot be imported — re-export with `--reveal` first.

## MCP integration

MCP clients spawn a command and talk over the child's stdio. Use `kprun run` as a transparent wrapper.

**Linux / macOS** (with `kprun` on `PATH`):

```json
{
"mcpServers": {
"github": {
"command": "kprun",
"args": ["run", "github", "--", "npx", "-y", "@modelcontextprotocol/server-github"]
}
}
}
```

**Windows** (prefer full path — some MCP clients do not resolve `PATH` reliably):

```json
{
"mcpServers": {
"github": {
"command": "C:\\Users\\you\\AppData\\Local\\kprun\\bin\\kprun.exe",
"args": ["run", "github", "--", "npx", "-y", "@modelcontextprotocol/server-github"]
}
}
}
```

Generate a ready-to-paste fragment:

```bash
kprun doctor --mcp github
```

For other entries, append the MCP server command after `--`:

```bash
kprun doctor --mcp qdrant -- npx -y @modelcontextprotocol/server-qdrant
```

Without a child command, generic entries emit `["run", "", "--"]` and a stderr hint — paste the server command into `args` manually or re-run with `--`.

After editing MCP config, check `git diff` — some tools may write secrets back to disk.

## Automation and cron

When no interactive session is available (cron, Task Scheduler), the OS keychain may be unavailable. Use a **keyfile**:

```bash
kprun init --keyfile ~/.kprun/master.key
export KPRUN_KEYFILE=~/.kprun/master.key
kprun run myservice -- /path/to/script.sh
```

The keyfile is generated by kprun (64 random bytes), not a plaintext password file. Restrict permissions (`chmod 600` on Unix; user-only ACL on Windows).

For scheduled jobs, set `KPRUN_DB` and `KPRUN_KEYFILE` in the job environment. Use `--no-store` at `init` if you do not want the master password in the keychain.

## Project structure

```
kprun/
├── crates/
│ ├── kprun-core/ # vault, unlock, inject, audit (no clap / Command)
│ └── kprun/ # CLI binary, spawn, commands
├── scripts/
│ ├── install.sh # RTK-style installer (Unix)
│ └── install.ps1 # Windows installer
├── tests/ # integration tests (run, init, manage, export, doctor, …)
├── .github/workflows/
│ ├── ci.yml # fmt, clippy, test matrix
│ └── release.yml # cross-build + checksums on tag v*
└── docs/
├── kprun.gif # demo animation
└── changelogs/ # per-version release notes
```

## Development

### Setup

```bash
git clone https://github.com/numikel/kprun.git
cd kprun
cargo build -p kprun
```

### Running tests

```bash
cargo test --all
```

KeePassXC compatibility test (optional, local fixture):

```bash
# Create tests/fixtures/keepassxc.kdbx in KeePassXC (gitignored)
# Entry title: fixture; custom attribute: FIXTURE_KEY
KPRUN_KEEPASSXC_FIXTURE=1 KPRUN_TEST_MASTER='your-pass' \
cargo test reads_keepassxc_fixture -- --ignored
```

### Code quality (matches CI)

```bash
cargo fmt --all -- --check
cargo clippy --all-targets --all-features -- -D warnings
cargo test --all
```

## Security model

- Use a dedicated **dev-secrets** vault, not your personal password manager.
- Report vulnerabilities per [SECURITY.md](SECURITY.md) (**contact@michalsk.pl**); do not file public issues for security bugs.
- Secrets exist in the **child process environment** after injection (same model as other secret runners).
- Audit log records entry names and injected key names — **never values**.
- Do not use `setx` or global shell profiles for API keys.
- Pass only the entries a command needs: `kprun run openai -- python script.py`, not every secret at once.
- `export --reveal` and `get --reveal` print values to the terminal — use deliberately.

## Releases

Releases are published when a maintainer tags `vX.Y.Z` and pushes:

```bash
git tag vX.Y.Z
git push origin main --tags
```

CI validates the changelog file and version match, builds release binaries for five targets, and publishes a GitHub Release whose body comes from [docs/changelogs/vX.Y.Z.md](docs/changelogs/).

## Contributing

1. Fork the repository.
2. Create a feature branch (`git checkout -b feat/my-change`).
3. Commit using **Conventional Commits 1.0.0** (e.g. `feat(cli): add example command`, `fix(core): handle locked db`).
4. Add or update tests for behavior changes.
5. Run `cargo fmt`, `cargo clippy --all-targets --all-features -- -D warnings`, and `cargo test --all`.
6. Open a pull request against `main`.

Use English for code, comments, and CLI messages.

## License

MIT License — see [LICENSE](LICENSE).

## Author

**@numikel**

---

**Security note:** kprun injects secrets into child process environments. Treat the vault file, keyfile, and audit log as sensitive. Do not commit `.kdbx` files or keyfiles to version control.