CLI

Login, profiles and environment

One login covers every document base in a workspace. Profiles let one machine talk to several environments, environment variables cover CI where a config file is the wrong shape, and the credential never crosses the network in the clear.

Logging in

engram login --api-key <your key> --api-url https://api.engramdynamics.org

Login validates before it stores. It makes a real authenticated call against the contract the profile will use, so a typo, a revoked key or a URL pointing at nothing fails here rather than on your next command. What it prints is the URL, the profile, how many document bases the key can see, the API contract, and the file it wrote.

Two checks run before that call, both about the credential rather than the account. The key has to be something an HTTP header can carry, which means printable ASCII with no whitespace, and the URL has to be somewhere a bearer token can safely be sent. Neither is worth a network round trip to discover.

Leave --api-key off and the CLI prompts for it with the input hidden, so the key stays out of your shell history and scrollback. With nobody at the keyboard, it refuses rather than waiting:

error: No API key given. Pass --api-key or set ENGRAM_API_KEY.

That exits 2 and sends nothing. It matters on Windows, where a password prompt reads the console rather than stdin, so a script with stdin redirected used to sit at the prompt forever.

Where credentials live

Profiles live in one TOML file in your user config directory:

PlatformPath
Windows%LOCALAPPDATA%\engram\config.toml
macOS and LinuxThe user config directory for your OS, for example ~/.config/engram/config.toml

engram profiles prints the exact path on the machine you are on, along with every profile and the first characters of its key. The stored secret is never printed in full.

engram profiles

The file holds a live credential, so it is written owner-only wherever the OS honours POSIX modes. On Windows it lands under the per-user LOCALAPPDATA tree, which is not world-readable by default. Its shape:

[profiles.default]
api_url = "https://api.engramdynamics.org"
api_key = "ek_live_..."
api_version = "legacy"

[profiles.uat]
api_url = "https://uat-api.engramdynamics.org"
api_key = "ek_uat_..."
api_version = "1"

Several environments on one machine

Every command takes --profile, or -p, and it works before or after the subcommand. Log in once per environment:

engram login --api-key <prod key>
engram login --profile uat --api-key <uat key> --api-url https://uat-api.engramdynamics.org

engram corpora list                 # the default profile
engram corpora list --profile uat   # the other one

The profile also decides which URL and key an MCP config block carries, so a block printed for one environment points at that environment:

engram mcp --profile uat

Logging in again under the same profile name replaces that profile and leaves every other one untouched.

Environment variables

In CI, writing a config file is the wrong shape: the key comes from a secret store. Environment variables cover that, and they win over the stored profile.

VariableEffect
ENGRAM_API_KEYThe API key to use. Overrides the profile's stored key.
ENGRAM_API_URLThe control-plane base URL. Overrides the profile's URL.
ENGRAM_API_VERSIONThe API contract: legacy, 1, or auto.
ENGRAM_CONFIG_DIRWhere to keep config.toml, for a config beside a project or in a test.

Precedence, highest first: the environment variables, then the named profile in the config file, then the built-in default URL. That last one is why engram login --api-key ... needs no URL at all.

export ENGRAM_API_KEY="$ENGRAM_KEY_FROM_SECRET_STORE"
engram push ./docs --corpus "Support KB" --json

With only the variables set, no config file is written or needed, which is exactly what you want in a container. engram status reports where the credentials came from as env, config, or config+env.

Why plain http is refused

Point a profile at an http:// URL and the CLI stops:

error: Refusing to send your API key over plain http. Use https://, or pass --insecure
for a local server.

This is not pedantry. The production load balancer answers http with a redirect to https, so by the time the client follows the redirect the Authorization header has already crossed the network in the clear. The rule is simple: https always passes, plain http passes only against localhost, 127.0.0.1 or ::1, and --insecure is the deliberate override for a control plane on your own machine.

engram login --api-key <dev key> --api-url http://localhost:8000            # allowed
engram login --api-key <dev key> --api-url http://box.internal --insecure  # deliberate

ENGRAM_API_URL never passes through login, so the same check runs where it is read: an insecure URL from the environment is refused at use time, on every command.

API contract

A profile records which API contract it speaks, because "the API is up" and "this client is talking to the paths it thinks it is" are different facts.

ValueMeaning
legacyThe default, and the safe answer. The unversioned paths, which every deployment answers.
1The published /v1 contract: paged list responses and the structured error envelope.
autoAsk the deployment what it serves and take the newest. Resolved once, at login, and the resolved value is what gets stored.
engram login --api-key <your key> --api-version 1

An installed CLI must not change behaviour because a server rolled forward, which is why legacy stays the default. engram status prints the version in play, and it is the first thing to check when a command starts failing against a new deployment.

Checking where you are

engram status

This prints the profile, the URL, the API version, where the credentials came from, whether the API is reachable, whether you are logged in, the current serving state, and how many document bases the key can see. It exits 1 when the API is unreachable or the credential is refused, which is what makes it usable as a gate in a script. Scripting and CI covers that.

Next