> ## Documentation Index
> Fetch the complete documentation index at: https://prism.ntecdev.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# SPEC-122: Prism-Vault Shared Config and Secrets Service

> Prism-first shared config, secret, and credential-resolution service with provider adapters for local, LAN, and Render deployments; designed for later Janus/DPA-Crawl collaboration without making DPA-Crawl the first rollout.

# SPEC-122 v0.2 - Prism-Vault Shared Config and Secrets Service

**Status:** draft
**Owner / Author:** Texi (architecture)
**Phase name:** Prism-Vault
**First consumer:** Prism
**Later consumers:** Janus, DPA-Crawl/WebCrawl, and other projects after the Prism-first rollout proves the contract.
**Related:** SPEC-019 (local/lan/cloud modes), SPEC-056 (isolation), SPEC-087 (Render deployment), SPEC-089 (cloud auth), SPEC-116 (bridge audit pattern), Datris `datris-platform-oss` HashiCorp Vault implementation review 2026-05-14.

## Summary

Prism-Vault is a Prism-first shared config, secret, and credential-resolution
service. It gives Prism agents and Prism backend surfaces one stable contract for
runtime configuration and secret access across local, LAN, and Render production
deployments.

The service lives as a Prism-accessible separable subproject for this phase, not
as a separate repository immediately. It still carries its own
version/build/deploy lifecycle from the start. That boundary is deliberate:
Prism-Vault begins under the Prism umbrella for easier build/test/debug and
integration, while remaining cleanly peelable into a standalone service later.

Janus and DPA-Crawl/WebCrawl are explicitly later collaboration targets. They
inform the design, but they are not the first integration or acceptance anchor.
The first rollout proves Prism-scoped secret/config management for Prism agents.

Datris is useful prior art: it has a compact Vault KV v2 wrapper,
self-describing secret records, environment-scoped paths, UI masking,
masked-placeholder preservation, and runtime secret injection into worker
scripts. Prism-Vault keeps those ergonomic lessons but hardens the model for
Prism production use and later multi-project expansion.

## v0.2 Ratification Amendment - 2026-05-18

This amendment prepares SPEC-122 for Frank ratification after the initial
settings-backed skeleton landed and Carla became unavailable.

**V-0 build-start gate.** No new Prism-Vault implementation code may land after
the existing skeleton until Frank ratifies this SPEC-122 v0.2 shape plus the
scoped Plan #28 update. Operations Console remains the active implementation
lane; Vault work queues behind it.

**Phase 0A - existing contract skeleton.** The current implementation is
recognized as Phase 0A only:

* `backend/app/schemas/vault.py`
* `backend/app/services/vault_service.py`
* `backend/app/routers/vault.py`
* `backend/tests/test_vault_router.py`
* Prism-Vault docs, diagrams, and Plan #28 surfaces

Phase 0A establishes the HTTP schema/router/service seam, a
`SettingsBackedVaultProvider`, masked metadata reads, runtime resolve response
shape, config get, service-scope denial, header-bound audit caller identity,
agent `run_ref` requirement, stub audit IDs, and no-raw-value error tests. It is
not a full durable Vault implementation.

**Phase 0A explicit non-claims.** Phase 0A does not claim:

* durable `prism_vault_*` SQL tables,
* persistent append-only audit,
* real Vault KV v2 provider behavior,
* Render provider behavior,
* production secret ownership migration,
* full secret/config CRUD,
* MCP-side `prism_vault_*` verb parity,
* operator UI,
* rotation/revocation automation.

**Phase 0B - durable audit and policy floor.** The next build slice after
ratification is durable audit:

* Alembic migration and model for append-only Vault audit events.
* Service audit sink that writes an attempt/reservation before any provider read.
* Success, denied, and failure finalization before any raw value returns.
* Fail-closed `prism_vault_audit_unavailable` behavior when audit cannot be
  written.
* Provider-neutral tests for success, denied, missing, and audit-unavailable
  paths.

Raw secret values remain out of Prism SQL. Audit stores hashes and metadata
only.

