The fleet’s 1Password access runs through a single no-biometric service account
(claude-automation, vault Automation). That service account is now
permanently rate-limited (HTTP 429): thousands of retry calls keep resetting the
rate-limit window, so it never recovers. The current mitigation — the
fleet-cred-get wrapper caching creds in the macOS Keychain and serving stale values when
op is capped — is a band-aid over a structural problem.
Infisical (open-source secrets platform, infisical.com)
is the James-Goldbach-recommended replacement. It authenticates machines with
short-lived machine-identity tokens instead of a long-lived service account, so there is
no single service-account object to rate-limit into oblivion. Its
infisical run -- <cmd> model injects secrets straight into a child process’s
environment — the values never touch stdout, a file on disk, or an agent’s context window.
op item get … --reveal → infisical secrets get inside the same fleet-cred-get wrapperfleet-cred-get get/refresh/warm-all CLI surface every agent callsInfisical self-describes as “the open-source, all-in-one platform for secrets, certificates, and privileged access management.” Confirmed spelling is Infisical (James’s transcript caption “in physical” was an auto-transcription error). Official site: infisical.com.
infisical run, infisical secrets get/set, infisical login, --watch auto-reload.env (key=value) and YAML via infisical secrets set --file=. CSV not accepted for import| Tier | Price | Identity cap | Projects / Envs | Audit retention | Key features |
|---|---|---|---|---|---|
| Free | $0 | 5 identities total (humans + machines combined) | 3 projects / 3 envs each / 10 integrations | Not specified (community) | CLI, API, SDKs, Infisical Agent, webhooks, 2FA, all integrations, secret scanning & sharing, community support |
| Pro | $18 / mo per identity | Per-identity billing | 12 projects / 50 integrations | 90 days | + secret versioning, point-in-time recovery, RBAC, secret rotation, SAML SSO, IP allowlisting, priority support |
| Enterprise | Custom | Custom | Custom | Custom retention | + dedicated infra, SCIM, LDAP, dynamic secrets, approval workflows, KMIP, 99.99% SLA, SOC2 reports |
Today the entire fleet authenticates to 1Password as one service account
(claude-automation). All 10 agents run on the same Mac and read from the same
Automation vault. The Infisical mapping is one-to-one: create one fleet
machine identity (Universal Auth client ID + client secret), grant it read access to the fleet project,
and have every agent’s fleet-cred-get wrapper authenticate as that single identity.
That is 1 machine identity + 1 human (Zach) = 2 of the 5 free-tier slots —
comfortably free.
Two access patterns, both stdout-safe:
# Pattern A — inject into a child process (secrets never printed): infisical run --projectId=<id> --env=prod -- ./some-fleet-script.sh # secrets exist ONLY as env vars inside the child; nothing echoed to terminal # Pattern B — single value into the existing Keychain-cached wrapper: infisical secrets get CLOUDFLARE_API_TOKEN --plain --projectId=<id> --env=prod # replaces `op item get ... --reveal` inside fleet-cred-get's _op_pull()
The machine-identity token is obtained once per session and held in an env var:
export INFISICAL_TOKEN=$(infisical login --method=universal-auth \
--client-id=<id> --client-secret=<secret> --silent --plain)
OP_SERVICE_ACCOUNT_TOKEN via op-token-ensure)| Dimension | 1Password service account (now) | Infisical machine identity |
|---|---|---|
| Auth object | One long-lived service-account token, globally rate-limited | Short-lived token minted from a client secret; the identity itself isn’t a throttle target the same way |
| Failure mode under load | Retry storms reset the 429 window → permanent lockout | Reads are normal API calls against your own project; no shared service-account quota choke point |
| Recovery | Stuck until call volume drops for a full window (didn’t happen) | Token renew/re-mint is cheap and local; no global cooldown to wait out |
| Secret-on-disk | Avoided via Keychain cache (our wrapper) | Native: infisical run never writes secrets to disk |
| Audit | Limited | Secret access logged (retention by tier) |
fleet-cred-get Keychain cache even after migrating. It’s defense-in-depth:
if Infisical Cloud has an outage, the fleet still serves recently-cached creds instead of blocking
customer-facing work — exactly the resilience property it provides today.
Every step below is designed so no secret value ever passes through an AI agent’s chat/context. The migration is file-to-file: export → transform → import, with secret values redacted in all logging and never echoed to a stdout an agent reads.
Key fact (verified): 1Password’s desktop export
(File > Export) is a local operation gated by the account password. It does
not use the rate-limited service-account API — so it works even while the
service account is throttled. Zach (human, at the GUI) runs this for both the
Codex/personal vault and the Automation vault.
Choose .1pux, not CSV. Correction to a common assumption:
.1pux is not encrypted — it is a plaintext JSON-in-ZIP archive. But it is the
right choice because CSV silently drops everything that isn’t a Login/Password item (API keys
stored as custom fields, secure notes, OTP secrets, multi-field items like the fleet’s
VE Stats Supabase with URL + Service Role Key + DB Password). .1pux
preserves all item types, all custom fields, and vault structure. Since .1pux is
plaintext, treat it like a live secret from the moment it lands (§7).
Output: codex-vault.1pux and automation-vault.1pux written to a
tmpfs / RAM-disk path if possible, otherwise a chmod 700 directory
that is shredded at the end (§9).
A converter script reads the .1pux ZIP, walks export.data JSON, and
emits one .env file per logical environment/project (e.g. fleet-prod.env,
codex.env). Infisical bulk import accepts .env (KEY=value) and
YAML — not CSV — so .env is the target format.
Approach (not final code — this is the design + the safeguards that matter):
.1pux → write .env. Secret values move buffer-to-buffer in the script’s memory and into the output file. They are never print/echo/console.log-ed.item::field pairs to Infisical key names. The fleet’s 24 warm-all entries (Cloudflare::API Token, VE Stats Supabase::Service Role Key, …) get a deterministic naming convention so the wrapper can still look them up..env files are written with 0600 perms to the shredded directory..env: the very next step (import) consumes it; no cat/Read of the file by any agent at any point.Keep a separate, committed-to-repo key manifest (key names only, zero values) so the mapping is reviewable and reproducible without exposing secrets.
Authenticate the human (Zach) interactively once for the import, then bulk-import each
.env straight from file:
infisical login # Zach, interactive, one time infisical secrets set --file="./fleet-prod.env" --env=prod --projectId=<id> infisical secrets set --file="./codex.env" --env=prod --projectId=<codexId>
infisical secrets set --file= reads the file directly — values go file →
API over TLS and are never echoed. Note: infisical secrets import is a
different command (it links secrets between Infisical paths, not from a file) — do not
confuse the two. There is no official 1Password→Infisical tool, so the
Step-2 converter is custom work the fleet owns.
The fleet reads every credential through one script:
orgs/riles-fleet/shared/scripts/fleet-cred-get (435 lines; ~18 files / 10 agents call
it or call op via skills). The rewrite is surgical — the public
get / refresh / warm-all / clear / list interface stays identical so no caller changes:
_op_pull() (line 176, op item get "$item" --vault "$vault" --fields "$field" --reveal) with infisical secrets get "$key" --plain --projectId="$pid" --env="$env"._op_pull_with_fallover, OP_RATE_LIMIT_RC, OP_SERVICE_ACCOUNT_TOKEN_B) — there is no service-account rate limit to fall over from.op-token-ensure (seeds OP_SERVICE_ACCOUNT_TOKEN) → an infisical-token-ensure that mints/renews INFISICAL_TOKEN from the launchd-held client secret (same secure-env pattern, no GUI popups).item::field::vault tuples become Infisical key names; warm-all pre-fetches them into the Keychain exactly as today.op item get directly (ttc-wave-send, gws-auth-recovery, monarch-puller, sked-api, etc.) route through fleet-cred-get or the new infisical call. Prefer routing through the wrapper so caching/resilience is centralized.fleet-cred-get get returns a working value from Infisical (validate by using it — e.g. a Cloudflare API ping — never by printing it).op calls remain in live paths (grep for op item get across agent scripts — should be migrated or dead).| Where a secret could leak | How the plan prevents it |
|---|---|
The .1pux export file (plaintext JSON-in-ZIP) | Written to a RAM-disk / chmod 700 dir; treated as live secret; rm -P/shred immediately after import (§9). Never cat/Read by an agent. |
| Converter script printing values to stdout | Script logs keys + counts only; a sentinel-secret test verifies the redaction path before real data flows. |
Generated .env files | 0600 perms, written to the shredded dir, consumed immediately by import, never read by an agent. |
| Import command echoing secrets | infisical secrets set --file= reads file directly → TLS; nothing echoed. |
| Runtime: secrets in an agent’s context | infisical run injects into the child process env only; infisical secrets get --plain output is captured by the wrapper into Keychain, never surfaced to the agent transcript. |
| Secret “zero” (the client secret) | Held in launchd-seeded secure env (same model as today’s OP token); short-lived INFISICAL_TOKEN minted from it; consider a periodic token to avoid re-handling the client secret. |
| Git | Only a key manifest (names, no values) is committed. .env and .1pux are never in the repo; add to .gitignore defensively. |
.1pux export is
plaintext and contains every secret from both vaults at once. From the
instant it is created until it is securely shredded, it is the highest-value target in the entire
migration. Keep it on a RAM-disk or chmod 700 path, never let any AI agent
cat/Read it, and shred/rm -P it the moment import
verifies — before anything else.
.1pux via desktop app; converter run; secrets imported to Infisical; key manifest committed (names only).shred -u / rm -P the .1pux exports and all generated .env files. Confirm the shredded directory is empty.fleet-cred-get rewritten + deployed; infisical-token-ensure seeding the client secret in launchd env; warm-all succeeds against Infisical.grep -r "op item get" across all agent scripts/skills → every hit migrated or confirmed dead. Zero live op calls remain.claude-automation service account in 1Password. Remove OP_SERVICE_ACCOUNT_TOKEN / token-B from launchd env and the ~/.secrets keychain entries.op-token-ensure sourcing and any residual op wrappers; delete dead 1Password skills (op-daemon-socket-reset, op-fresh-inode-workaround).~/.claude/CLAUDE.md & fleet knowledge.md: secrets-management section now points to Infisical, not 1Password.