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:
| Platform | Path |
|---|---|
| Windows | %LOCALAPPDATA%\engram\config.toml |
| macOS and Linux | The 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.
| Variable | Effect |
|---|---|
ENGRAM_API_KEY | The API key to use. Overrides the profile's stored key. |
ENGRAM_API_URL | The control-plane base URL. Overrides the profile's URL. |
ENGRAM_API_VERSION | The API contract: legacy, 1, or auto. |
ENGRAM_CONFIG_DIR | Where 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.
| Value | Meaning |
|---|---|
legacy | The default, and the safe answer. The unversioned paths, which every deployment answers. |
1 | The published /v1 contract: paged list responses and the structured error envelope. |
auto | Ask 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.