**Phase 0C - agent verb parity.** After Phase 0B, add thin MCP verb shims that
round-trip to the HTTP source contract:

* `prism_vault_secret_get_metadata`
* `prism_vault_secret_resolve`
* `prism_vault_config_get`

Phase 0C includes an MCP smoke proving the verbs call `/vault`; no shim-only
stub is acceptable.

**Phase 1 - LAN-first real provider.** Because server1 already has a Vault
container, the first real provider is LAN Vault KV v2:

* non-root app token,
* scoped Vault policy,
* readiness/policy probe,
* provider selection that keeps caller APIs provider-neutral,
* same contract tests against the LAN provider.

Local parity follows as Phase 2. Render remains deferred unless Frank explicitly
reorders.

**Carla coverage.** Carla remains the eventual viewer/review coordinator but is
offline and not an active blocker. Ratification and implementation coordination
route through Frank, Donna, Texi, Candi, Samantha, Lafonda, and Desiree per Plan
\#28.

## Diagrams

* Architecture: `docs/diagrams/prism-vault/shared-service-architecture.mmd`
* Runtime resolution: `docs/diagrams/prism-vault/secret-resolution-sequence.mmd`
* Deployment modes: `docs/diagrams/prism-vault/deployment-modes.mmd`
* Scope data model: `docs/diagrams/prism-vault/scope-data-model.mmd`

## Problem

Prism needs a first-class service for secrets and runtime config before extending
the pattern to Janus/DPA-Crawl or other projects. Current deployment modes have
different ways to pass credentials and config:

1. Local mode often uses `.env` and dev-service defaults.
2. LAN mode needs durable, non-root secret handling with private-network access.
3. Render production uses platform env/secret bindings and may need an external
   provider for per-project runtime secrets.
4. Agents need scoped runtime values without broad secret-store credentials.
5. Operators need masked metadata, audit evidence, and repairable config state.

The Datris implementation proves the developer ergonomics, but its app-local
Vault shape is not the final Prism service boundary. Prism-Vault makes that
boundary explicit.

## Goals

* Deliver Prism-scoped secret/config management first.
* Support Prism agents and backend services as first-class runtime consumers.
* Support local, LAN, and Render deployments behind one Prism-Vault contract.
* Keep the provider-adapter design so Vault, Render, or a future managed
  provider can back the same API.
* Enforce tenant/project/environment/service scope in the backend.
* Return masked metadata on admin/read paths and reserve raw secret values for
  runtime resolution only.
* Capture audit rows sufficient to answer who resolved what, for which Prism
  project, purpose, and run/job/session.
* Establish subproject-first Prism-Vault version/build/deploy boundaries from
  day one, even while it lives under the Prism umbrella.
* Defer Janus/DPA-Crawl/WebCrawl integration until the Prism path is stable.

## Non-Goals

* Making DPA-Crawl/WebCrawl the first consumer.
* Replacing Prism's existing human auth system. Prism-Vault consumes
  authoritative caller identity; it does not become the IdP.
* Cross-tenant secret sharing in v0.1.
* Direct per-agent or per-worker Vault tokens in v0.1. Runtime consumers receive
  resolved env payloads, not provider credentials.
* Building a full human-facing admin console in this spec. Console screens can
  consume the API but are separate implementation work.
* Provider-specific rotation automation for every possible secret kind. v0.1
  defines monthly and manual-on-demand rotation policy plus hooks/audit;
  individual automated rotators land incrementally.

## Architecture Decision

Prism-Vault is a broker with three internal surfaces:

1. **Secret Store Surface** - CRUD and metadata for secret records.
2. **Config Store Surface** - versioned non-secret Prism runtime config.
3. **Credential Resolver Surface** - runtime-only resolution for Prism agents,
   backend services, and later worker integrations.

All three surfaces pass through the same identity, scope, policy, and audit gate.
The provider adapter is behind that gate. Callers do not talk directly to Vault,
Render environment variables, or any future provider.

