<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Leon</title>
    <description>The latest articles on DEV Community by Leon (@b2a48b).</description>
    <link>https://dev.to/b2a48b</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F2763971%2F9ca8020e-1ea4-43cb-b367-5d38db8d6055.png</url>
      <title>DEV Community: Leon</title>
      <link>https://dev.to/b2a48b</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/b2a48b"/>
    <language>en</language>
    <item>
      <title>Secrets, Agents, and Too Many Approval Buttons</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Sat, 29 Aug 2026 17:11:00 +0000</pubDate>
      <link>https://dev.to/b2a48b/secrets-agents-and-too-many-approval-buttons-2jk1</link>
      <guid>https://dev.to/b2a48b/secrets-agents-and-too-many-approval-buttons-2jk1</guid>
      <description>&lt;p&gt;There is a special kind of optimism in giving several Codex agents real work&lt;br&gt;
and then discovering that you have also promoted yourself to Chief Approval&lt;br&gt;
Button Officer.&lt;/p&gt;

&lt;p&gt;Every agent needs one credential. Then another. One task is waiting for an API&lt;br&gt;
token, another needs a webhook secret, and somewhere behind everything a&lt;br&gt;
password manager is politely asking whether you approve. Again.&lt;/p&gt;

&lt;p&gt;I recently spent far too much time looking for a secure, dependable way to&lt;br&gt;
share credentials with concurrent local agents. Every promising solution&lt;br&gt;
eventually introduced its own plot twist: quotas, concurrency problems,&lt;br&gt;
context-free approval dialogs, plaintext files, or enough local infrastructure&lt;br&gt;
to make me wonder whether I had accidentally started a platform team.&lt;/p&gt;

&lt;p&gt;1Password is not a requirement for the pattern in this article. It is simply&lt;br&gt;
the password manager I use, and therefore the character that appears most&lt;br&gt;
often in this story. The broader problem exists with any secret store: how do&lt;br&gt;
you give an application the credentials it needs without turning every agent&lt;br&gt;
operation into another trip to the vault?&lt;/p&gt;

&lt;p&gt;The answer that finally worked was almost disappointingly architectural:&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Resolve secrets once at the application boundary. Let agent commands inherit&lt;br&gt;
only an explicit application-wide allowlist.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;I tested the whole assortment discussed below. Two approaches remained&lt;br&gt;
practical enough to use. Choose one:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Put the actual values in &lt;code&gt;~/.codex/.env&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;Keep the values in a secret store and start ChatGPT with &lt;code&gt;op run&lt;/code&gt;. It reads
an env file containing 1Password references, authenticates through
1Password desktop, resolves the values, and passes them to ChatGPT.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The first option is gloriously boring. The second keeps 1Password as the only&lt;br&gt;
durable secret store. Both are compromises, but useful ones. I chose the option&lt;br&gt;
that concentrates its weirdness at startup.&lt;/p&gt;

&lt;p&gt;These are alternatives, not layers. If you migrate from &lt;code&gt;~/.codex/.env&lt;/code&gt; to&lt;br&gt;
&lt;code&gt;op run&lt;/code&gt;, remove the plaintext file rather than leaving two credential sources&lt;br&gt;
behind.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;I tested this on macOS on 2026-08-27 with ChatGPT desktop/Codex app&lt;br&gt;
&lt;code&gt;26.820.71523&lt;/code&gt;, Codex CLI &lt;code&gt;0.150.1&lt;/code&gt;, and 1Password CLI &lt;code&gt;2.39.0&lt;/code&gt;. The&lt;br&gt;
undocumented behavior described below may change in later builds.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;h2&gt;
  
  
  The Suspiciously Easy Option: &lt;code&gt;~/.codex/.env&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;On the ChatGPT/Codex desktop build I tested, ChatGPT loads this file when it&lt;br&gt;
starts:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;~/.codex/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It is an ordinary dotenv file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXAMPLE_API_TOKEN=&amp;lt;actual value&amp;gt;
EXAMPLE_WEBHOOK_SECRET=&amp;lt;actual value&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is it. No sidecar and no broker.&lt;/p&gt;

&lt;p&gt;I verified the behavior with both a fresh ChatGPT launch and a fresh&lt;br&gt;
&lt;code&gt;codex exec&lt;/code&gt; process, the non-interactive entry point to the same local Codex&lt;br&gt;
tooling. OpenAI's documentation lists the&lt;br&gt;
&lt;a href="https://learn.chatgpt.com/docs/config-file/environment-variables" rel="noopener noreferrer"&gt;environment variables that Codex supports directly&lt;/a&gt;,&lt;br&gt;
but it does not document automatic loading of this file. I therefore treat&lt;br&gt;
&lt;code&gt;~/.codex/.env&lt;/code&gt; as observed behavior of the tested setup, not a permanent&lt;br&gt;
cross-platform contract.&lt;/p&gt;

