q-ring โ€” never paste an API key into .env again
# q-ring **OS keychain secrets for AI coding agents, over MCP.** [![CI](https://img.shields.io/github/actions/workflow/status/I4cTime/q-ring/ci.yml?style=flat-square&label=CI)](https://github.com/I4cTime/q-ring/actions/workflows/ci.yml) [![NPM Version](https://img.shields.io/npm/v/@i4ctime/q-ring?style=flat-square&color=0ea5e9)](https://www.npmjs.com/package/@i4ctime/q-ring) [![NPM Downloads](https://img.shields.io/npm/dm/@i4ctime/q-ring?style=flat-square&color=0ea5e9&label=downloads)](https://www.npmjs.com/package/@i4ctime/q-ring) [![Docs](https://img.shields.io/badge/docs-website-0ea5e9?style=flat-square)](https://qring.i4c.studio/docs) [![MCP Tools](https://img.shields.io/badge/MCP_tools-44-0ea5e9?style=flat-square)](https://glama.ai/mcp/servers/I4cTime/q-ring) [![Smithery](https://img.shields.io/badge/smithery-i4ctime%2Fq--ring-0ea5e9?style=flat-square)](https://smithery.ai/servers/i4ctime/q-ring) [![Cursor Directory](https://img.shields.io/badge/cursor_directory-q--ring-0ea5e9?style=flat-square)](https://cursor.directory/plugins/q-ring) [![PulseMCP](https://img.shields.io/badge/pulsemcp-q--ring-0ea5e9?style=flat-square)](https://www.pulsemcp.com/servers/i4ctime-q-ring) [![mcpservers.org](https://img.shields.io/badge/mcpservers.org-q--ring-0ea5e9?style=flat-square)](https://mcpservers.org/servers/i4ctime/q-ring) [![License](https://img.shields.io/npm/l/@i4ctime/q-ring?style=flat-square&color=0ea5e9)](https://github.com/I4cTime/q-ring/blob/main/LICENSE) [![Discord](https://img.shields.io/badge/discord-join%20the%20studio-5865F2?style=flat-square&logo=discord&logoColor=white)](https://discord.gg/5uEApw5uEz) [![YouTube](https://img.shields.io/badge/youtube-%40qring__dev-FF0000?style=flat-square&logo=youtube&logoColor=white)](https://www.youtube.com/@qring_dev) [![X](https://img.shields.io/badge/follow-%40i4c__studio-000000?style=flat-square&logo=x&logoColor=white)](https://x.com/i4c_studio) q-ring MCP server Stop pasting API keys into plain-text `.env` files or wrestling with clunky secret managers. **q-ring** securely anchors your credentials to your OS's native vault (macOS Keychain, Linux Secret Service, Windows Credential Vault) and supercharges them with mechanics from quantum physics. > ๐Ÿ“– **[View the Official Documentation](https://qring.i4c.studio/docs)** for a complete CLI reference, MCP prompt cookbooks, and architecture details. ### Why q-ring? - **Superposition:** Store one key with multiple states (dev/staging/prod) that collapse based on context. - **Entanglement:** Link keys across projects so rotating one automatically updates them all. - **Tunneling:** Create ephemeral, in-memory secrets that self-destruct after a set time or read count. - **Teleportation:** Securely pack and share AES-256-GCM encrypted secret bundles. - **Seamless AI Integration:** 44 built-in MCP tools for native use in **Cursor**, **Kiro**, and **Claude Code**. ## ๐Ÿš€ Installation q-ring is designed to be installed globally so it's available anywhere in your terminal. Pick your favorite package manager: ```bash # pnpm (recommended) pnpm add -g @i4ctime/q-ring # npm npm install -g @i4ctime/q-ring # yarn yarn global add @i4ctime/q-ring # Homebrew (macOS / Linux) brew install i4ctime/tap/qring ``` ### Docker (MCP server) The repo ships a `Dockerfile` that builds the MCP server and exposes it through [`mcp-proxy`](https://github.com/punkpeye/mcp-proxy) โ€” useful for hosted MCP deployments (e.g. Glama) or keeping the server off the host entirely: ```bash git clone https://github.com/I4cTime/q-ring.git cd q-ring docker build -t qring-mcp . docker run --rm -p 8080:8080 qring-mcp ``` > Note: inside a container there is no OS keychain (GNOME Keyring / macOS Keychain), so this path is for the MCP protocol surface, ephemeral use, and CI experiments โ€” not for durable local secret storage. For day-to-day use install the CLI natively via one of the package managers above. ## โšก Quick Start ```bash # 1๏ธโƒฃ Store a secret (prompts securely if value is omitted) qring set OPENAI_API_KEY sk-... # 2๏ธโƒฃ Retrieve it anytime qring get OPENAI_API_KEY # 3๏ธโƒฃ List all keys (values are never shown) qring list # 4๏ธโƒฃ Generate a cryptographic secret and save it qring generate --format api-key --prefix "sk-" --save MY_KEY # 5๏ธโƒฃ Run a full health scan qring health # Something not working? Diagnose the install (keyring, audit, MCP wiring) qring doctor # Tab completion for your shell qring completion zsh > ~/.zsh/completions/_qring # also: bash, fish ``` ## Quantum Features ### Superposition โ€” One Key, Multiple Environments A single secret can hold different values for dev, staging, and prod simultaneously. The correct value resolves based on your current context. ```bash # Set environment-specific values qring set API_KEY "sk-dev-123" --env dev qring set API_KEY "sk-stg-456" --env staging qring set API_KEY "sk-prod-789" --env prod # Value resolves based on context QRING_ENV=prod qring get API_KEY # โ†’ sk-prod-789 QRING_ENV=dev qring get API_KEY # โ†’ sk-dev-123 # Inspect the quantum state qring inspect API_KEY ``` ### Wavefunction Collapse โ€” Smart Environment Detection q-ring auto-detects your environment without explicit flags. Resolution order: 1. `--env` flag 2. `QRING_ENV` environment variable 3. `NODE_ENV` environment variable 4. Git branch heuristics (`main`/`master` โ†’ prod, `develop` โ†’ dev) 5. `.q-ring.json` project config 6. Default environment from the secret ```bash # See what environment q-ring detects qring env # Project config (.q-ring.json) echo '{"env": "staging", "branchMap": {"release/*": "staging"}}' > .q-ring.json ``` ### Quantum Decay โ€” Secrets with TTL Secrets can have a time-to-live. Expired secrets are blocked from reads. Stale secrets (75%+ lifetime) trigger warnings. ```bash # Set a secret that expires in 1 hour qring set SESSION_TOKEN "tok-..." --ttl 3600 # Set with explicit expiry qring set CERT_KEY "..." --expires "2026-06-01T00:00:00Z" # Health check shows decay status qring health ``` ### Observer Effect โ€” Audit Everything Every secret read, write, and delete is logged with a tamper-evident hash chain. Access patterns are tracked for anomaly detection. ```bash # View audit log qring audit qring audit --key OPENAI_KEY --limit 50 # Detect anomalies (burst access, unusual hours, chain tampering) qring audit --anomalies # Verify audit chain integrity qring audit:verify # Export audit log qring audit:export --format json --since 2026-03-01 qring audit:export --format csv --output audit-report.csv ``` ### Quantum Noise โ€” Secret Generation Generate cryptographically strong secrets in common formats. ```bash qring generate # API key (default) qring generate --format password -l 32 # Strong password qring generate --format uuid # UUID v4 qring generate --format token # Base64url token qring generate --format hex -l 64 # 64-byte hex qring generate --format api-key --prefix "sk-live-" --save STRIPE_KEY ``` ### Entanglement โ€” Linked Secrets Link secrets across projects. When you rotate one, all entangled copies update automatically. ```bash # Entangle two secrets qring entangle API_KEY API_KEY_BACKUP # Now updating API_KEY also updates API_KEY_BACKUP qring set API_KEY "new-value" # Unlink entangled secrets qring disentangle API_KEY API_KEY_BACKUP ``` ### Tunneling โ€” Ephemeral Secrets Create secrets that exist only in memory. They never touch disk. Optional TTL and max-read self-destruction. ```bash # Create an ephemeral secret (returns tunnel ID) qring tunnel create "temporary-token-xyz" --ttl 300 --max-reads 1 # Read it (self-destructs after this read) qring tunnel read tun_abc123 # List active tunnels qring tunnel list ``` ### Teleportation โ€” Encrypted Sharing Pack secrets into AES-256-GCM encrypted bundles for secure transfer between machines. Keys are derived with PBKDF2-HMAC-SHA512 (210 000 iterations) from your passphrase; each bundle records its iteration count, so bundles produced by older versions still unpack. ```bash # Pack secrets (prompts for passphrase) qring teleport pack --keys "API_KEY,DB_PASS" > bundle.txt # On another machine: unpack (prompts for passphrase) cat bundle.txt | qring teleport unpack # Preview without importing qring teleport unpack --dry-run ``` ### Import โ€” Bulk Secret Ingestion Import secrets from `.env` files directly into q-ring. Supports standard dotenv syntax including comments, quoted values, and escape sequences. The CLI accepts either a file path or raw content; the `import_dotenv` MCP tool only accepts raw content (it never reads files from disk) so an agent can't coerce it into reading arbitrary local files. ```bash # Import all secrets from a .env file qring import .env # Import to project scope, skipping existing keys qring import .env --project --skip-existing # Preview what would be imported qring import .env --dry-run ``` ### Selective Export Export only the secrets you need using key names or tag filters. ```bash # Export specific keys qring export --keys "API_KEY,DB_PASS,REDIS_URL" # Export by tag qring export --tags "backend" # Combine with format qring export --keys "API_KEY,DB_PASS" --format json ``` ### Secret Search and Filtering Filter `qring list` output by tag, expiry state, or key pattern. ```bash # Filter by tag qring list --tag backend # Show only expired secrets qring list --expired # Show only stale secrets (75%+ decay) qring list --stale # Glob pattern on key name qring list --filter "API_*" # Script-friendly existence check (exit 0 if present, 1 if not; decay-aware) qring has OPENAI_API_KEY --quiet && echo "configured" ``` ### Project Secret Manifest Declare required secrets in `.q-ring.json` and validate project readiness with a single command. ```bash # Validate project secrets against the manifest qring check # See which secrets are present, missing, expired, or stale qring check --project-path /path/to/project ``` ### Env File Sync Generate a `.env` file from the project manifest, resolving each key from q-ring with environment-aware superposition collapse. ```bash # Generate to stdout qring env:generate # Write to a file qring env:generate --output .env # Force a specific environment qring env:generate --env staging --output .env.staging ``` ### Secret References & Least-Privilege Run A `qring://` reference is a committable pointer to a secret โ€” it goes in your `.env` file instead of the value. `qring run` resolves references and manifest keys at spawn time, injecting **only what the project declares** (unlike `exec`, which injects the whole scope). Output is auto-redacted. ```bash # .env โ€” safe to commit: these are references, not values DATABASE_URL=qring://project/DATABASE_URL OPENAI_API_KEY=qring://global/OPENAI_API_KEY STRIPE_KEY=qring:///STRIPE_KEY # auto scope: project, then global SESSION_TTL=3600 # plain values pass through # Run with declared secrets injected (manifest + .env refs) qring run -- pnpm dev # Preview what would be injected, without running qring run --dry-run -- pnpm dev # Pin an environment, use a specific env file, or skip the manifest qring run --env prod --env-file .env.prod --no-manifest -- ./deploy.sh ``` The key lives in the **path**, never the host (`qring://project/KEY`, not `qring://KEY`) โ€” URL hosts are case-insensitive, and env-var keys are not. Malformed references fail loudly instead of leaking a literal `qring://โ€ฆ` string into the child. A reference pinned to an environment: `qring://project/DATABASE_URL?env=prod`. ### Editor Setup Wire the q-ring MCP server into an editor's MCP config with one command. Merges non-destructively โ€” other servers are preserved, and an existing q-ring entry is only replaced with `--force`. ```bash qring setup cursor # .cursor/mcp.json (project) or --global for ~/.cursor qring setup kiro # .kiro/settings/mcp.json, with read-only autoApprove list qring setup claude # .mcp.json (project scope) # Preview without writing qring setup cursor --dry-run ``` ### Push to Deployment Platforms Push manifest secrets to GitHub Actions, Vercel, or Cloudflare Workers through each platform's **own authenticated CLI** (`gh` / `vercel` / `wrangler`) โ€” q-ring never holds platform tokens, and values travel over stdin, never argv. Every push is recorded in the audit chain. ```bash # Push the .q-ring.json manifest keys to GitHub Actions secrets qring push github --repo you/your-app # Push to Vercel environments qring push vercel --vercel-env production,preview # Push to Cloudflare Workers secrets qring push cloudflare # Explicit keys, preview first qring push github --keys DATABASE_URL,API_KEY --dry-run ``` Canaries can ride along: `qring canary plant KEY --format aws --push github` plants a honeytoken locally and seeds it into the platform without reading it back (see Canary Honeytokens). ### Secret Liveness Validation Test if a secret is actually valid with its target service. q-ring auto-detects the provider from key prefixes (`sk-` โ†’ OpenAI, `ghp_` โ†’ GitHub, etc.) or accepts an explicit provider name. ```bash # Validate a single secret qring validate OPENAI_API_KEY # Force a specific provider qring validate SOME_KEY --provider stripe # Validate all secrets with detectable providers qring validate --all # Only validate manifest-declared secrets qring validate --all --manifest # List available providers qring validate --list-providers ``` **Built-in providers:** OpenAI, Anthropic, OpenRouter, Google AI (Gemini), Groq, Hugging Face, ElevenLabs*, Vercel*, Stripe, GitHub, AWS (format check), Generic HTTP. Keys are only ever sent in headers, never URLs. (*no safe public prefix โ€” select explicitly with `--provider` or the manifest `provider` field.) Output: ``` โœ“ OPENAI_API_KEY valid (openai, 342ms) โœ— STRIPE_KEY invalid (stripe, 128ms) โ€” API key has been revoked โš  AWS_ACCESS_KEY error (aws, 10002ms) โ€” network timeout โ—‹ DATABASE_URL unknown โ€” no provider detected ``` ### Hooks โ€” Callbacks on Secret Change Register webhooks, shell commands, or process signals that fire when secrets are created, updated, or deleted. Supports key matching, glob patterns, tag filtering, and scope constraints. ```bash # Run a shell command when a secret changes qring hook add --key DB_PASS --exec "docker restart app" # POST to a webhook on any write/delete qring hook add --key API_KEY --url "https://hooks.example.com/rotate" # Trigger on all secrets tagged "backend" qring hook add --tag backend --exec "pm2 restart all" # Signal a process when DB secrets change qring hook add --key-pattern "DB_*" --signal-target "node" # List all hooks qring hook list # Remove a hook qring hook remove # Enable/disable qring hook enable qring hook disable # Dry-run test a hook qring hook test ``` Hooks are fire-and-forget: a failing hook never blocks secret operations. The hook registry is stored at `~/.config/q-ring/hooks.json`. **SSRF protection:** HTTP hook URLs targeting private/loopback IP ranges (`127.0.0.0/8`, `10.0.0.0/8`, `172.16.0.0/12`, `192.168.0.0/16`, `169.254.0.0/16`, `::1`, `fc00::/7`) are blocked by default. DNS is checked up front *and* re-validated at connect time, so a hostname can't pass the check then rebind to a private address before the socket opens. To allow hooks targeting local services (e.g. during development), set the environment variable `Q_RING_ALLOW_PRIVATE_HOOKS=1`. ### Configurable Rotation Set a rotation format per secret so the agent auto-rotates with the correct value shape. ```bash # Store a secret with rotation format metadata qring set STRIPE_KEY "sk-..." --rotation-format api-key --rotation-prefix "sk-" # Store a password with password rotation format qring set DB_PASS "..." --rotation-format password ``` ### Secure Execution & Auto-Redaction Run commands with secrets securely injected into the environment. All known secret values are automatically redacted from stdout and stderr to prevent leaking into terminal logs or agent transcripts. Exec profiles restrict which commands may be run. ```bash # Execute a deployment script with secrets injected qring exec -- npm run deploy # Inject only specific tags qring exec --tags backend -- node server.js # Run with a restricted profile (blocks network tools and interpreters/shells, 30s timeout) qring exec --profile restricted -- npm test ``` ### Codebase Secret Scanner Migrating a legacy codebase? Quickly scan directories for hardcoded credentials using regex heuristics and Shannon entropy analysis. ```bash # Scan current directory qring scan . ``` Output: ``` โœ— src/db/connection.js:12 Key: DB_PASSWORD Entropy: 4.23 Context: const DB_PASSWORD = "..." ``` ### Composite / Templated Secrets Store complex connection strings that dynamically resolve other secrets. If `DB_PASS` rotates, `DB_URL` is automatically correct without manual updates. ```bash qring set DB_USER "admin" qring set DB_PASS "supersecret" qring set DB_URL "postgres://{{DB_USER}}:{{DB_PASS}}@localhost/mydb" # Resolves embedded templates automatically qring get DB_URL # Output: postgres://admin:supersecret@localhost/mydb ``` ### User Approvals (Zero-Trust Agent) Protect sensitive production secrets from being read autonomously by the MCP server without explicit user approval. Each approval token is HMAC-verified, scoped, reasoned, and time-limited. The gate applies to bulk reads too โ€” `export_secrets` and `teleport_pack` over MCP skip approval-protected keys that lack a valid grant. ```bash # Mark a secret as requiring approval qring set PROD_DB_URL "..." --requires-approval # Temporarily grant MCP access for 1 hour with a reason qring approve PROD_DB_URL --for 3600 --reason "deploying v2.0" # List all approvals with verification status qring approvals # Revoke an approval qring approve PROD_DB_URL --revoke ``` When an agent is blocked on an approval-protected key, q-ring raises a desktop notification (Linux `notify-send`, macOS `osascript`) naming the key and the exact `qring approve` command โ€” throttled per key, disabled with `QRING_NOTIFY=off`. ### Canary Honeytokens Plant fake credentials that look and read exactly like real ones. Anything that touches one โ€” a compromised MCP server, an over-curious agent, exfiltrated tooling sweeping the ring โ€” gets the fake value back with no tell, while q-ring fires a desktop alert and writes a `canary` event into the tamper-evident audit chain. ```bash # Plant a canary shaped like a real AWS access key qring canary plant AWS_SECRET_ACCESS_KEY --format aws # Other shapes: aws-secret, github, github-pat, openai, openai-project, # anthropic, stripe, gitlab, slack, google, npm, generic qring canary plant GHP_BACKUP_TOKEN --format github-pat # See what's been tripped qring canary list qring audit --action canary ``` Values are CSPRNG noise in the provider's real token shape (an `aws` canary matches `AKIA[A-Z0-9]{16}`, an `anthropic` one the real `sk-ant-api03-โ€ฆAA` layout) โ€” plausible enough to be taken, never valid. Alerts are throttled to one per key per 30 seconds; the audit trail records every read. **Get paged.** Desktop notifications only help when you are at the machine. Register webhook channels and every trip reaches them too: ```bash qring canary alert add --discord https://discord.com/api/webhooks/โ€ฆ qring canary alert add --slack https://hooks.slack.com/services/โ€ฆ qring canary alert add --ntfy https://ntfy.sh/my-canaries qring canary alert add --url https://example.com/canary # generic JSON POST qring canary alert list qring canary alert test # send a clearly-labelled drill ``` Channels live in `~/.config/q-ring/canary-alerts.json` (mode `0600`). Sends are fire-and-forget, SSRF-guarded like hooks, throttled with the desktop alert, and never include the fake value โ€” only the key, scope, source, and the agent label that reached for it. **Seed a tripwire into CI.** Plant a canary and push it to a deployment platform in one step, so a leaked GitHub Actions / Vercel / Cloudflare environment carries a decoy: ```bash qring canary plant AWS_SECRET_ACCESS_KEY --format aws-secret --push github --repo you/your-app ``` Honest caveat: q-ring only sees reads that go through q-ring. A leaked value used directly on the platform side is not observable here โ€” pair it with the provider's own alerting if you need that. Canaries are built to stay covert: they carry no identifying description (add an innocuous cover story with `--description` if you like), their flag never appears in MCP tool responses, and trip records are visible only from the operator's terminal โ€” never to agents via MCP audit tools. Bulk `export` and `delete` trip them just like reads, so sweeping the ring or removing the tripwire both ring the bell. Done with one? `qring canary disarm ` turns it back into an ordinary secret (`qring set` over a canary warns you first โ€” the flag deliberately survives overwrites so an agent can't launder it away). ### MCP Airlock Run a third-party MCP server behind q-ring. The airlock sits between your agent host and the wrapped server, spawns it with a **stripped environment** (no inherited API keys โ€” opt back in with `--inherit-env`), records every tool call, resource read, and prompt fetch that crosses it as a `wrap` event in the audit chain (grouped per session and labeled with the calling client's identity), **scrubs known secret values out of every result** before it reaches the transcript, and enforces the project's `policy.wrap` rules. Tool and prompt arguments are never logged โ€” they may contain secrets. ```json { "mcpServers": { "some-server": { "command": "qring", "args": ["mcp", "wrap", "--", "npx", "-y", "some-mcp-server"] } } } ``` Tools, resources, and prompts all pass through verbatim (pagination, progress notifications, cancellation, subscriptions, and the `list_changed` / `updated` notifications included); the airlock advertises exactly the capabilities the wrapped server has. Long-running tools are governed by the host's own timeout, with a generous airlock ceiling configurable via `QRING_WRAP_TIMEOUT_MS`. ```bash # Wrap a remote Streamable HTTP server; the Bearer token comes from q-ring (audited read) qring mcp wrap --url https://mcp.example.com/mcp --auth-secret EXAMPLE_MCP_TOKEN # Keep results verbatim (default: known secret values are replaced with [QRING:REDACTED]) qring mcp wrap --no-redact -- npx -y some-mcp-server ``` **Wrap policy.** Govern the wrapped server from `.q-ring.json` โ€” the same file, the same fail-closed engine: ```json { "policy": { "wrap": { "allowTools": ["github_*", "search"], "denyTools": ["github_delete_*"], "approveTools": ["github_merge_pr"], "rateLimit": { "maxCalls": 60, "perSeconds": 60 }, "toolRateLimits": { "search": { "maxCalls": 5, "perSeconds": 10 } }, "redactResults": true } } } ``` Denied tools are hidden from `tools/list` and refused on call with a `policy_deny` audit event; `approveTools` are refused until you grant them: ```bash qring mcp approve github_merge_pr --for 900 --reason "release 1.4" qring mcp approvals qring mcp approve github_merge_pr --revoke ``` Be clear about what the airlock is: env stripping, a tamper-evident record of every crossing, policy at the tool boundary, and best-effort redaction of secret *values* the ring knows about. It is **not a sandbox** โ€” the wrapped process still runs as your user with normal filesystem, network, and OS-keychain access, and tool descriptions pass through uninspected. See `docs/threat-model.md` for the honest boundary picture. ### Just-In-Time (JIT) Provisioning Instead of storing static credentials, configure `q-ring` to dynamically generate short-lived tokens on the fly when requested (e.g. AWS STS, generic HTTP endpoints). ```bash # Store the STS role configuration qring set AWS_TEMP_KEYS '{"roleArn":"arn:aws:iam::123:role/AgentRole", "durationSeconds":3600}' --jit-provider aws-sts # Resolving the secret automatically assumes the role and caches the temporary token qring get AWS_TEMP_KEYS ``` ### Project Context for AI Agents A safe, redacted overview of the project's secrets, configuration, and state. Designed to be fed into an AI agent's system prompt without ever exposing secret values. ```bash # Human-readable summary qring context # JSON output (for MCP / programmatic use) qring context --json ``` ### Secret-Aware Linter Scan specific files for hardcoded secrets with optional auto-fix. When `--fix` is used, detected secrets are replaced with `process.env.KEY` references and stored in q-ring. ```bash # Lint files for hardcoded secrets qring lint src/config.ts src/db.ts # Auto-fix: replace hardcoded values and store in q-ring qring lint src/config.ts --fix # Scan entire directory with auto-fix qring scan . --fix ``` ### Agent Memory Encrypted, persistent key-value store that survives across AI agent sessions. Useful for remembering rotation history, project decisions, or context. ```bash # Store a memory qring remember last_rotation "Rotated STRIPE_KEY on 2026-03-21" # Retrieve it qring recall last_rotation # List all memories qring recall # Forget qring forget last_rotation ``` ### Pre-Commit Secret Scanning Install a git pre-commit hook that automatically blocks commits containing hardcoded secrets. ```bash # Install the hook qring hook:install # Uninstall qring hook:uninstall ``` ### Secret Analytics Analyze usage patterns and get optimization suggestions for your secrets. ```bash qring analyze ``` Output includes most accessed secrets, unused/stale secrets, scope optimization suggestions, and rotation recommendations. ### Service Setup Wizard Quickly set up a new service integration with secrets, manifest entries, and hooks in one command. ```bash # Create secrets for a new Stripe integration qring wizard stripe --keys STRIPE_KEY,STRIPE_SECRET --provider stripe --tags payment # With a hook to restart the app on change qring wizard myservice --hook-exec "pm2 restart app" ``` ### Governance Policy Define project-level governance rules in `.q-ring.json` to control which MCP tools can be used, which keys are accessible, which commands can be executed, and what a wrapped MCP server may do behind the airlock. Policy is enforced at the MCP server, keyring, and airlock level. Over MCP, policy is resolved from the directory the server was **launched** in โ€” not from the `projectPath` a caller passes โ€” so an agent can't sidestep restrictions by pointing at a directory with no policy. Launch the MCP server from your project root (where `.q-ring.json` lives). Edits to `.q-ring.json` are picked up automatically (the policy cache invalidates on file change), so you don't need to restart the server. Policy files are schema-validated and **fail closed**: an invalid `policy` object (say, a typo like `denytools`) raises a `PolicyConfigError` instead of being silently ignored, so a malformed rule can never widen access. ```bash # View the active policy qring policy # JSON output qring policy --json ``` Example policy in `.q-ring.json`: ```json { "policy": { "mcp": { "denyTools": ["delete_secret"], "deniedKeys": ["PROD_DB_PASSWORD"], "deniedTags": ["production"] }, "exec": { "denyCommands": ["curl", "wget", "ssh"], "maxRuntimeSeconds": 30 }, "secrets": { "requireApprovalForTags": ["production"], "maxTtlSeconds": 86400 }, "wrap": { "denyTools": ["*_delete_*"], "approveTools": ["deploy_*"], "rateLimit": { "maxCalls": 60, "perSeconds": 60 } } } } ``` ### Exec Profiles Restrict command execution with named profiles that control allowed commands, network access, timeouts, and environment sanitization. ```bash # Run with the "restricted" profile (blocks network tools and interpreters/shells; 30s timeout) qring exec --profile restricted -- npm test # Run with the "ci" profile (5min timeout, allows network) qring exec --profile ci -- npm run deploy # Default: unrestricted qring exec -- echo "hello" ``` **Built-in profiles:** `unrestricted`, `restricted` (denies network tools *and* interpreters/shells โ€” `python -c`, `node -e`, `bash` and friends can't exfiltrate injected secrets; 30s limit), `ci` (5min limit, blocks destructive commands). ### Tamper-Evident Audit Every audit event includes a SHA-256 hash of the previous event, creating a tamper-evident chain. Since v0.14 the chain is also anchored with a keyed HMAC stored in the OS keyring, so `qring audit:verify` detects truncation and whole-file rewrites โ€” not just in-place edits. Verify integrity and export logs in multiple formats. Events from MCP sessions are additionally stamped with the connecting client's self-reported identity (`clientInfo` name@version) โ€” shown in `qring audit` output and filterable with `qring audit --agent