## Subproject Boundary

Prism-Vault starts as a Prism-accessible separable subproject inside the Prism
umbrella. Do not require a separate GitHub repository in v0.1. The subproject
must still behave like an independent service:

* Own separable subproject path, with repo-separation-ready boundaries.
* Own version string and changelog.
* Own build artifact or image.
* Own deploy config for local, LAN, and Render.
* Own contract tests.
* No hard dependency on Prism monolith internals for provider adapters.
* Prism integration goes through the Prism-Vault API, not direct table/provider
  access.

This keeps future extraction boring: move the subproject into a separate repo or
deploy unit later, preserve the API.

## Phase 0 Boundary Concretization

Phase 0 must create the separable subproject boundary in one concrete place so
implementation slices do not each invent their own shape:

* **Code root / package boundary:** Prism-Vault runtime code lands under the
  existing Prism repo at `backend/app/{routers,schemas,services}/vault.py`.
  Phase 0C adds `mcp-node/src/verbs/vault.ts` as the Prism-hosted agent surface.
  The extraction-ready subproject anchor remains `prism-vault/`, which holds
  the independent version line and README contract for later peel-off.
* **Version source:** `prism-vault/VERSION` is the source of truth for the
  subproject version. Prism repo/package versions must not silently substitute
  for the Prism-Vault line.
* **Image / artifact name:** the intended extraction-ready artifact name is
  `prism-vault`. Until extraction, any Prism-hosted build artifact or container
  image for this surface should carry that name in tags/labels rather than a
  Janus or generic backend label.
* **Deploy config location:** Prism-hosted deploy wiring lives in the normal
  Prism deploy surfaces (`docker-compose*.yml`, `render.yaml`, and related
  deploy/runbooks) with Prism-Vault-specific entries called out explicitly as
  the future service boundary.
* **Contract-test target:** Phase 0A contract tests target the Prism-hosted
  `/vault` HTTP routes at `backend/tests/test_vault_router.py`. Phase 0C adds
  matching MCP-side smoke coverage for the `prism_vault_*` verb surface.

This is intentionally Prism-hosted in v0.2, but the names above are the
canonical boundary implementers must use so later extraction is mechanical.

## Scope Model

Canonical scope is:

```text theme={null}
tenant_id / project_id / environment / service / record_name
```

Human-readable slugs may be accepted as lookup input, but authorization uses
stable IDs. Example logical scopes:

```text theme={null}
f4b93fa7 / PID-PGR01 / local  / prism        / openai-api-key
f4b93fa7 / PID-PGR01 / lan    / prism-agent  / github-token
f4b93fa7 / PID-PGR01 / render / prism-cloud  / workos-secret
```

Later Janus/DPA-Crawl examples are valid only after the later integration phase:

```text theme={null}
f4b93fa7 / PID-DPA01 / lan / webcrawl / browserbase-key
```

Environment names are deployment/runtime scopes, not Git branches. Required
initial values:

* `local`
* `lan`
* `render`

Additional environments such as `staging`, `preview`, or `customer-prod` require
explicit registration and policy.

## Provider Binding

### Local

Local mode MAY run Vault dev mode for fast setup. Local mode MAY read bootstrap
inputs from `.env`, but `.env` is an input channel only. Prism-Vault state and
audit must still be written through Prism-Vault.

### LAN

LAN mode uses a real Vault deployment by default:

* non-root app token,
* project-scoped policies,
* durable storage,
* normal seal/unseal operation,
* private LAN address,
* no public Vault port exposure.

### Render

Render mode uses the same Prism-Vault API contract. Prism-Vault remains the
primary vault and service of record. Render-native environment variables and
secret bindings are exceptions for Render services that must consume values
through native Render service boundaries. Runtime/project secret records should
default to Prism-Vault unless a Render boundary makes native binding required.

Render is not allowed to leak into caller APIs. Callers still call
`prism_vault_secret_resolve`, `prism_vault_secret_put`,
`prism_vault_config_list`, etc. The adapter decides whether the provider read
comes from Prism-Vault provider storage, Render env/secret binding, or external
Vault.