&lt;p&gt;Protect the file and never commit it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;chmod &lt;/span&gt;600 ~/.codex/.env
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Changes take effect only on the next full launch. Closing a ChatGPT window does&lt;br&gt;
not quit the application, however final the disappearing window may look.&lt;/p&gt;

&lt;p&gt;This is the smallest setup and the easiest one to debug. Its price is equally&lt;br&gt;
simple: the credentials remain on disk in plaintext. File permissions reduce&lt;br&gt;
exposure, but the file is still a durable copy that must be protected, rotated,&lt;br&gt;
and kept in sync.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Option I Actually Use: Resolve References Once
&lt;/h2&gt;

&lt;p&gt;I wanted 1Password to remain the source of truth without inviting it into&lt;br&gt;
every agent operation. The order here matters: you run &lt;code&gt;op run&lt;/code&gt; first. It then&lt;br&gt;
asks 1Password desktop to unlock or approve the request, if needed, resolves&lt;br&gt;
the references, and finally launches ChatGPT.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcpr4grvz0tzu9vqqeu17.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fcpr4grvz0tzu9vqqeu17.png" alt="Launch sequence: run op run, authenticate through 1Password desktop if needed, resolve the references, and launch ChatGPT with allowed variables for Codex agents." width="799" height="221"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The runtime sequence has three stages:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;You start &lt;code&gt;op run&lt;/code&gt; with &lt;code&gt;~/.codex/.env-run&lt;/code&gt;, which maps
environment-variable names to 1Password references.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;op run&lt;/code&gt; contacts 1Password desktop. The desktop app unlocks or asks for
approval if needed; &lt;code&gt;op run&lt;/code&gt; then resolves the references and launches
ChatGPT with the resulting environment.&lt;/li&gt;
&lt;li&gt;After ChatGPT starts, &lt;code&gt;~/.codex/config.toml&lt;/code&gt; decides exactly which variables
Codex may forward to agent commands.&lt;/li&gt;
&lt;/ol&gt;
&lt;h3&gt;
  
  
  &lt;code&gt;.env-run&lt;/code&gt; Is the Map, Not the Treasure
&lt;/h3&gt;

&lt;p&gt;The file looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;EXAMPLE_API_TOKEN=op://&amp;lt;vault&amp;gt;/&amp;lt;item&amp;gt;/&amp;lt;field&amp;gt;
EXAMPLE_WEBHOOK_SECRET=op://&amp;lt;vault&amp;gt;/&amp;lt;item&amp;gt;/&amp;lt;field&amp;gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The right-hand sides are references, not copied credential values. I still&lt;br&gt;
keep the file local, uncommitted, and mode &lt;code&gt;0600&lt;/code&gt;, because vault and item names&lt;br&gt;
can reveal useful metadata. A treasure map may not contain the treasure, but&lt;br&gt;
there is no reason to hand it out at the train station.&lt;/p&gt;
&lt;h3&gt;
  
  
  One Command, One Boundary
&lt;/h3&gt;

&lt;p&gt;Quit ChatGPT completely, then run:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;op run &lt;span class="nt"&gt;--env-file&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$HOME&lt;/span&gt;&lt;span class="s2"&gt;/.codex/.env-run"&lt;/span&gt; &lt;span class="nt"&gt;--&lt;/span&gt; /usr/bin/open &lt;span class="nt"&gt;-a&lt;/span&gt; ChatGPT
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That is the whole launch mechanism. &lt;code&gt;op run&lt;/code&gt; begins first, asks 1Password&lt;br&gt;
desktop to unlock or approve the request if necessary, replaces the references&lt;br&gt;
with their values, and starts ChatGPT inside the resolved environment. There is&lt;br&gt;
no second launcher or background service. The command does the interesting&lt;br&gt;
work once and then gets out of the way.&lt;/p&gt;

&lt;p&gt;This assumes that the 1Password CLI's desktop-app integration is enabled and&lt;br&gt;
that the shell is not forcing a different 1Password authentication method. The&lt;br&gt;
&lt;a href="https://developer.1password.com/docs/cli/secrets-scripts" rel="noopener noreferrer"&gt;&lt;code&gt;op run&lt;/code&gt; documentation&lt;/a&gt;&lt;br&gt;
describes how it replaces secret references and gives the resolved values to&lt;br&gt;
its child process.&lt;/p&gt;

