{"id":51414080,"url":"https://github.com/spences10/nopeek","last_synced_at":"2026-07-04T17:30:41.554Z","repository":{"id":349020687,"uuid":"1200563652","full_name":"spences10/nopeek","owner":"spences10","description":"CLI for LLM agent secret safety — load env secrets without exposing values","archived":false,"fork":false,"pushed_at":"2026-06-19T20:33:46.000Z","size":247,"stargazers_count":11,"open_issues_count":7,"forks_count":1,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-19T22:14:16.937Z","etag":null,"topics":["agents","cli","coding-agents","env","llm","redaction","secrets","security"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/spences10.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-04-03T15:04:10.000Z","updated_at":"2026-06-19T20:31:04.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/spences10/nopeek","commit_stats":null,"previous_names":["spences10/nopeek"],"tags_count":13,"template":false,"template_full_name":null,"purl":"pkg:github/spences10/nopeek","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spences10%2Fnopeek","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spences10%2Fnopeek/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spences10%2Fnopeek/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spences10%2Fnopeek/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/spences10","download_url":"https://codeload.github.com/spences10/nopeek/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/spences10%2Fnopeek/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":35130722,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-07-04T02:00:05.987Z","response_time":113,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["agents","cli","coding-agents","env","llm","redaction","secrets","security"],"created_at":"2026-07-04T17:30:40.907Z","updated_at":"2026-07-04T17:30:41.549Z","avatar_url":"https://github.com/spences10.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# nopeek\n\n[![built with vite+](https://img.shields.io/badge/built%20with-Vite+-646CFF?logo=vite\u0026logoColor=white)](https://viteplus.dev)\n[![tested with vitest](https://img.shields.io/badge/tested%20with-Vitest-6E9F18?logo=vitest\u0026logoColor=white)](https://vitest.dev)\n\nCLI for LLM agent secret safety. nopeek loads environment secrets for\ncoding agents without exposing secret values in tool output or chat\ncontext. Agents see key _names_, not key _values_.\n\n## Quick Start\n\nIn an LLM coding session, tell the agent to use nopeek:\n\n```\n\"run npx nopeek load .env then use $DATABASE_URL to query the users table\"\n\n\"use npx nopeek load .env --only STRIPE_KEY and then curl the billing API\"\n\n\"run npx nopeek load .env --only API_KEY,API_SECRET and test the auth endpoint\"\n```\n\nThe agent runs the command, gets back only the key name, and uses the\nvariable in subsequent commands without seeing the actual value.\n\n## How It Works\n\nShell command output visible to an LLM coding agent may be sent to a\nmodel provider and retained by that provider. nopeek prevents secrets\nfrom appearing in that output.\n\n**Step 1.** Tell your agent to use nopeek. It just needs to run the\ncommand; it will self-discover subcommands and flags from the CLI\noutput:\n\n```bash\nnpx nopeek load .env --only DATABASE_URL\n```\n\n**Step 2.** nopeek injects the value into the session environment and\nprints only the key name:\n\n```\nLoaded 1 key from .env: DATABASE_URL\n```\n\n**Step 3.** The agent can now use the variable by name without ever\nseeing the value:\n\n```bash\npsql $DATABASE_URL -c \"SELECT count(*) FROM users\"\n```\n\n\u003e **Important:** Your agent does not know about nopeek unless you\n\u003e mention it. You do not need to spell out the full command, just\n\u003e mention `{npx,pnpx,bunx} nopeek` and the agent can discover the\n\u003e rest.\n\n### Optional agent reminders\n\nIf you use a harness with persistent system-prompt extensions, add a\nsmall reminder so the model reaches for nopeek automatically instead\nof needing the Quick Start text in every prompt. For Pi users, the\n`@spences10/pi-nopeek` extension does this:\n\n```bash\npi install npm:@spences10/pi-nopeek\n```\n\n[`my-pi`](https://github.com/spences10/my-pi) already includes this\nreminder by default. This is optional: nopeek remains harness-agnostic\nand still works anywhere when you mention it in the session.\n\nThree modes depending on environment:\n\n| Context                                       | What happens                                                       |\n| --------------------------------------------- | ------------------------------------------------------------------ |\n| Agent session with env-file injection support | Writes directly to env file; future commands can use the variables |\n| Agent session without env-file injection      | Writes to temp file and outputs a `source` command                 |\n| Regular shell                                 | Prints `export` statements for `eval`                              |\n\nWhen env-file injection is unavailable, `load` cannot mutate the\nparent shell or future unrelated shell processes. Use the reported\n`next_command`, or run your command in the same shell after sourcing\nor evaluating the output.\n\n## Usage\n\nNo install needed. Your agent runs it directly via `npx`:\n\n```bash\nnpx nopeek load .env\nnpx nopeek load .env --only DATABASE_URL\nnpx nopeek run .env --only API_KEY -- sh -c 'curl -H \"Authorization: Bearer $API_KEY\" https://api.example.com'\nnpx nopeek set MY_API_KEY --from-env\nnpx nopeek status\n```\n\nAll commands are designed to be run inside an LLM coding session. Just\nmention `nopeek` in your prompt. The agent will discover the right\nsubcommand from the CLI output.\n\n## Commands\n\n### `load` - Load secrets from .env or .tfvars files\n\n```bash\nnpx nopeek load .env\nnpx nopeek load .env --only DATABASE_URL,API_KEY\nnpx nopeek load .env --shell bash  # eval/source-safe shell output\nnpx nopeek load .env --persist  # also save to config for future sessions\nnpx nopeek load terraform.tfvars --only prod_password\nnpx nopeek load production.tfvars.json --only db_password\n```\n\nSupported formats:\n\n| Extension        | Format                        |\n| ---------------- | ----------------------------- |\n| `.env`, `.env.*` | `KEY=value`                   |\n| `.tfvars`        | `key = \"value\"` (HCL strings) |\n| `.tfvars.json`   | JSON top-level strings        |\n\nFor `.tfvars` files, only top-level quoted string values are loaded.\nMaps, lists, numbers, and booleans are skipped.\n\nThe `--persist` flag saves keys to `~/.config/nopeek/config.json` so a\nSessionStart hook can auto-inject them on future sessions.\n\n`load` returns a `method` field in JSON output. If `method` is\n`env_file`, the keys are available to future session commands. If\n`method` is `export` or `source_file`, the keys are not available\nuntil you evaluate the returned `next_command`, for example:\n\n```bash\neval \"$(npx nopeek load .env --shell bash)\"\nsource \u003c(npx nopeek load .env --shell bash)\nnpx nopeek load .env --shell fish | source\n```\n\n`--shell` supports `bash`, `zsh`, and `fish`. Shell assignments are\nwritten to stdout for the shell to consume; status/progress messages\ngo to stderr.\n\n### `run` - Run one command with loaded secrets\n\n```bash\nnpx nopeek run .env --only API_KEY -- node ./script.js\nnpx nopeek run .env --only INGEST_TOKEN,FEEDGEN_SERVICE_URL -- sh -c 'curl -H \"Authorization: Bearer $INGEST_TOKEN\" \"$FEEDGEN_SERVICE_URL\"'\nnpx nopeek run terraform.tfvars --only prod_password -- ./deploy.sh\nnpx nopeek run production.tfvars.json --only DATABASE_URL -- sh -c 'psql \"$DATABASE_URL\" -c \"select 1\"'\n```\n\n`run` injects selected keys into only the child process environment\nand preserves the child command exit code. Use `sh -c` when you need\nshell expansion, pipes, redirects, or inline `$VARIABLE` expansion\ninside the child process.\n\n### `set` - Store a secret key\n\n```bash\nnpx nopeek set MY_API_KEY --from-env  # read from current shell env\nnpx nopeek set MY_API_KEY             # interactive prompt (TTY only)\n```\n\nStores to `~/.config/nopeek/config.json` with `0600` permissions. This\nis plaintext at rest; use `set`/`--persist` only for secrets you are\ncomfortable storing in your user config.\n\n\u003e **Note:** `--value` is rejected inside detected LLM agent sessions.\n\u003e The value would appear in the conversation. Use `--from-env`\n\u003e instead.\n\n### `list` - Show available keys\n\n```bash\nnpx nopeek list\n```\n\nShows key names and sources without values.\n\n### `remove` - Remove a stored key\n\n```bash\nnpx nopeek remove MY_API_KEY\n```\n\n### `init` - Scan and configure cloud CLIs\n\n```bash\nnpx nopeek init\n```\n\nDetects installed cloud CLIs, checks their auth configuration, and\nstores profile mappings.\n\n| CLI      | Safer pattern                                        | Detection                                          |\n| -------- | ---------------------------------------------------- | -------------------------------------------------- |\n| `aws`    | Named profiles (`AWS_PROFILE`)                       | `~/.aws/credentials` + env vars                    |\n| `hcloud` | Named contexts (`HCLOUD_CONTEXT`)                    | `~/.config/hcloud/cli.toml`                        |\n| `gcloud` | Named configurations (`CLOUDSDK_ACTIVE_CONFIG_NAME`) | active gcloud account + inline credential env vars |\n| `az`     | Azure CLI cached login + active subscription         | `az account show` + inline credential env vars     |\n\n### `status` - Show current state\n\n```bash\nnpx nopeek status\n```\n\nShows session type, stored keys, CLI profiles, and detected CLIs.\n\n### `audit` - Scan for exposed secrets\n\n```bash\nnpx nopeek audit\nnpx nopeek audit ./path/to/dir\n```\n\nScans for `.env` files and reports secrets found using pattern\nmatching (AWS keys, bearer tokens, API keys, private keys, connection\nstrings, etc.). Checks `.gitignore` coverage.\n\n## Security\n\n- **Key name validation** - env key names are validated against\n  `^[a-zA-Z_][a-zA-Z0-9_]*$` to prevent shell injection\n- **Secure file permissions** - config dir is `0700`, config file is\n  `0600`, temp env files are `0600`\n- **Atomic writes** - config is written via temp file + rename to\n  prevent corruption\n- **Key validation before output** - invalid env names are rejected\n  before shell exports are printed\n- **No values in stdout** - in detected agent sessions, values are\n  written to env files or temp files; only `source` paths or key names\n  reach stdout\n- **Plaintext config warning** - persisted keys are local plaintext\n  secrets protected by file permissions, not encryption\n\n## Recommended Agent Deny Rules\n\nnopeek is the primary defense, but deny rules are a useful safety net\nin any agent runtime that supports them. Block the agent from reading\nsecret files or embedding credentials inline in commands:\n\n```jsonc\n{\n\t\"permissions\": {\n\t\t\"deny\": [\n\t\t\t// Block reading secret files\n\t\t\t\"Read(.env)\",\n\t\t\t\"Read(*.env)\",\n\t\t\t\"Read(*.tfvars)\",\n\t\t\t\"Read(*credentials*)\",\n\t\t\t\"Read(*secret*)\",\n\t\t\t\"Read(**/.config/gcloud/**)\",\n\t\t\t\"Read(**/.azure/**)\",\n\t\t\t\"Read(*service-account*.json)\",\n\n\t\t\t// Block cat/head on secret files\n\t\t\t\"Bash(cat .env)\",\n\t\t\t\"Bash(cat *.env*)\",\n\t\t\t\"Bash(cat *tfvars*)\",\n\t\t\t\"Bash(cat *credentials*)\",\n\t\t\t\"Bash(cat *secret*)\",\n\n\t\t\t// Block inline credentials in commands\n\t\t\t\"Bash(PGPASSWORD*)\",\n\t\t\t\"Bash(*HCLOUD_TOKEN*)\",\n\t\t\t\"Bash(hcloud context create*)\",\n\t\t\t\"Bash(*GOOGLE_APPLICATION_CREDENTIALS*)\",\n\t\t\t\"Bash(*CLOUDSDK_AUTH_ACCESS_TOKEN*)\",\n\t\t\t\"Bash(*GOOGLE_OAUTH_ACCESS_TOKEN*)\",\n\t\t\t\"Bash(*AZURE_CLIENT_SECRET*)\",\n\t\t\t\"Bash(*ARM_CLIENT_SECRET*)\",\n\t\t\t\"Bash(*AZURE_PASSWORD*)\",\n\t\t\t\"Bash(*AZURE_ACCESS_TOKEN*)\",\n\t\t\t\"Bash(*ARM_ACCESS_KEY*)\",\n\n\t\t\t// Block fetching secret values from cloud providers\n\t\t\t\"Bash(*secretsmanager get-secret-value*)\",\n\t\t\t\"Bash(*hetzner*secret*)\",\n\t\t\t\"Bash(*hetzner*access_key*)\",\n\t\t\t\"Bash(gcloud auth print-access-token*)\",\n\t\t\t\"Bash(gcloud auth application-default print-access-token*)\",\n\t\t\t\"Bash(az account get-access-token*)\",\n\t\t],\n\t},\n}\n```\n\nWithout these rules, an agent can still read a `.tfvars` or `.env`\nfile directly and hardcode the values into a shell command. nopeek\nprevents secrets from appearing in _output_, but deny rules prevent\nthe agent from _reading_ the files in the first place.\n\n## Limitations\n\n- **Pattern-based secret detection is best-effort.** The audit\n  patterns catch known formats but cannot catch every possible secret.\n- **Agent detection is marker-based.** nopeek detects common agent\n  environment markers and env-file injection, but no CLI can guarantee\n  every harness is identified.\n- **Temp files exist on disk briefly.** Written to `/tmp/nopeek/` with\n  `0600` perms, but values are on disk until the file is cleaned up.\n- **Persisted keys are plaintext.** `set` and `load --persist` store\n  values in `~/.config/nopeek/config.json` with `0600` permissions.\n- **Output redaction is not comprehensive.** Prefer loading secrets as\n  environment variables so values never need to be printed.\n\n## License\n\nMIT\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspences10%2Fnopeek","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fspences10%2Fnopeek","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fspences10%2Fnopeek/lists"}