Commands Reference

trustless secret — Credential Store Operations

SubcommandDescriptionExample
listList all available credential keystrustless secret list
get <key>Retrieve a credential value (JSON output)trustless secret get github_token
set <key> [value]Store a new credential (wraps pass insert)trustless secret set openai_key sk-...

get outputs JSON by default:

{"key": "github_token", "value": "ghp_..."}

trustless oauth — OAuth Credential Management

Manage OAuth credentials (RFC 8628 device flow + refresh grant) for providers like Google and Lark. trustless oauth login runs the device authorization flow and stores the resulting tokens as a compact single-line JSON entry (type=oauth) in the credential backend. The entry is then resolved like any other credential — trustless run -s <key> / trustless proxy return a fresh access token, with automatic refresh on expiry.

SubcommandDescriptionExample
login <provider> <key>Device flow login; stores the OAuth entrytrustless oauth login google api/google
refresh <key>Force refresh the OAuth entry (ignore cache)trustless oauth refresh api/google
status <key>Show entry status (valid / expired / reauth_required)trustless oauth status api/google
providersList configured providerstrustless oauth providers

login prints the verification URL to stdout, then polls until the user approves:

$ trustless oauth login google api/google
https://oauth2.googleapis.com/device/code?user_code=ABCD-1234   # open this in a browser
{"key":"api/google","provider":"google","expires_at":"2026-08-13T12:00:00Z"}

refresh force-refreshes the access token without waiting for expiry; the access token value is never printed. status reports valid when the token is still fresh, and reauth_required when the refresh token is revoked (invalid_grant):

$ trustless oauth status api/google
{"key":"api/google","provider":"google","expires_at":"...","status":"valid"}

Configuration ([oauth.providers]): define a provider with its token/device endpoints and credentials. The built-in google and lark definitions ship with the endpoints below — you only need to fill in client_id / client_secret (register the app in the provider’s developer console) and any additional scopes:

[oauth.providers.google]
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
scopes = ["https://www.googleapis.com/auth/gmail.readonly"]

[oauth.providers.lark]
client_id = "YOUR_CLIENT_ID"
client_secret = "YOUR_CLIENT_SECRET"
# scopes 未設定時は既定の offline_access が使われる(refresh token 取得に必須)
ProviderDevice authorization endpointToken endpointDevice authToken request
googlehttps://oauth2.googleapis.com/device/codehttps://oauth2.googleapis.com/tokenbody (client_secret in form body)form
larkhttps://accounts.larksuite.com/oauth/v1/device_authorizationhttps://open.larksuite.com/open-apis/authen/v2/oauth/tokenbasic (Authorization header)json (Lark code-style response)

client_id / client_secret are registered in the provider’s developer console (Google Cloud Console / Lark Open Platform) — never commit them. OAuth entries in the backend store only the tokens, never the client credentials.

trustless audit — Structured Audit Log

All events (proxy injection/deny, run spawn, DLP redaction, OAuth refresh/failure/reauth) are recorded as JSONL. No token or secret values ever appear in events — only key names, hosts, verdicts, and small details.

SinkWhereDefault
journaldserve (stdout JSONL → systemd journald)serve
fileappend-only ~/.local/state/trustless/audit.jsonl (0600, SIGHUP-reopen for logrotate)run / proxy / oauth
offdiscard
[audit]
sink = "file"        # "journald" | "file" | "off"(未設定はコマンド別デフォルト)
file = "~/.local/state/trustless/audit.jsonl"
buffer = 1024
$ journalctl --user -u trustless | grep '"event"'
{"ts":"...","event":"proxy.inject","key":"edinet","host":"api.edinet-fsa.go.jp","verdict":"inject","detail":"header=Ocp-Apim-Subscription-Key"}
{"ts":"...","event":"oauth.refresh","key":"iria/api/lark-oauth","verdict":"refresh","detail":"provider=lark"}

Events: proxy.inject / proxy.deny / run.spawn / dlp.redact / oauth.refresh / oauth.fail / oauth.reauth_required.