### Provider credential isolation

Provider adapter credentials are deployment-mode-local implementation detail, not
shared application config. LAN Vault app tokens, Render-native bindings, and any
future managed-provider credentials must be loaded exclusively by their own
adapter, scoped to the active deployment mode, and must never appear in a
unified config namespace that another mode, caller, or adapter can read.

## API Contract

v0.2 follows the normal Prism capability shape:

```text theme={null}
backend service -> /vault HTTP router -> thin mcp-node prism_vault_* verb shims
```

Do not add a standalone Prism-Vault SDK in v0.2. The backend HTTP API is the
source contract. `mcp-node` verbs are thin clients for agents and land in Phase
0C after durable audit exists. A separate SDK may be extracted later only when a
non-MCP consumer exists, such as a CI tool or deploy script.

Names below are logical verb semantics that the HTTP routes expose and the Phase
0C mcp-node shims must mirror.

### Secret metadata

```text theme={null}
prism_vault_secret_put(scope, name, fields, labels?, policy?)
prism_vault_secret_get_metadata(scope, name)
prism_vault_secret_list(scope, filters?)
prism_vault_secret_delete(scope, name)
prism_vault_secret_rotate(scope, name, rotator_ref?)
```

`get_metadata` and `list` never return raw secret values. Sensitive fields are
masked and include only field names, last updated metadata, provider ref, labels,
and policy summary.

### Runtime resolution

```text theme={null}
prism_vault_secret_resolve(scope, name, purpose, caller, run_ref?, field_allowlist?)
```

Resolution is the only v0.1 path that returns secret values. It is allowed only
for runtime identities such as a registered Prism agent or backend service. It
must include a purpose.

`purpose` is a registered string, not free text. Resolution must validate
`purpose` against an allowlist or registry before policy evaluation. wildcard or
prefix-based purpose matching is forbidden by default and is allowed only when a
record policy explicitly opts into that broader match shape.

The response is a short-lived env payload:

```json theme={null}
{
  "ttl_s": 900,
  "env": {
    "OPENAI_API_KEY": "...",
    "GITHUB_TOKEN": "..."
  },
  "audit_id": "..."
}
```

The TTL is the maximum post-resolution exposure window. Rotation or revocation
does not retroactively invalidate an already-issued env payload unless an
emergency revocation path explicitly disables it. v0.1 must document and support
an emergency revocation path independent of normal TTL expiry, such as `ttl_s=0`
responses or provider-level disablement.

### Config

```text theme={null}
prism_vault_config_put(scope, name, document, schema_ref?, labels?)
prism_vault_config_get(scope, name, version?)
prism_vault_config_list(scope, filters?)
prism_vault_config_promote(scope, name, from_version, to_environment)
```

Config records are non-secret JSON documents. They are versioned and may be
returned to authorized callers. Examples: model routing defaults, provider
selection, agent runtime knobs, allowed outbound integrations, cloud deploy
config, and service health thresholds.

Config Store is non-secret by contract. Writes must reject, quarantine, or fail
review on secret-looking fields/values where practical, and examples/docs must
route credentials, tokens, API keys, client secrets, passwords, and similar
sensitive material through Secret Store instead of Config Store. Config Store is
not an escape hatch around masking, audit, or resolution discipline.

## Authorization Contract

Backend authorization is enforced, not advisory.

Every request must resolve:

* `caller_identity`
* `caller_kind` (`human`, `agent`, `service`)
* `tenant_id`
* requested `project_id`
* requested `environment`
* `purpose`

Default rule: a caller can only read, write, list, or resolve inside its own
tenant and project. Cross-project access is denied unless an explicit policy
grants the caller and purpose.

For v0.1, shared-service access is Prism-first:

* Prism agents may resolve only Prism-scoped records that match their project,
  identity, and purpose.
* Prism backend services may manage service-scoped records through service
  identity.
