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

# Records and secrets

> Create, read, inject, rotate and share encrypted records without sending plaintext to AIRCTRL.

export function AirctrlWordmark() {
  return <span className="airctrl-wordmark" aria-label="AIRCTRL">
      <span aria-hidden="true" className="airctrl-wordmark-air">AIR</span>
      <span aria-hidden="true" className="airctrl-wordmark-ctrl">CTRL</span>
    </span>;
}

A record stores one encrypted secret and its metadata. Record plaintext is encrypted and decrypted in the SDK, CLI, Web app, or local MCP process.

## Choose the right surface

* Use the **SDK** inside an application or script.
* Use the **CLI** to inject records into a child process without writing a `.env` file.
* Use **MCP** when an agent needs an approved <AirctrlWordmark /> action.
* Use the raw **API** for metadata and pre-encrypted payloads. Prefer the SDK for values because it performs the required cryptography.

## Read one record

### SDK

```ts theme={}
const secret = await airctrl.getSecret({
  recordId: '00000000-0000-4000-8000-000000000100',
  vaultPassword: process.env.AIRCTRL_VAULT_PASSPHRASE!,
})

console.log(secret.name)
console.log(secret.fields)
```

`getSecret` returns the decrypted value and parsed fields. The decryption happens in your process.

Use `readRecord` when you want selected sections instead of the complete record:

```ts theme={}
const record = await airctrl.readRecord({
  recordId: '00000000-0000-4000-8000-000000000100',
  scope: ['meta', 'fields'],
  vaultPassword: process.env.AIRCTRL_VAULT_PASSPHRASE!,
})
```

### CLI

Print only the secret value:

```bash theme={}
airctrl get 00000000-0000-4000-8000-000000000100
```

Read structured fields and metadata:

```bash theme={}
airctrl read 00000000-0000-4000-8000-000000000100 --scope meta,fields
```

### MCP

The MCP server reads the vault passphrase from `AIRCTRL_MCP_VAULT_PASSWORD`, never from the prompt.

<Warning>
  An agent can see values returned by a record tool. Only call a decryption tool when the model is allowed to receive that secret.
</Warning>

```text theme={}
Read only the "username" and "password" fields from the production environment
of record "00000000-0000-4000-8000-000000000100". Use them only for this task.
Do not print, log or repeat their values in your response.
```

<div className="technical-reference">
  **MCP tool used:** `read_record`
</div>

## Inject a project into a process

The CLI converts record names to uppercase environment variable names and injects them only into the child process.

```bash theme={}
airctrl run --project 00000000-0000-4000-8000-000000000010 -- node server.js
```

For example, `Database URL` becomes `DATABASE_URL`. <AirctrlWordmark /> control variables are removed before the child starts.

SDK equivalent:

```ts theme={}
const records = await airctrl.getAll({
  projectId: '00000000-0000-4000-8000-000000000010',
  vaultPassword: process.env.AIRCTRL_VAULT_PASSPHRASE!,
})

const environment = Object.fromEntries(
  records.map((record) => [record.name, record.value]),
)
```

### MCP is different

MCP does not inject values into a child process. It returns tool results to the agent. Prefer the CLI when the goal is only to start an application without a `.env` file. A bulk MCP read exposes decrypted values to the agent, so use it only in an approved context.

When the agent is explicitly allowed to use every accessible value in one project, ask:

```text theme={}
Load every accessible record from project
"00000000-0000-4000-8000-000000000010" for this task. Use the values only as
runtime input. Do not print, summarize or retain them after the task.
```

<div className="technical-reference">
  **MCP tool used:** `get_all`
</div>

## Create a record

Use `createSecret` with the fields required by the selected secret format:

```ts theme={}
const result = await airctrl.createSecret({
  projectId: '00000000-0000-4000-8000-000000000010',
  name: 'Payments database',
  secretFormat: 'database',
  fieldValues: {
    engine: 'postgresql',
    host: 'db.internal.example',
    port: '5432',
    database: 'payments',
    username: 'payments-app',
    password: process.env.SOURCE_DATABASE_PASSWORD!,
  },
  tags: ['payments', 'production'],
  idempotencyKey: '00000000-0000-4000-8000-000000000120',
  vaultPassword: process.env.AIRCTRL_VAULT_PASSPHRASE!,
})

console.log(result.recordId)
```

