Skip to main content
Glama
fainir

nice

by fainir
README.md
# nice.

**The access layer between your AI agents and everything they touch.**

[![CI](https://github.com/fainir/nice/actions/workflows/ci.yml/badge.svg)](https://github.com/fainir/nice/actions/workflows/ci.yml)
[![License: MIT](https://img.shields.io/badge/license-MIT-green.svg)](LICENSE)
![Node >= 22](https://img.shields.io/badge/node-%3E%3D22-brightgreen)
![Dependencies: 0](https://img.shields.io/badge/dependencies-0-blue)

Add an API key or connect an app **once**, in a web UI. Pair each machine **once**, with a single command. Every agent you run - Claude Code, custom scripts, any CLI - gets exactly the access you scope to it: injected as env vars, or proxied through the hub so the agent **never holds a raw key at all**. Every access is audited. Any device can be cut off in one click.

Your keys today: pasted into `.env` files and MCP configs across every laptop, unrotated, unauditable, unrevocable. This replaces that.

## How it works

```
┌─────────────┐     pair once      ┌──────────────┐   scoped, audited   ┌──────────────┐
│  nice hub    │ ◄──────────────── │  your machine │ ◄────────────────  │  your agents  │
│  (self-host) │                    │  (nice CLI)   │    env or MCP      │  claude, ...  │
└─────────────┘                    └──────────────┘                    └──────────────┘
   encrypted vault, web UI,           device token,                       nice run -- claude
   OAuth refresh, audit log           ~/.nice/config                      nice mcp serve
```

## Quickstart

Requires Node 22+. Zero dependencies - nothing to install.

```sh
git clone https://github.com/fainir/nice && cd nice
node server/server.js
# nice hub listening on http://localhost:8787
```

1. Open http://localhost:8787, create your account, and add a connection (an API key, or OAuth once configured). Secrets are AES-256-GCM encrypted before touching disk; the UI only ever shows the last 4 characters again.
2. Install the CLI and pair the machine your agents run on (Devices tab → "Pair a device"):

```sh
npm install -g .          # from the repo; gives you the `nice` command
nice pair <CODE> --server http://localhost:8787
```

3. Give every agent access:

```sh
nice run -- claude                   # any command, all scoped keys injected as env vars
nice run --only GITHUB_TOKEN -- npx -y @modelcontextprotocol/server-github
eval "$(nice env)"                   # or load into the current shell
nice status                          # what this machine can reach
nice unpair                          # revoke this machine, server-side too
```

## Gateway mode - agents never see your keys

```sh
nice mcp serve
```

runs an MCP server (stdio) exposing `list_connections` and `http_request`. When an agent calls `http_request`, the **hub** makes the API call and injects auth server-side - the credential never enters the agent's process. Requests are restricted to each provider's real API origin, client-supplied auth headers are stripped, and every call is audited.

Plug into Claude Code via `.mcp.json`:

```json
{ "mcpServers": { "nice-hub": { "command": "nice", "args": ["mcp", "serve"] } } }
```

## Scoping, audit, revocation

- **Scope per device**: in the Devices tab, limit any paired machine to exactly the connections it should see - enforced for both env injection and the gateway.
- **Audit everything**: every login, key save, pairing, secret read, and proxied call lands in a per-user audit log with the acting device.
- **Revoke instantly**: delete a device in the UI (or `nice unpair` from the machine) and its access dies immediately.

## Connect apps with sign-in (OAuth)

The full authorization-code flow (single-use state, encrypted token storage, automatic refresh) is built in for GitHub, Google, and Slack - and any custom OAuth provider. Register an OAuth app with the provider (callback: `<your hub>/oauth/callback`), then:

```json
// data/oauth.json
{ "github": { "clientId": "...", "clientSecret": "..." } }
```

A "Connect with sign-in" button lights up on the Connections tab - no restart needed. Tokens refresh automatically whenever an agent uses them.

## Deploy

```sh
docker build -t nice-hub .
docker run -d -p 8787:8787 -v nice-data:/data --name nice-hub nice-hub
```

The vault (store + master key) lives in the `nice-data` volume - back it up. **Always put TLS in front** (Caddy, nginx, or your platform) for any non-localhost deployment.

| Env var | Default | Meaning |
|---------|---------|---------|
| `NICE_PORT` | `8787` | server port |
| `NICE_DATA` | `./data` | server data dir (store + master key + oauth.json) |
| `NICE_HOME` | `~/.nice` | CLI config dir |

## Security model

Self-host trust model: your machine, your keys, your master key. Vault encrypted with AES-256-GCM; passwords scrypt-hashed; tokens stored only as SHA-256 hashes; single-use expiring pairing codes; rate-limited auth; origin-allowlisted proxy. Full details and reporting instructions in [SECURITY.md](SECURITY.md).

## FAQ

**Why trust this with my keys?** You don't have to trust anyone - it's self-hosted, zero-dependency, and small enough to read in an afternoon (~1500 lines). Your keys never leave your infrastructure.

**How is this different from 1Password CLI or Doppler?** Those inject secrets for humans and CI. Nice is agent-native: per-device pairing and scoping, an audit trail of what each agent read, one-click revocation, OAuth refresh handled for you, and an MCP gateway where agents call APIs without ever holding credentials.

**What if the hub is down?** `nice run` fails closed (no stale secrets on disk). Run the hub on the same machine or your LAN for zero-dependency startups.

**Is there a hosted version?** Not yet. The roadmap includes a zero-knowledge hosted mode - where the server cannot decrypt your vault - after an external audit.

## Contributing

PRs welcome - see [CONTRIBUTING.md](CONTRIBUTING.md). Security reports: [SECURITY.md](SECURITY.md) (please, not public issues).

## License

[MIT](LICENSE)