---
slug: cli/secrets
title: afy secrets — Aetherfy agent and workspace secrets
kind: reference
surface: cli
summary: Reference for afy secrets in the Aetherfy CLI — list, set, and delete agent-scoped or workspace-scoped secrets, the --workspace and --stdin flags, the AETHERFY_ reserved prefix, and the rule that agent secrets override workspace secrets.
sources:
  - aetherfy-cli:cmd/secrets.go
  - aetherfy-cli:internal/api/secrets.go
---

# afy secrets

## The afy secrets command group in the Aetherfy CLI

`afy secrets` manages encrypted configuration values for Aetherfy agents. The
group has two aliases, `secret` and `s`.

| Subcommand | Purpose |
|---|---|
| `afy secrets list [agent]` | List secret keys (never values) |
| `afy secrets set [agent] <KEY=value>...` | Create or replace secrets |
| `afy secrets delete [agent] <key>` | Delete one secret |

Every subcommand works in one of two scopes:

| Scope | How to select it |
|---|---|
| Agent-scoped | Pass the agent name as the first positional argument |
| Workspace-scoped | Pass `--workspace <name>` / `-w <name>` instead |

## Listing Aetherfy secrets

`afy secrets list [agent]` lists the secret keys in a scope.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--workspace` | `-w` | string | empty | Workspace name (for workspace-scoped secrets) |

Provide an agent name **or** `--workspace`, not both.

```bash
# Agent-scoped
afy secrets list catalogue-scraper

# Workspace-scoped
afy secrets list --workspace research

# As JSON
afy secrets list catalogue-scraper -o json
```

The table has three columns: Key, Created, Updated. **Values are never returned
by Aetherfy** — there is no command that reads a secret back. `afy secrets list`
is the only Aetherfy list command that emits `[]` for an empty result under
`-o json`.

## Setting Aetherfy secrets

`afy secrets set` creates or replaces secrets. Setting an existing key
overwrites it.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--workspace` | `-w` | string | empty | Workspace name (for workspace-scoped secrets) |
| `--stdin` | | bool | false | Read secret value from stdin |

Argument parsing depends on the scope, which is the one genuinely confusing part
of this Aetherfy command:

| Scope | Positional arguments |
|---|---|
| Without `--workspace` | The **first** argument is the agent name; every argument after it is a `KEY=value` pair |
| With `--workspace` | **All** positional arguments are `KEY=value` pairs |

```bash
# Agent-scoped, several at once
afy secrets set catalogue-scraper OPENAI_API_KEY=sk-xxxx DB_URL=postgres://...

# Workspace-scoped — no agent argument
afy secrets set --workspace research SHARED_TOKEN=abc123
```

Malformed pairs are reported and skipped; the Aetherfy CLI does not abort the
whole command because one argument lacks an `=`.

`--stdin` reads the value from standard input and requires **exactly one key
name** as the argument — a bare key, not a `KEY=value` pair. This keeps the
secret out of your shell history and out of the process list:

```bash
# Agent-scoped
printf '%s' "$OPENAI_KEY" | afy secrets set catalogue-scraper OPENAI_API_KEY --stdin

# Workspace-scoped
cat private.pem | afy secrets set --workspace research SIGNING_KEY --stdin
```

## Deleting an Aetherfy secret

`afy secrets delete [agent] <key>` removes a single secret.

| Flag | Short | Type | Default | Description |
|---|---|---|---|---|
| `--workspace` | `-w` | string | empty | Workspace name (for workspace-scoped secrets) |

With `--workspace` you pass only the key. Without it, you pass the agent name and
then the key.

```bash
# Agent-scoped
afy secrets delete catalogue-scraper OPENAI_API_KEY

# Workspace-scoped
afy secrets delete --workspace research SHARED_TOKEN
```

There is **no `--force` flag** on `afy secrets delete`. It always asks for
confirmation, which makes it unsuitable for a non-interactive Aetherfy pipeline.

## How Aetherfy resolves secret scope and precedence

An Aetherfy agent sees the union of the secrets in its workspace and its own
agent-scoped secrets.

| Situation | Result |
|---|---|
| Key exists only on the workspace | The workspace value is injected |
| Key exists only on the agent | The agent value is injected |
| Key exists on both | **The agent-scoped value wins** |

Agent-scoped secrets override workspace-scoped secrets with the same key. This is
how a single Aetherfy agent overrides a shared workspace default without changing
the workspace.

## Reserved key names in Aetherfy secrets

Any key beginning with `AETHERFY_`, in any letter case, is reserved by the
platform and rejected. `AETHERFY_API_KEY`, `aetherfy_region`, and
`Aetherfy_Anything` are all refused.

The reservation exists because Aetherfy injects its own `AETHERFY_`-prefixed
variables into the agent environment — including the
`AETHERFY_AGENT_<NAME>_URL` variables that let agents in a workspace reach each
other. See [/cli/workspaces](/cli/workspaces).

## How Aetherfy delivers secrets to an agent

| Property | Behaviour |
|---|---|
| Storage | Encrypted at rest by Aetherfy |
| Delivery | Injected into the agent process as environment variables |
| Readback | Never — no Aetherfy command or API returns a secret value |
| Propagation | Changing a secret does **not** redeploy a running agent |

Because a change does not redeploy, a new value takes effect on the next
`afy deploy` or the next run of the agent. To pick up a rotated credential
immediately on a running service agent, redeploy it:

```bash
afy secrets set catalogue-scraper OPENAI_API_KEY --stdin < newkey.txt
afy deploy
```

Note also that `.env` and `.env.*` files are excluded from every Aetherfy deploy
archive, so secrets must go through this command group rather than being shipped
as files. See [/cli/deploy](/cli/deploy).
