omp packages

@sidshaytay/pi-secret-safe0.2.1

Pi extension that keeps secrets out of model context, provider requests, tool output, and session history.

sidshaytay Published 5 days ago MIT ~278 downloads/mo

Untested on omp

This is a pi package. No one has reported whether it works on omp yet. If you try it, add your result below.

Did it work for you?

Result

One report per person. A new report replaces your old one.

Reports 0

No reports yet.

Readme

@sidshaytay/pi-secret-safe

A pi extension that keeps secret values out of model context, the outbound provider request, tool output, and session history — while still letting the agent use those secrets in bash commands.

What it does

pi-secret-safe discovers secret values from environment variables and dotenv files, replaces them with placeholders the model can see, and exports the real values into the shell environment. The model reads and writes the placeholder; when a command runs, the shell substitutes the real value, so the secret never enters the conversation.

The model sees a placeholder like this:

«Redacted — read as environment variable $NAME via script»

NAME is the secret's variable name — OPENAI_API_KEY, DB_PASSWORD, or a generated SECRET_* name for values matched by a pattern. The model references $OPENAI_API_KEY in a bash command, and the shell expands it at run time. The placeholder avoids quotes, backslashes, colons, and equals signs, so it stays valid when it lands inside a JSON, YAML, or TOML string value. Short values found in URL credentials are hidden in URLs, but not in unrelated words that happen to contain the same letters.

Quick start

Install the package:

pi install npm:@sidshaytay/pi-secret-safe

Load it from a local checkout instead:

pi -e ./packages/pi-secret-safe/extensions/index.ts

If you edit the extension source while pi is running, run /reload in pi to pick up the changes.

Put the secrets you want protected in a dotenv file in your project, or in the environment before you start pi:

# .env
OPENAI_API_KEY=sk-...
DATABASE_URL=postgres://user:password@host/db

Then check what it found:

/secret-safe

Usage

Modes

Mode Behavior
redact (default) Redact secrets everywhere. Block nothing.
strict Redact, and additionally block reads, writes, edits, and greps of sensitive paths, sensitive bash commands, and bash commands or write/edit content carrying secret literals. When a UI is available and promptOnBlock is true, you are asked to allow once or deny.
off The extension does nothing for the session.

Switch modes with a command, or set the default in a config file.

Commands

Command Does
/secret-safe Same as /secret-safe status
/secret-safe status Show mode, protected secret count, placeholder count, redaction and block counters, the loaded config files, and any config errors
/secret-safe strict Switch to strict mode
/secret-safe redact Switch to redact mode
/secret-safe off Disable for this session
/secret-safe rescan Re-read dotenv files and environment

Configuration

pi-secret-safe reads JSON from two files, lowest precedence first:

  1. ~/.pi/agent/secret-safe.json
  2. <project>/.pi/secret-safe.json

The array keys patterns, allowPaths, blockPaths, and extraBlockCommands accumulate across both files. Every other key, including dotenvFiles, overrides: the project file wins over the user file. Invalid values fall back to their defaults and are reported by /secret-safe status.

Key Default Meaning
mode "redact" "redact", "strict", or "off"
dotenvFiles [".env", ".env.local", ".env.development", ".env.development.local"] Dotenv filenames to read, relative to the session directory
patterns [] Extra regex rules for secret formats the built-in table does not cover
allowPaths [] Strict mode: paths that are always allowed, overriding built-in rules
blockPaths [] Strict mode: paths that are always blocked, overriding built-in rules
extraBlockCommands [] Strict mode: extra regex sources that make a bash command blockable
scanEnv true Discover secrets from the process environment
exportToShell true Export discovered secrets into the shell environment so bash can reference them by name. When false, secrets are still redacted, but the placeholder's $NAME form will not expand in bash, so the agent cannot use those values
minValueLength 8 Minimum value length for a name-matched env or dotenv value to count as a secret
promptOnBlock true In strict mode, ask before denying when a UI is available

Each patterns item is an object with name, regex, and an optional flags:

{
  "patterns": [
    { "name": "INTERNAL_TOKEN", "regex": "tok_[a-z0-9]{24}" }
  ]
}

Example project config:

{
  "mode": "strict",
  "dotenvFiles": [".env", ".env.local"],
  "allowPaths": ["docs/fixtures/**"],
  "extraBlockCommands": ["vault\\s+read"]
}

Troubleshooting

The agent can't use a secret in bash. The value is exported into the shell environment by its variable name, not inlined into the command. If exportToShell is false, set it back to true in secret-safe.json and run /secret-safe rescan. The agent must reference $OPENAI_API_KEY, not the literal value — a literal value in a command cannot be expanded, and in strict mode it is blocked as a secret literal.

Strict mode blocks something it shouldn't. Turn the extension off for the session with /secret-safe off. To keep strict mode, add the path to allowPaths, or refine detection with a patterns entry.

Config isn't loading. Run /secret-safe and check the path it prints. Confirm the file is at ~/.pi/agent/secret-safe.json or <project>/.pi/secret-safe.json, that its JSON parses, and that each key uses the type in the table above. Invalid values fall back to defaults and appear in the /secret-safe output.

What it does not protect

  • Detection is heuristic. It matches exact values plus a pattern table. An unusual secret format that is neither in the environment or dotenv files nor matched by a pattern can pass through.
  • Image content is never redacted.
  • Files on disk are unchanged. Secrets written into files the agent reads are redacted at read time, but the file still holds the real value. Rotating a leaked credential is the only real remedy.
  • Nothing outside the session. It does not manage pi debug logs, terminal scrollback, or shell history.
  • Blocking is a guard, not proof. Strict mode blocks operations and redact mode rewrites content. Neither proves a secret never existed.
  • A user-run command is stored as typed. A ! or !! command is recorded in session history exactly as entered, so a secret typed literally into the command itself is stored, while its output is redacted as it is produced.
  • User command output redaction is line-buffered. A secret that spans multiple lines and is not recognised as a private-key block can partially survive in the session file.
  • Other extensions can write ahead of us. A message injected by another extension through pi's sendMessage API is written to the session file before this extension can inspect it.
  • A thrown redaction hook fails open. pi logs the error and the original content continues unredacted.
  • Generic assignment rules stop at punctuation. They end at #, ,, ;, }, and ], so when a value is not already known from the environment or a dotenv file, a tail after one of those characters can stay visible.

How it hooks into pi

pi-secret-safe registers these hooks:

Hook Runs when Does
session_start A session starts Load config, discover secrets, refresh the redactor, export secrets to the shell environment
before_agent_start Before the agent starts Append system-prompt guidance explaining placeholders and safe $VAR usage
input User input arrives Redact secret values before they enter the conversation
context Before each model request Redact every conversation message
before_provider_request Before the request leaves Redact the final provider payload as a last line of defence
tool_result A tool returns Redact tool output, including SSH config metadata and private keys that arrive in chunks
message_end A message is finalized Redact the message so session history on disk is scrubbed
tool_call Before a tool runs In strict mode, block reads, writes, edits, and greps of sensitive paths and calls whose command or content carries a secret literal
user_bash Before a user bash command runs In strict mode, block commands that would expose secrets; otherwise redact the command's output as it streams, before pi records it

Credits

pi-secret-safe merges ideas and code adapted from several MIT-licensed projects. See CREDITS.md.

License

MIT