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

# Piping & secrets

> How to feed secret values, file bodies, and stdin into the CLI safely.

Many CLI commands take content that could be:

* Sensitive (API keys, tokens, DB URLs).
* Large (multi-line prompts, markdown notes, JSON payloads).
* Coming from another process (a previous command's output).

The CLI supports a consistent input syntax for these across every subcommand.

## The three input modes

Wherever the CLI accepts a value that could be a secret, a file, or a pipe, it recognizes:

* `?` — **prompt interactively**. Input is masked for secret fields, unmasked otherwise.
* `-` — **read one line from stdin**. Pipe-friendly.
* `@<path>` — **read from a file**. Whole-file content becomes the value.
* Any other value — **used literally**, with a shell-history warning for secret fields.

Examples:

```bash theme={null}
# Interactive prompt
nora tools headers add t_api --name Authorization --value ?

# Pipe from previous command
echo -n "$MY_TOKEN" | nora providers set openai --stdin

# From file
nora agents update ag_1 --set-prompt-file prompts/support.md

# Literal (avoid for secrets)
nora tools headers add t_api --name Authorization --value "Bearer sk-..."
```

## Which fields accept which mode

Most non-secret fields (names, descriptions, prompts) accept `@<path>` for file-based input. Secret-sensitive fields (`--api-key`, `--auth-value`, header values, DB URLs) also accept `?` for masked prompt and `-` for stdin.

When in doubt, `<command> --help` shows the specific input contract for each flag.

## Reading a value from another CLI

Anywhere you can pass a literal, you can pass a subshell:

```bash theme={null}
nora providers set openai --stdin <<< "$(vault read -field=key secret/nora/openai)"

nora tools headers add t_api \
  --name Authorization \
  --value "Bearer $(aws secretsmanager get-secret-value --secret-id nora/api --query SecretString --output text)"
```

## Passing multi-line content

`@file` for anything multi-line — prompts, note bodies, JSON payloads:

```bash theme={null}
nora agents update ag_1 --set-prompt-file prompts/support-v3.md

nora memory notes upsert sp_wiki \
  --path playbooks/refunds.md \
  --body @refunds.md
```

Or heredoc + stdin:

```bash theme={null}
cat <<'PROMPT' | nora agents update ag_1 --set-prompt -
You are a support assistant.
Answer questions about billing, refunds, and account issues.

If unsure, say so explicitly.
PROMPT
```

Note: not every command supports `-` for this specific flag — `--help` confirms.

## Secrets and shell history

Passing a secret as a literal on the command line writes it to your shell history. Not just risky — often violates security policy.

Symptoms:

```bash theme={null}
# BAD — this goes in ~/.bash_history / ~/.zsh_history
nora providers set openai sk-abc123...
```

Fix:

```bash theme={null}
# Good — one of:
nora providers set openai --env OPENAI_API_KEY       # env var
nora providers set openai --stdin < ~/.nora/openai   # file (with 0600 perms)
echo "$OPENAI_API_KEY" | nora providers set openai --stdin
nora providers set openai --stdin                    # interactive prompt (paste)
```

The CLI warns when it detects a secret-shaped literal but doesn't refuse — you can override if you have your reasons.

## Piping between nora commands

Because many commands support `--json`, they compose:

```bash theme={null}
# Delete all superseded documents (with confirmation)
nora documents list --json | \
  jq -r '.[] | select(.superseded) | .id' | \
  xargs -n1 nora documents delete
```

```bash theme={null}
# Publish every Flow that has an unpublished draft
nora flows list --json | \
  jq -r '.[] | select(.draft_differs_from_published) | .slug' | \
  while read slug; do
    nora flows publish "$slug" --summary "batch publish $(date +%Y-%m-%d)"
  done
```

## Reading complex structures via jq

Most `--json` output is arrays or objects. Common patterns:

```bash theme={null}
# Get first agent block's ID
nora flows get support | jq -r '.blocks[] | select(.kind=="agent") | .id' | head -n1

# Sum trace cost
nora traces list --from 2026-07-01 --json | jq '[.[].cost_cents] | add / 100'

# Filter by nested field
nora agents sources list ag_1 --json | jq '.[] | select(.preset=="high-precision")'
```

## Environment variables for CI

The CLI reads env vars for auth and workspace context:

```yaml theme={null}
env:
  NORA_TOKEN: ${{ secrets.NORA_TOKEN }}
  NORA_TENANT: ${{ vars.NORA_WORKSPACE }}
  OPENAI_API_KEY: ${{ secrets.OPENAI_API_KEY }}
```

Then commands become:

```bash theme={null}
nora providers set openai --env OPENAI_API_KEY
nora flows publish support --summary "$GIT_COMMIT_MSG"
```

No credentials in the command line, no state written to disk.

## Quoting rules

Bash and zsh handle quoting differently for special chars in shell values. If a value contains spaces, `$`, `!`, or `#`:

```bash theme={null}
# Safe: single quotes preserve everything literally
nora agents update ag_1 --set-prompt 'You are $friendly.'

# Or use --set-prompt-file to sidestep quoting entirely
nora agents update ag_1 --set-prompt-file prompt.md
```

Interpolation-heavy JSON payloads: use `jq -c` to compact a JSON file into a single line:

```bash theme={null}
nora retrieval presets upsert my-preset \
  --name "My preset" \
  --config "$(jq -c . preset.json)"
```

## Exit codes

The CLI follows standard Unix exit codes:

* `0` — success.
* `1` — general error.
* `2` — misuse (bad flags, missing required args).
* `4` — not authenticated.
* `8` — permission denied (auth OK but role insufficient).
* `16` — server error (5xx from platform).
* `64` — command not found or malformed.

CI can gate on exit code:

```bash theme={null}
if ! nora flows publish support --summary "$MSG"; then
  echo "Publish failed"
  exit 1
fi
```

## When something's not working

* Turn on `--verbose` to see the full request/response.
* Check `nora auth status` to confirm workspace and token.
* Confirm the pinned Flow: `nora flows current`.
* For CI, echo the exit code: `nora flows publish support; echo "Exit: $?"`.