CLI:

```bash theme={}
airctrl create database \
  --project 00000000-0000-4000-8000-000000000010 \
  --name "Payments database" \
  --field engine=postgresql \
  --field host=db.internal.example \
  --field port=5432 \
  --field database=payments \
  --field username=payments-app
```

Avoid placing sensitive field values directly in shell history. For files of environment variables, use:

```bash theme={}
airctrl import env ./source.env \
  --project 00000000-0000-4000-8000-000000000010 \
  --name "Payments environment" \
  --target-env production
```

### MCP

Supply secret values only when the model is authorized to receive them.

```text theme={}
Create a database record named "Payments database" in project
"00000000-0000-4000-8000-000000000010" using values from the approved local
secret source. Show the project, name, format and field names, but never the
field values. Wait for my confirmation before creating it.
```

<div className="technical-reference">
  **MCP tool used:** `create_record`
</div>

## Generate a new secret

<AirctrlWordmark /> can generate supported material locally and store it in one operation. Supported generators include passwords, API keys, TOTP seeds, SSH keys, certificates, webhook secrets, and OAuth client secrets.

```ts theme={}
await airctrl.createGeneratedRecord({
  projectId,
  name: 'Webhook signing key',
  secretFormat: 'webhook',
  vaultPassword: process.env.AIRCTRL_VAULT_PASSPHRASE!,
})
```

```bash theme={}
airctrl new webhook --project "$PROJECT_ID" --name "Webhook signing key"
```

MCP request:

```text theme={}
Create a webhook secret named "Webhook signing key" in project
"00000000-0000-4000-8000-000000000010". Generate its value locally. Show only
the non-secret details and wait for my confirmation. Never print the generated
value.
```

<div className="technical-reference">
  **MCP tools used:** `generate_secret`, `create_record`
</div>

## Update, rotate and roll back

* `setSecret` saves a new encrypted value version.
* `rotateRecord` creates a new data key and encrypted value.
* `rollbackRecordToVersion` makes an earlier encrypted version current without deleting history.
* `updateRecordMetadata` changes name, tags, due date, or rotation interval without changing the value.

CLI equivalents are `set`, `record rotate`, `record rollback`, and `record metadata`.

MCP equivalents are `set_secret`, `rotate_record`, `rollback_record`, and `update_record_metadata`.

## Share and revoke

<div className="section-help">
  Sharing encrypts the record key for the recipient. It does not share your vault passphrase.

  The same pattern exists for Service Accounts and groups. CLI uses `record share-user`, `share-sa`, `share-group` and their matching `revoke-*` commands.
</div>

```ts theme={}
await airctrl.shareRecordWithUser({
  recordId,
  granteeUserId,
  permission: 'read',
  vaultPassword: process.env.AIRCTRL_VAULT_PASSPHRASE!,
})

await airctrl.revokeRecordFromUser(recordId, granteeUserId)
```

MCP request:

```text theme={}
Give user "00000000-0000-4000-8000-000000000050" read access to record
"00000000-0000-4000-8000-000000000020". Confirm both resources and wait for
my approval. After I confirm, change only this direct user grant.
```

To remove that direct grant later:

```text theme={}
Remove user "00000000-0000-4000-8000-000000000050" from record
"00000000-0000-4000-8000-000000000020". Explain that access will end
immediately and wait for my confirmation. Do not change any other grant.
```

<div className="technical-reference">
  **MCP tools used:** `share_record_user`, `revoke_record_user`
</div>

## History and audit

Use record versions, record audit, anomalies, activity, alerts, and access feeds to understand changes without exposing plaintext. Project-scoped audit feeds require `audit:read`.

## Common failures

* `403 not_authorized`: the caller lacks record access or the required action permission.
* `404 record_not_found`: the ID is wrong or unavailable in the active account.
* `409 record_name_exists`: another record already uses that name where uniqueness is required.
* `409 project_not_keyed`: refresh project key state before retrying the operation.