Notes:

  • Access tokens are cached in memory (validity minus a 60s safety margin); refresh happens automatically on Resolve when expired.
  • When a provider rotates the refresh token (Lark), the updated entry is written back with a CAS guard so a concurrent writer is never overwritten.
  • invalid_grant (revoked refresh token) is not retried — re-run trustless oauth login to re-authenticate.

trustless run — Subprocess Credential Injection (Core Command)

Run a command with one or more credentials injected as environment variables. The injected values are never returned to the caller — only the subprocess stdout/stderr, and any matching credential patterns are redacted.

trustless run -s iria/api/xai -- curl -s https://api.x.ai/v1/models
trustless run -s GITHUB_TOKEN -s OPENAI_KEY -- gh pr list

How it works:

  1. trustless resolves each -s key from the backend
  2. Spawns the subprocess with the credential value set as an environment variable
  3. The environment variable name is derived from the last path segment of the key, converted to UPPER_SNAKE_CASE (e.g. iria/api/xaiXAI)
  4. Forwards stdin to the subprocess and streams stdout/stderr
  5. Scans output (line by line) for credential patterns and redacts matches with [REDACTED]
  6. Returns sanitized output to the caller

Security features:

  • --scan-args (default: true): Before spawning the subprocess, all command arguments are scanned for credential patterns and injected values. If detected, execution is blocked with exit code 3 (fail closed). This prevents the agent from accidentally exposing credential values in CLI arguments like curl -H "Authorization: Bearer ***".
  • --sanitize (default: true): Scans and redacts credential patterns from subprocess output.
  • Policy engine: Command-level access control (see configuration section).

stdio protocols (ACP / MCP / LSP): stdin is always forwarded to the child (fixed 2026-07-31), and output is sanitized line-by-line in real time so long-running processes (ACP servers, gateways) flush output instead of buffering until exit. For interactive JSON-RPC stdio servers, sanitizing the stream can corrupt protocol messages — pass --sanitize=false for those (e.g. hermes acp).

FlagDescription
-s, --secret <key>Credential key to inject (repeatable, format: KEY or KEY:ENVNAME)
--sanitizeEnable output scanning/redaction (default: on)
--sanitize-policy <file>Custom redaction patterns file
--scan-argsScan command arguments for credential patterns before spawning (default: on)
--jsonOutput as JSON {"exit_code": N, "stdout": "...", "stderr": "..."}
--timeout <duration>Subprocess timeout (default: 5m)

trustless proxy — HTTP Forward Proxy with Credential Injection

Start a local HTTP forward proxy that injects credentials into requests based on the destination host. The agent sends plain requests — no placeholder syntax, no knowledge of the key.

trustless proxy start --port 8080
trustless proxy start --port 8080 --mitm  # HTTPS interception mode

Configure your agent to use the proxy:

export HTTPS_PROXY=http://127.0.0.1:8080

Injection rules (config [proxy.rules]): map a host to a credential injected as a header or query parameter. The header/parameter is injected only when absent; unresolved keys fail open (no injection).

[proxy.rules]
# Header injection (e.g. LLM APIs, EDINET)
"api.x.ai" = { header = "Authorization", key = "xai", prefix = "Bearer " }
"api.edinet-fsa.go.jp" = { header = "Ocp-Apim-Subscription-Key", key = "edinet" }
# Query parameter injection (e.g. e-Stat, Alpha Vantage)
"statdb.nstac.go.jp" = { query = "appid", key = "estat" }
"www.alphavantage.co" = { query = "apikey", key = "alphavantage/mcp-key" }
  • header / query: injection target (exactly one per rule)
  • key: credential key (resolution: lowercase → pass, fallback iria/api/<key>)
  • prefix / suffix: header value wrapping (e.g. Bearer prefix)

Egress allowlist (config proxy.allowlist): when set, only listed hosts are permitted through the proxy; all other requests are rejected with 403 Forbidden. Empty/absent = all hosts allowed.

[proxy]
allowlist = ["api.x.ai", "api.edinet-fsa.go.jp"]

Hot reload (SIGHUP): rule/allowlist changes and credential rotations take effect without a restart.