&lt;p&gt;Once ChatGPT starts, its agents inherit the resolved environment through the&lt;br&gt;
policy below. They do not need to return to 1Password individually.&lt;/p&gt;
&lt;h2&gt;
  
  
  The Bouncer: &lt;code&gt;shell_environment_policy&lt;/code&gt;
&lt;/h2&gt;

&lt;p&gt;Getting values into the ChatGPT process is only half the job. &lt;code&gt;config.toml&lt;/code&gt;&lt;br&gt;
still decides which variables Codex may forward to commands.&lt;/p&gt;

&lt;p&gt;An &lt;code&gt;include&lt;/code&gt; entry creates an allowlist. Once any include filter exists,&lt;br&gt;
variables that do not match one are removed. This is excellent for security&lt;br&gt;
and slightly less excellent if you include two API tokens but forget that&lt;br&gt;
programs also enjoy having a &lt;code&gt;PATH&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;A practical baseline looks like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight toml"&gt;&lt;code&gt;&lt;span class="nn"&gt;[shell_environment_policy]&lt;/span&gt;
&lt;span class="py"&gt;inherit&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"all"&lt;/span&gt;
&lt;span class="py"&gt;ignore_default_excludes&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;

&lt;span class="nn"&gt;[shell_environment_policy.filters]&lt;/span&gt;
&lt;span class="py"&gt;"PATH"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"HOME"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"USER"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"SHELL"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"PWD"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"TMPDIR"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"LANG"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"LC_*"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"TERM"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"CODEX_HOME"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"EXAMPLE_API_TOKEN"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;span class="py"&gt;"EXAMPLE_WEBHOOK_SECRET"&lt;/span&gt; &lt;span class="p"&gt;=&lt;/span&gt; &lt;span class="s"&gt;"include"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The exact non-secret baseline depends on the commands you run. The goal is not&lt;br&gt;
to recreate your entire login shell inside Codex. Preserve the ordinary&lt;br&gt;
process context your tools need, then add credentials by exact name.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;ignore_default_excludes = true&lt;/code&gt; matters because the example names contain&lt;br&gt;
&lt;code&gt;TOKEN&lt;/code&gt; and &lt;code&gt;SECRET&lt;/code&gt;; the explicit include filters still form the allowlist.&lt;br&gt;
The official OpenAI&lt;br&gt;
&lt;a href="https://learn.chatgpt.com/docs/config-file/config-reference" rel="noopener noreferrer"&gt;configuration reference&lt;/a&gt;&lt;br&gt;
documents the precedence and recommends &lt;code&gt;filters&lt;/code&gt; instead of the legacy&lt;br&gt;
&lt;code&gt;include_only&lt;/code&gt; setting.&lt;/p&gt;

&lt;p&gt;Adding a value to &lt;code&gt;.env&lt;/code&gt; or &lt;code&gt;.env-run&lt;/code&gt; is therefore only half a configuration&lt;br&gt;
change. You must also include its name in &lt;code&gt;shell_environment_policy&lt;/code&gt;. The&lt;br&gt;
secret source and the allowlist must agree on the name; computers remain&lt;br&gt;
stubbornly literal about spelling.&lt;/p&gt;

&lt;p&gt;Because the environment belongs to the ChatGPT process, this works for project&lt;br&gt;
and non-project tasks, including tasks whose working directories are created&lt;br&gt;
dynamically.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 1Password Obstacle Course
&lt;/h2&gt;

&lt;p&gt;1Password has many relevant features. Each one made sense on its own. My&lt;br&gt;
problem was asking for all of these properties at once:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;several local agents;&lt;/li&gt;
&lt;li&gt;concurrent work;&lt;/li&gt;
&lt;li&gt;an explicit credential allowlist;&lt;/li&gt;
&lt;li&gt;no repeated human intervention;&lt;/li&gt;
&lt;li&gt;preferably no plaintext secret copy on disk.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;That combination turned the product tour into an obstacle course. The following&lt;br&gt;
observations come from the specific account and software setup identified in&lt;br&gt;
the version note above; they are not timeless guarantees about every 1Password&lt;br&gt;
configuration.&lt;/p&gt;

&lt;h3&gt;
  
  
  Service-Account Token
&lt;/h3&gt;