* Operator/admin identities may write and rotate records within their tenant.
* Janus/DPA-Crawl and non-Prism projects have no default access in v0.1.

Policy write/modify operations are restricted to `caller_kind in {human,
service}` and are explicitly denied to `agent` and `worker` callers. An agent or
worker may not grant itself broader resolve access by attaching or mutating
policy data in a secret/config write path.

If Prism-Vault is uncertain whether an operation is allowed, it fails closed and
writes a denied audit event.

## Prism Integration Contract

Prism is the first integration target. The initial Prism rollout must support:

1. Prism backend service secrets for local/LAN/Render.
2. Prism agent runtime secret resolution for explicitly allowed purposes.
3. Prism config records for non-secret runtime config.
4. Masked metadata lookup for operator/admin inspection.
5. Audit lookup scoped to the requesting Prism project.

Required resolve input:

```json theme={null}
{
  "scope": {
    "tenant_id": "...",
    "project_id": "PID-PGR01",
    "environment": "lan",
    "service": "prism-agent"
  },
  "name": "agent-provider-credentials",
  "purpose": "prism.agent.execute",
  "run_ref": "session_or_scheduled_run_id",
  "field_allowlist": ["OPENAI_API_KEY"]
}
```

Agents must not receive broad Prism-Vault admin credentials. They receive
resolved env payloads only. Agent/tool logs must mask every resolved value before
persistence.

## Later Janus / DPA-Crawl Contract

Janus and DPA-Crawl/WebCrawl remain design targets but move near the end of the
rollout. Their integration should happen only after Prism local, LAN, and Render
paths pass the same contract tests.

Later DPA-Crawl/WebCrawl integration will:

1. Read versioned crawl/extraction config before starting a job.
2. Resolve only the credentials that job needs immediately before execution.
3. Require `job_id` for worker resolves.
4. Mask resolved values in worker logs before persistence.

That later phase may add `caller_kind=worker` and job-specific policy rules.

## Data Model

Minimum durable records:

### `prism_vault_secret_records`

* `id`
* `tenant_id`
* `project_id`
* `environment`
* `service`
* `name`
* `provider`
* `provider_ref`
* `labels`
* `active`
* `created_at`
* `updated_at`

### `prism_vault_secret_versions`

* `id`
* `secret_record_id`
* `version`
* `field_names`
* `value_hash`
* `provider_version_ref`
* `created_by`
* `created_at`

Raw values stay in the provider, not in Prism SQL, unless a future encrypted
storage spec explicitly creates a Prism-Vault-native provider.

### `prism_vault_config_records`

* `id`
* `tenant_id`
* `project_id`
* `environment`
* `service`
* `name`
* `schema_ref`
* `active_version`
* `created_at`
* `updated_at`

### `prism_vault_config_versions`

* `id`
* `config_record_id`
* `version`
* `document_json`
* `document_hash`
* `created_by`
* `created_at`

### `prism_vault_access_policies`

* `id`
* `tenant_id`
* `project_id`
* `environment`
* `service`
* `record_ref`
* `caller_kind`
* `caller_identity_ref`
* `purpose`
* `permission`
* `effect`

### `prism_vault_audit_events`

* `id`
* `tenant_id`
* `project_id`
* `environment`
* `service`
* `record_name`
* `record_kind`
* `operation`
* `caller_identity`
* `caller_kind`
* `purpose`
* `run_ref`
* `provider`
* `result`
* `value_hash`
* `created_at`

Audit never stores raw secret values.
Audit rows are append-only at the application layer: no UPDATE or DELETE path is
allowed for runtime callers or admin surfaces. v0.1 requires a minimum 12-month
retention period for audit evidence. A future integrity layer, such as chained
hashes or append-only secondary export, must be named even if Phase 0 defers its
implementation.

## Datris Lessons Adopted

Prism-Vault SHOULD adopt these Datris patterns:

* Self-describing secret payloads for complex provider slots.
* Masked metadata on read paths.
* Preserve existing sensitive field values when a UI sends the masked
  placeholder.