systemctl --user reload trustless-proxy   # systemd: sends SIGHUP
# or manually:
# kill -HUP $(pgrep -f "trustless proxy start")

Reload re-reads config.toml (rules/allowlist) and refreshes the backend cache (bitwarden), so newly rotated keys are visible immediately instead of waiting for the 24h cache TTL.

MITM mode (--mitm):

  • Enables HTTPS interception for credential injection into encrypted requests

  • Auto-generates a root CA certificate at ~/.config/trustless/trustless-ca.{crt,key} on first use

  • Leaf certificates are generated per-hostname (24h validity, ECDSA P-256)

  • Install the CA certificate system-wide for seamless HTTPS interception:

    sudo cp ~/.config/trustless/trustless-ca.crt /usr/local/share/ca-certificates/
    sudo update-ca-certificates
    
FlagDescription
--port <n>Listen port (default: 8080)
--unix-socket <path>Listen on Unix socket (file permission control)
--mitmEnable MITM mode (intercept HTTPS for credential injection)

HTTPS CONNECT tunneling is supported. Without --mitm, CONNECT requests pass through without modification. With --mitm, the connection is intercepted and host-based credential injection applies.

trustless dlp — Outbound DLP Reverse Proxy (former dlp-proxy)

trustless dlp is the successor subcommand for the former github.com/ikkun1222/dlp-proxy: an outbound DLP reverse proxy that masks known secrets in LLM API request bodies with <redacted> before they leave the host.

