Move secrets from credential providers without printing them
Project description
ainv
ainv is a small, provider-neutral CLI for moving secrets without printing them.
It is intended for humans and shell-capable coding agents that need to:
- add credentials to an existing provider through hidden human input;
- search credential stores using non-sensitive metadata;
- write a selected credential directly into an environment file; and
- inject selected credentials into one child process.
ainv is not a vault, daemon, cloud service, or MCP server. Credential providers
remain the source of truth.
[!IMPORTANT] This project is an early development preview. The current release supports non-synchronizable generic passwords in the default macOS Keychain only.
The proposed product and security contract is documented in SPEC.md.
Installation
[!WARNING] Version 0.1.0 is a pre-alpha name-reservation and evaluation release. In the current
uv tooldistribution, macOS Keychain trusts the uv-managed Python interpreter, not theainvcommand. Do not treat it as a stable, least-privilege identity for unattended high-value credentials. See SECURITY.md before choosing Keychain approval.
Install the published package with:
uv tool install ainv
For development from a local checkout:
uv tool install .
Usage
Add a native Keychain credential through one hidden input prompt:
ainv add OPENAI_API_KEY --provider keychain --account personal
--label is optional. Existing credentials are never overwritten. A human may
paste a newly issued credential from a browser into the hidden prompt. Agents
must never read, inspect, or manipulate the clipboard. On success, the full
opaque reference is labeled Reference (non-secret identifier) so it is not
mistaken for a credential value.
Search Keychain metadata without retrieving secret values:
ainv find openai
ainv find openai --json
Use the opaque reference returned by find to set one dotenv entry:
ainv set 'keychain://v1/item/REFERENCE' --as OPENAI_API_KEY --file .env
Or inject it into one child process without touching disk:
ainv run 'OPENAI_API_KEY=keychain://v1/item/REFERENCE' -- command
set refuses tracked or non-ignored Git destinations unless explicitly
overridden. Run ainv <command> --help for all options.
[!WARNING]
ainv runkeeps resolved values out of its normal arguments and output, but it gives them to the selected process. That process, its descendants, dependencies, crash reporters, telemetry, and anything it invokes can read, retain, transmit, or expose them. Use it only for an intended, trusted consumer and avoid debug or environment-dumping modes. This is guidance, not an enforcement boundary:ainvdoes not make untrusted agents, repositories, dependencies, or commands safe.
The command surface will not include a generic operation that prints a resolved secret.
References and cleanup
A Keychain reference is an opaque local locator, not portable project configuration or a unique identifier for one immutable credential incarnation. It may become stale after identity metadata changes or deletion. If it no longer resolves, search again rather than reconstructing it from metadata.
For private dogfood, remove an ainv-created Keychain item manually in Keychain
Access by its service, account, and label. Remove a materialized dotenv entry
manually without asking an agent to read the file. If a credential is exposed,
revoke or rotate it with its remote issuer first. Removing the local Keychain
item does not revoke it remotely.
Agent skill
The repository includes an optional agent skill at skills/ainv.
Install it into the canonical shared skills directory with:
mkdir -p ~/.agents/skills
ditto skills/ainv ~/.agents/skills/ainv
Claude Code additionally needs a discovery symlink:
ln -s ~/.agents/skills/ainv ~/.claude/skills/ainv
Development
Requires Python 3.13 and uv.
uv sync
uv run pytest
uv run ruff check .
uv run ruff format --check .
Security model
ainv reduces accidental credential exposure by keeping resolved values out of
its normal arguments and output. Once a secret is written to a file or injected
into a child process, it can be read, retained, printed, transmitted, or exposed
by that process, its descendants, dependencies, crash reporters, telemetry, or
anything it invokes. Child stdout and stderr pass through unchanged. ainv
does not make untrusted agents, repositories, dependencies, or commands safe.
License
No license has been granted yet. The published pre-alpha package is available for evaluation, but permission to copy, modify, or redistribute it has not been granted.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file ainv-0.1.0.tar.gz.
File metadata
- Download URL: ainv-0.1.0.tar.gz
- Upload date:
- Size: 18.4 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
6a5b9fdf7d1255729b002bd162b4497b5c9e6e15a3b86b6148e33e994991a7fe
|
|
| MD5 |
43b44a9834cc25f87f2097bd2a91f3fb
|
|
| BLAKE2b-256 |
285cc270429cfb279929b767af7eff94db7627da37a114dfd9541c8fbe5a7a8a
|
File details
Details for the file ainv-0.1.0-py3-none-any.whl.
File metadata
- Download URL: ainv-0.1.0-py3-none-any.whl
- Upload date:
- Size: 22.9 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: uv/0.11.26 {"installer":{"name":"uv","version":"0.11.26","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"macOS","version":null,"id":null,"libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":null}
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
fafa92924f10ce96b1b65e6262b03ae31c5109bdd2b8aceac894d2a06742684d
|
|
| MD5 |
eb515a17e778845c6f095758e73e7d72
|
|
| BLAKE2b-256 |
22daaf5302890942f7455071654f03ed954e75bec6e4898d5b2001336b8e30e1
|