* Hot reload for config/AI/provider changes where the consuming service supports
  it.
* Runtime env injection, with log masking before persistence.

Prism-Vault MUST improve these areas:

* No fail-open tenant fallback. Unmapped or missing caller credentials fail
  closed.
* No root-token provider access in LAN or Render.
* No stack traces returned to clients.
* No direct broad provider reads from application code.
* No caller-visible dependency on `.env` persistence in production.

## Security Requirements

* All state-changing writes require authenticated caller identity.
* Raw secret values are returned only by `prism_vault_secret_resolve`.
* `prism_vault_secret_resolve` requires `purpose`.
* Prism project isolation is default-deny.
* Cross-project policies require explicit operator/admin creation and audit.
* Provider adapter credentials are service-owned and never sent to agents.
* Provider adapter credentials are adapter-local and mode-scoped; local callers
  cannot observe LAN or Render adapter credentials, and vice versa.
* Every value resolution writes an audit event before returning the value.
* `resolve()` MUST create an audit attempt/reservation before provider read and
  MUST finalize success, denied, or failure before returning any value.
* Audit writes are atomic with Prism-Vault authorization. If audit finalization
  cannot be written, no value is returned and the operation fails closed.
* Audit evidence is append-only and retained for at least 12 months.
* Runtime resolve responses remain provider-neutral: callers receive `ttl_s`,
  `env`, and `audit_id`, not provider refs or provider version refs.
* Policy write/modify is denied to `agent` and `worker` callers.
* `purpose` values are validated against a registered allowlist; wildcard/prefix
  policies require explicit per-record opt-in.
* Logs must mask exact resolved values and common transformed forms where
  practical.
* Render production defaults to Prism-Vault as service of record. Render-native
  encrypted env/secret handling is allowed only where the Render service boundary
  requires it; local `.env` is not production state.

## Rotation Policy

v0.1 baseline rotation cadence:

* Monthly scheduled rotation for Prism-Vault-managed production secrets where the
  provider supports rotation.
* Manual on-demand rotation whenever an operator requests it, a credential is
  suspected exposed, a user/service leaves scope, or a provider key must be
  replaced.
* Every rotation attempt writes audit: requested\_by, reason, record scope,
  provider, old value hash, new value hash, result, and timestamp.
* Rotation automation may be partial in v0.1, but the policy, audit shape, and
  manual operation path must exist.

## Failure Modes

| Name                                 | Meaning                                                                 | Handling                                                                 |
| ------------------------------------ | ----------------------------------------------------------------------- | ------------------------------------------------------------------------ |
| `prism_vault_scope_denied`           | Caller lacks permission for requested scope                             | 403, denied audit                                                        |
| `prism_vault_provider_unavailable`   | Backing provider cannot be reached                                      | 503, no fallback to stale secret unless policy says cached metadata only |
| `prism_vault_secret_missing`         | Record or provider value missing                                        | 404, audit                                                               |
| `prism_vault_audit_unavailable`      | Audit write failed                                                      | fail closed                                                              |
| `prism_vault_render_binding_missing` | Render adapter expected env binding absent                              | 503 in production, setup error in deploy smoke                           |
| `prism_vault_run_context_missing`    | Runtime resolve omitted required run\_ref for a policy that requires it | 400                                                                      |

## Implementation Plan

### Phase 0A - Settings-backed service boundary skeleton

* Land this spec and Mermaid diagrams.
* Create the Prism-Vault separable subproject boundary and independent
  version/build plan inside the Prism umbrella.
* Define `vault_service.py`, `/vault` HTTP router, schemas, settings-backed
  provider, and router tests.
* Prove masked metadata, runtime resolve shape, config get, service-scope
  denial, header-bound audit caller, agent `run_ref` requirement, audit
  fail-closed seam, and no raw value in error paths.
* Do not introduce durable `prism_vault_*` tables or real provider behavior.

### Phase 0B - Durable audit and policy floor