&lt;p&gt;In one incident on my individual 1Password account, parallel agents repeated&lt;br&gt;
reads until the shared daily allowance reached &lt;code&gt;1000 / 1000&lt;/code&gt;. By the time I&lt;br&gt;
checked, the token's hourly counter was back at &lt;code&gt;0 / 1000&lt;/code&gt;, but the daily&lt;br&gt;
account limit was still exhausted and dependent tasks had to wait roughly 13&lt;br&gt;
hours. &lt;a href="https://www.1password.dev/service-accounts/rate-limits" rel="noopener noreferrer"&gt;1Password documents&lt;/a&gt;&lt;br&gt;
that the 1,000-request daily limit for individual and Families accounts is&lt;br&gt;
shared by all service accounts. A new token would have given me a new token,&lt;br&gt;
not a new day.&lt;/p&gt;

&lt;h3&gt;
  
  
  Desktop CLI Calls from Agents
&lt;/h3&gt;

&lt;p&gt;Every agent effectively acquired a doorbell. Approval appeared in a separate&lt;br&gt;
1Password window without clearly identifying the requesting Codex task, the&lt;br&gt;
downstream operation, or enough context to understand what I was approving.&lt;br&gt;
That is human involvement, but not especially informed human involvement.&lt;/p&gt;

&lt;h3&gt;
  
  
  1Password Environments
&lt;/h3&gt;

&lt;p&gt;In my test, values in an Environment were separate stored values; putting an&lt;br&gt;
&lt;code&gt;op://&lt;/code&gt; reference inside one did not resolve it dynamically. The local dotenv&lt;br&gt;
destination used a named pipe rather than plaintext, but prompted on first&lt;br&gt;
read, relocked with 1Password, was not designed for concurrent access, and&lt;br&gt;
fresh Codex processes alternated between receiving all variables and receiving&lt;br&gt;
none. That made it unsuitable for this workflow.&lt;/p&gt;

&lt;h3&gt;
  
  
  1Password Connect
&lt;/h3&gt;

&lt;p&gt;Connect can provide a vault-scoped access token and cache data locally, but the&lt;br&gt;
token is not inherently read-only: the&lt;br&gt;
&lt;a href="https://www.1password.dev/connect/api-reference" rel="noopener noreferrer"&gt;Connect API&lt;/a&gt; includes create,&lt;br&gt;
replace, update, and delete operations. The deployment I evaluated also meant&lt;br&gt;
an API container, a sync container, a credentials JSON file, a token, a cache&lt;br&gt;
volume, ports, lifecycle management, and ideally a broker so agents would not&lt;br&gt;
hold a write-capable credential. This can be the right architecture for an&lt;br&gt;
organization. For one desktop app, I had accidentally founded a small&lt;br&gt;
secret-management civilization.&lt;/p&gt;

&lt;h3&gt;
  
  
  1Password MCP or Agent Tool Calls
&lt;/h3&gt;

&lt;p&gt;These are useful when the task is “operate on 1Password.” They do not&lt;br&gt;
transparently inject environment variables into arbitrary programs, and they&lt;br&gt;
keep password-manager calls inside the agent workflow—the dependency I was&lt;br&gt;
trying to remove. Useful tool, different plumbing.&lt;/p&gt;

&lt;p&gt;The repeated failure was not that any one feature was bad. It was that a simple&lt;br&gt;
question—“can this process receive the credential it needs?”—kept acquiring&lt;br&gt;
quota state, approval dialogs, concurrency behavior, or a local server.&lt;/p&gt;

&lt;p&gt;My goal was never to eliminate 1Password. It was to remove it from the&lt;br&gt;
per-agent hot path. One authorization initiated by &lt;code&gt;op run&lt;/code&gt; during application&lt;br&gt;
startup is much easier to reason about than repeated context-poor interruptions.&lt;/p&gt;

&lt;h2&gt;
  
  
  Security Has Entered the Chat
&lt;/h2&gt;

&lt;p&gt;None of this turns environment variables into an enchanted security boundary.&lt;/p&gt;

&lt;p&gt;The plaintext option keeps credentials on disk. The &lt;code&gt;op run&lt;/code&gt; option avoids that&lt;br&gt;
extra durable copy, but depends on desktop authentication, requires starting&lt;br&gt;
ChatGPT from a terminal command, and concentrates trust in that launch step.&lt;/p&gt;

&lt;p&gt;Both options place secrets in the ChatGPT process environment.&lt;br&gt;
&lt;code&gt;shell_environment_policy&lt;/code&gt; does not authorize commands; it only filters the&lt;br&gt;
variables inherited by commands that Codex launches. A command that inherits&lt;br&gt;
an allowlisted credential can use it, so the configuration and the code being&lt;br&gt;
run still need to be trusted. Environment variables improve delivery and&lt;br&gt;
separation of concerns; they do not make an untrusted process trustworthy.&lt;/p&gt;