trustless dlp start -config ~/.config/dlp-proxy/config.json   # start DLP reverse proxy (default 127.0.0.1:8787)
trustless dlp scrub-db  <db-path> [--apply] [--backup]        # scan / scrub secrets in a SQLite DB
trustless dlp scrub-text <path>   [--apply]                   # scan / scrub secrets in text files / dirs
  • Config schema is the same JSON as dlp-proxy: listen / min_secret_len / secrets_source (pass | bitwarden, default pass) / secrets_refresh_interval (required, e.g. "10m") / routes (prefix → upstream URL)
  • Secrets load through the shared backend (backend.Values); the former bitwardenloader/passstore are gone
  • fail-closed: startup aborts if secrets cannot be loaded; a failed reload keeps the previous set and logs a warning (fail-safe)
  • Hot reload: periodic refresh per secrets_refresh_interval + immediate reload on SIGHUP
  • Two-layer redaction (2026-08-14): Layer 1 = known-value substring scan (zero false positives); Layer 2 = gitleaks-compatible pattern rules (API key formats, JWT, private keys, etc.) with keyword pre-filter → RE2 regex → Shannon entropy threshold (default 3.5, per-rule override). Pattern rules are bundled in internal/dlp/redact/rules.toml (40 rules, //go:embed), derived from gitleaks (MIT, Copyright (c) 2019 Zachary Rice — see LICENSE.gitleaks / NOTICE)
  • New config fields: rules_file (path to an external gitleaks-compatible rules TOML; empty = bundled rules) / pattern_mode ("mask" = redact pattern matches, "log" = detect only, body unchanged, audit event with detail="patterns=hit&mode=log") / pattern_disabled (list of rule IDs to disable, e.g. ["generic-api-key"] to silence a false-positive rule)
  • Hot reload (serve): trustless serve re-applies pattern_mode / pattern_disabled / rules_file on every reload (SIGHUP via kill -HUP $(pgrep -f 'trustless serve') or the 10-minute periodic refresh) — config is re-read, the pattern set is atomically swapped (PatternSet.Replace), failures keep the previous state (fail-safe). Standalone trustless dlp start reads them at startup only
  • The former dlp-proxy repository is frozen (2026-08-13); trustless dlp is its replacement

Scrub commands clean up secrets that already persisted on disk — agent session DBs, logs, dumps — using the same two-layer redaction as the live proxy:

trustless dlp scrub-db  ~/.local/state/hermes/sessions.db            # dry-run: scan only
trustless dlp scrub-db  ~/.local/state/hermes/sessions.db --apply    # write changes
trustless dlp scrub-db  ~/.local/state/hermes/sessions.db --apply --backup  # keep a .bak copy first
trustless dlp scrub-text ~/.hermes/sessions --apply                  # scan/scrub text files & dirs
  • Default is dry-run: both commands scan and print per-table/per-file hit counts without writing. Add --apply to actually scrub; scrub-db additionally accepts --backup (copy DB to <db>.bak before writing) and --min-len (minimum secret length, default 8).
  • scrub-db operates on SQLite databases: Layer 1 known-value replacement + Layer 2 pattern masking, then rebuilds FTS virtual tables and runs VACUUM so no physical remnants survive in the file (verified by tests).
  • scrub-text walks a file or directory tree (agent sessions/, logs, dumps) with the same two-layer redaction.
  • Both load secrets through the DLP config’s secrets_source (pass / bitwarden) and honor pattern_mode"log" counts hits without masking, "mask" redacts in place.

trustless setup — First-Time Setup Wizard

Interactive wizard that automates the full first-time setup:

trustless setup

4-step flow:

StepActionAuto-detection
[1/4] GPG KeyDetect existing key or batch-create RSA 3072 (no passphrase, 5y expiry)Scans gpg --list-secret-keys
[2/4] pass StoreInitialize pass store, git initChecks pass availability
[3/4] .env ImportScan directories for .env files, parse KEY=VALUE, import to pass, backup originalsWalks --import-dir paths (default: .)
[4/4] Agent IntegrationDetect AI coding agents and install trustless-usage SKILL.md into their skill directory (upon confirmation)Config file existence + grep for trustless references

Skill installation paths per agent:

AgentSkill directory
OpenCode~/.config/opencode/skills/trustless-usage/
Claude Code~/.claude/skills/trustless-usage/
Codex~/.codex/skills/trustless-usage/
Hermes~/.hermes/skills/credential-management/trustless-usage/

The installed skill teaches the AI agent the credential conventions: use trustless run for injection, trustless secret set for registration, and never store plaintext credentials.

Options:

FlagDescription
--non-interactiveRun in non-interactive mode (safe defaults, no prompts, no file removal)
--import-dir <dir>Directory to scan for .env files (repeatable, default: .)

Agent detection currently supports: OpenCode, Claude Code, Codex, Hermes.

trustless doctor — System Health Check

Diagnostic tool that validates the entire trustless setup:

trustless doctor           # Human-readable output
trustless doctor --json    # Structured JSON for cron/SIEM
trustless doctor --fix     # Auto-resolve detected issues (stub)

Health checks performed: GPG key validity, pass store health, gpg-agent status, .env file security scan, agent integration status, MITM CA certificate installation.

trustless config — Tool Configuration

SubcommandDescription
initCreate default config at ~/.config/trustless/config.toml
showPrint current configuration
set <key> <value>Update a configuration value

Config keys:

KeyDescriptionDefault
backendCredential backend (pass, env, bitwarden)pass
outputDefault output modejson
run_defaults.sanitizeEnable sanitization by defaulttrue
run_defaults.timeoutDefault subprocess timeout5m
proxy.portDefault proxy port8080
policy.default.denied_commandsCommands blocked globally (e.g., sh,bash)(empty)

Config file location: ~/.config/trustless/config.toml (overridable via TRUSTLESS_CONFIG env var)

backend = "pass"
output = "json"

run_defaults = { sanitize = true, timeout = "5m" }

[proxy]
port = 8080

[sanitize]
patterns = [
  "(sk_live|sk_test)_[A-Za-z0-9]+",
  "(ghp|gho|ghu|ghs)_[A-Za-z0-9_]+",
  "Bearer [A-Za-z0-9._-]+",
]

[policy.default]
denied_commands = ["sh", "bash", "zsh"]

[[policy.overrides]]
secret_key = "iria/api/xai"
denied_commands = ["curl"]

trustless completion — Shell Completion

Generate shell completion scripts for bash, zsh, or fish:

trustless completion bash > /etc/bash_completion.d/trustless
trustless completion zsh > /usr/local/share/zsh/site-functions/_trustless
trustless completion fish > ~/.config/fish/completions/trustless.fish

trustless version — Version Information

trustless version