* Add append-only Vault audit migration/model/sink.
* Require audit attempt/reservation before provider read.
* Finalize success, denial, and failure audit before returning.
* Fail closed if audit is unavailable.
* Keep raw secret values out of Prism SQL.
* Add provider-neutral tests for audit success, denied, missing, and
  audit-unavailable paths.

### Phase 0C - MCP verb parity

* Add thin `mcp-node` shims for `prism_vault_secret_get_metadata`,
  `prism_vault_secret_resolve`, and `prism_vault_config_get`.
* Add MCP smoke proving the shims call the `/vault` HTTP source contract.
* Do not add a standalone SDK in v0.1.

### Phase 1 - Prism LAN provider

* Implement Vault KV v2 adapter for LAN mode.
* Add non-root app token and scoped policy.
* Add health/readiness probe for Vault availability and policy identity.
* Prove Prism agents and Prism backend services resolve only Prism-scoped
  records without cross-project leakage.

### Phase 2 - Prism local provider

* Implement Vault KV v2 adapter for local mode.
* Implement Prism local bootstrap for Prism-scoped config and secrets.
* Treat `.env` as seed input only; state and audit still go through
  Prism-Vault.
* Prove Prism can put metadata, get masked metadata, resolve for a Prism runtime
  purpose, and observe audit.

### Phase 3 - Prism Render provider

* Add Render adapter for service-level env/secret bindings.
* Define Render deploy env contract and smoke probes.
* Prove Render deployment serves the same Prism-Vault API contract as local/LAN.
* Make Prism-Vault the default service of record in Render.
* Use Render-native env/secret bindings only where the Render service boundary
  truly requires native injection; document each exception.

### Phase 4 - Prism operations

* Add operator UI/API for masked metadata, config version history, promotion,
  policy creation, and audit lookup.
* Add monthly and manual-on-demand rotation hooks for common Prism provider keys.
* Add export/import for Prism project migration between local, LAN, and Render.

### Phase 5 - Janus and DPA-Crawl collaboration

* Add Janus/DPA-Crawl as later consumers after Prism paths are stable.
* Add worker caller kind and job-scoped policy gates.
* Prove WebCrawl job credential resolution with `job_id`.
* Keep non-Prism integration behind explicit policy and audit.

## Acceptance Criteria

* Prism can store masked metadata for Prism-scoped records.
* Prism agents can resolve an allowed Prism runtime secret and cannot resolve it
  outside the allowed purpose/scope.
* Prism backend services can consume Prism-Vault config in local, LAN, and
  Render modes.
* Local and LAN pass the same Prism-Vault contract tests against different
  providers.
* Render passes the same API contract, with provider-specific differences hidden
  behind the adapter.
* Masked metadata read never returns raw values.
* Every resolve emits an audit event with caller, scope, purpose, run\_ref when
  present, provider, result, and value hash.
* Missing or unmapped tenant/project identity fails closed.
* Prism-Vault has separable subproject version/build/deploy metadata sufficient
  for later extraction from the Prism umbrella.
* Render mode treats Prism-Vault as the default service of record, with
  Render-native secret bindings documented as explicit exceptions.
* Monthly and manual-on-demand rotation policy is documented and audited.
* Provider adapter credentials remain isolated by deployment mode and are not
  exposed through runtime config or cross-mode resolution.
* Agent/worker callers cannot create or modify access policies.
* Purpose validation rejects unregistered purpose strings unless an explicit
  per-record wildcard rule exists.
* Audit evidence is append-only, retained for at least 12 months, and created
  before any resolved value is returned.
* Rotation/revocation docs explicitly state TTL as the max exposure window and
  document an emergency revocation path independent of normal TTL expiry.
* Janus/DPA-Crawl acceptance is deferred to Phase 5 and is not a v0.2 ship gate.

## Ownership

* Architecture: Texi
* First consumer: Prism
* Prism backend integration: Donna / Prism backend owner
* Install/deploy: Lafonda
* Governance/security review: Candi
* Viewer/review coordination: Carla
* Later collaboration: Janus / DPA-Crawl after Prism rollout gates pass