&lt;p&gt;The allowlist is application-wide, not task-specific. Every task and subagent&lt;br&gt;
running inside that ChatGPT process should be treated as capable of launching&lt;br&gt;
a command that inherits every listed secret. It limits what can leave the&lt;br&gt;
application environment; it does not decide which agent gets which credential.&lt;br&gt;
True per-agent isolation would require separate processes or a credential&lt;br&gt;
broker, and neither preserves the simplicity of this setup.&lt;/p&gt;

&lt;p&gt;At startup, Codex adds the names exposed to its command environment to the&lt;br&gt;
initial prompt, not their values. Instructions can therefore say, “To access&lt;br&gt;
the API, use the environment variable &lt;code&gt;SOME_API_KEY&lt;/code&gt;.” The model can refer to&lt;br&gt;
that name in a command, and the program reads the value from its environment&lt;br&gt;
without the value appearing in the command itself. That distinction is useful,&lt;br&gt;
but it is not a force field. An agent can still dump its environment or make a&lt;br&gt;
program log a credential. Avoiding those operations is part of the model's and&lt;br&gt;
the tool's responsibility.&lt;/p&gt;

&lt;p&gt;Resolved values remain in the application's runtime environment until the app&lt;br&gt;
exits. Locking 1Password, changing a vault value, or removing vault access does&lt;br&gt;
not rewrite the copy already injected into a running ChatGPT process. Fully&lt;br&gt;
quit and relaunch through the chosen route to discard the old environment and&lt;br&gt;
receive the current values.&lt;/p&gt;

&lt;p&gt;Finally, &lt;code&gt;~/.codex/.env&lt;/code&gt; loading is observed rather than documented, and the&lt;br&gt;
1Password-backed route depends on several products behaving as tested. A&lt;br&gt;
small, non-secret startup check is worthwhile. It is nicer to discover a broken&lt;br&gt;
environment before an agent begins real work and develops opinions about the&lt;br&gt;
error message.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Least-Worst Setup Wins
&lt;/h2&gt;

&lt;p&gt;The useful idea was not a particular password-manager feature. It was choosing&lt;br&gt;
one boundary for secret resolution and giving every agent the same boring&lt;br&gt;
contract: receive a small, explicit set of environment variables.&lt;/p&gt;

&lt;p&gt;Use &lt;code&gt;~/.codex/.env&lt;/code&gt; when the smallest possible setup matters most and a&lt;br&gt;
protected plaintext file is acceptable. Use a launch-time injection mechanism&lt;br&gt;
when the secret store should remain the only durable source and one&lt;br&gt;
authentication step triggered by &lt;code&gt;op run&lt;/code&gt; at startup is acceptable. In my&lt;br&gt;
case, that mechanism is &lt;code&gt;op run&lt;/code&gt; with &lt;code&gt;~/.codex/.env-run&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;This is the least cumbersome arrangement I have found. In secret plumbing,&lt;br&gt;
“least cumbersome” is practically a five-star review, not a declaration that&lt;br&gt;
the problem has been solved forever.&lt;/p&gt;

&lt;p&gt;Disclosure: I used ChatGPT Codex to help draft and edit this article. The&lt;br&gt;
experience, conclusions, and final publication decision are mine.&lt;/p&gt;

&lt;p&gt;The unresolved question is how desktop agents (and subagents) should receive a&lt;br&gt;
well-attributed, least-privilege identity without persistent tokens, plaintext&lt;br&gt;
files, or context-free approval windows.&lt;/p&gt;

&lt;p&gt;Process-scoped injection solves secret delivery, not agent identity. If you&lt;br&gt;
have a cleaner pattern for giving concurrent Codex agents unattended access to&lt;br&gt;
credentials—especially one that avoids plaintext files, repeated approvals,&lt;br&gt;
quota pressure, and a local server—I genuinely want to hear it.&lt;/p&gt;

</description>
      <category>ai</category>
      <category>security</category>
      <category>productivity</category>
      <category>openai</category>
    </item>
    <item>
      <title>Hello, World!</title>
      <dc:creator>Leon</dc:creator>
      <pubDate>Wed, 26 Aug 2026 02:51:23 +0000</pubDate>
      <link>https://dev.to/b2a48b/hello-world-3p4k</link>
      <guid>https://dev.to/b2a48b/hello-world-3p4k</guid>
      <description>&lt;p&gt;Hello there!&lt;/p&gt;

</description>
    </item>
  </channel>
</rss>
