Secrets, Service Setup & Materializer

Trinity stores every API key, token, and config file your project needs in one encrypted store. The Secrets page in the sidebar is the full management surface — table view, filters, bulk import, per-target editing.

Where secrets land on disk

Most secrets are environment variables — they get injected into the agent's process at execution time and never touch your filesystem. A handful (like dexie-cloud.json or .env.local) need to live as files inside your project — Trinity writes those into your repo under a managed .gitignore block so they never get committed. See The materializer below.

The Secrets page

Open Secrets from the sidebar. You'll see a table grouped by key name. A key with two target overrides shows up as one row that expands to reveal the per-target values.

What each row tells you

Column Meaning
Key name The env var name (e.g. STRIPE_SECRET_KEY)
Target Which target this row binds to. "Project-wide" if it applies to every target.
Service The service that owns this key (e.g. stripe, dexie-cloud)
Purpose runtime (env var), provider (AI provider key), file (materializes to disk)
Value Masked. Click the eye icon to reveal — Trinity decrypts on the server and shows briefly.
Updated Last write time

Filters

  • Search — substring match on key name
  • Targets — filter by one or more targets. "Project-wide" is its own toggle.
  • Purpose — narrow to runtime, provider, or file-purpose secrets

Adding a secret

Click Add secret. The dialog asks for:

  • Key name — the env var name (e.g. STRIPE_SECRET_KEY)
  • Value — what you're storing. Sensitive by default; the input masks the value as you type.
  • Targets — pick one or more targets, or leave as "Project-wide" for cascade fallback. One key can fan out to multiple targets in a single submit.
  • Purpose — defaults to runtime. Pick provider for AI provider keys, file for config files (file purpose adds a destinations field — see The materializer).
  • Sensitive — UI dimension only; controls whether the value is masked by default. Every row is encrypted at rest regardless.

Trinity infers sensitive from the key name (*_SECRET, *_KEY, *_TOKEN, *_PASSWORD default to true) when you don't override.

Editing a secret

Click any row to open the edit dialog. You can change the value, retarget the binding (move from project-wide to target-specific or vice versa), update the label, or delete the entry.

The cascade resolution rule means: if you have a project-wide value for DATABASE_URL and a target-specific value for the same key on the api target, the API target gets its own value and every other target gets the project-wide one. No manual fan-out needed.

Bulk .env import

Click Import from .env to paste a .env file. Trinity:

  1. Parses the file (handles quoted values, escaped newlines, inline comments)
  2. Runs the sensitivity heuristic per key
  3. Lets you pick which targets each key binds to (or all → project-wide)
  4. Picks a conflict policy: keep existing, overwrite, or skip
  5. Submits everything in one transactional write — the whole batch rolls back on any failure

Per-row conflict overrides are available if you want different behavior for some keys. Result rows report created | updated | skipped | error so you can see exactly what happened.

Provider keys

The Project Settings → Provider Keys card is a focused view of purpose='provider' rows for AI providers (Anthropic, OpenAI, DeepSeek, Moonshot, Z.ai, Qwen, Ollama). Same encrypted store underneath; the card just narrows the table to provider rows.

You can also set provider keys globally (across all your projects) in App Settings → AI Models. Cascade rule: project-scoped wins over global.

The materializer

Some setup flows produce config files Trinity needs to write to disk — dexie-cloud.json, .env.local, certificates, or project-specific YAML. These get stored as purpose='file' secrets with destinations (where on disk to write them):

  • target — inside the consuming app's directory (e.g. apps/web/.env.local for a turborepo target)
  • repo — at the repo root (e.g. dexie-cloud.json next to package.json)
  • trunk — at your workspace root (project-wide config)

Trinity's materializer is what writes these files. It runs:

  • Right after a worktree is created (so every parallel story sees the right files)
  • After the setup runner finishes capturing values from a CLI
  • After successful story commits (so freshly-written secrets land before the next phase reads them)
  • On demand via Project Settings → Re-sync files

.gitignore management

Every materialized file gets added to a Trinity-managed block in your repo's .gitignore:

# === Trinity-managed (do not edit between markers) ===
.env.local
config/dexie-cloud.json
# === /Trinity-managed ===

Don't edit between the markers — Trinity will overwrite. Anywhere else in the file is yours to manage. If you delete a file-purpose secret, Trinity unlinks the file and prunes the line from the block on the next materializer pass.

How agents see your secrets

When a story executes, Trinity assembles the env var bag from:

  1. Target-specific rows for the story's target
  2. Project-wide rows (cascade fallback)
  3. Global rows (across all your projects)

The first hit wins per key name. Multi-target stories that don't have a clear target binding raise a gate so you can split the secret per-target or mark it project-wide.

For file-purpose secrets, agents just see the file on disk — the materializer wrote it before the agent ran.

Service setup gates

If you start a story that needs a service Trinity sees as unconfigured, the story pauses at a service setup required gate. The gate dialog has the setup runner pre-bound to the right target — finish the flow and the story resumes automatically. Agents can also raise this gate mid-execution via the signal_service_required tool when they hit a missing service that wasn't on Trinity's radar.

See Execution Gates for the full gate catalogue.