Operations
Layer CLI
The layer CLI operates hevlayer from the terminal. It manages
named environments, initializes adopted namespaces for sharding, observes
index, pipeline, and UDF state from the gateway, mints and revokes API keys,
shows VectorStore and Warehouse health, and runs Function manifests. Every
read goes through the gateway API with an API key; only run touches
Kubernetes — it applies the Function CR, registers the
UDF spec with the gateway, triggers discovery, and optionally watches until the
queue drains. run is the only command that needs a kube context: set it on
the environment with --kube-context/--kube-namespace or per invocation with
--context/--kube-namespace.
Install
From the repository root:
go build -o layer ./apps/layer-cli
Configuration
layer reads named environments from ~/.hevlayer/config.toml.
The directory is created with mode 0700; the config file is written
with mode 0600.
active = "partner"
[envs.partner]
base_url = "https://aws-us-east-1.hevlayer.com"
api_key = "..."
kube_context = "partner-cluster"
kube_namespace = "hevlayer"
[envs.local]
base_url = "http://localhost:8080"
api_key = "dev"
kube_context = "kind-hevlayer"
Resolution order is:
| Priority | Source |
|---|---|
| 1 | Explicit flags such as --base-url, --api-key, --context, and --kube-namespace |
| 2 | LAYER_BASE_URL, LAYER_API_KEY, and the HEVLAYER_ twins |
| 3 | Environment selected by --env or LAYER_ENV |
| 4 | Active environment in ~/.hevlayer/config.toml |
| 5 | Built-in base URL default |
A shell exporting LAYER_BASE_URL or LAYER_API_KEY keeps the
env-var-only behavior and does not need a config file. --env and
LAYER_ENV select an environment for one invocation without changing
the active environment.
| Flag | Environment | Default |
|---|---|---|
--base-url | LAYER_BASE_URL, HEVLAYER_BASE_URL | https://aws-us-east-1.hevlayer.com |
--api-key | LAYER_API_KEY, HEVLAYER_API_KEY | none |
--env | LAYER_ENV | active config env |
-o, --output | none | table |
Output formats are table, json, and names.
Environments
layer env add partner --base-url https://aws-us-east-1.hevlayer.com \
--api-key "$LAYER_API_KEY" --kube-context partner-cluster \
--kube-namespace hevlayer
layer env use partner
layer env ls
layer env show partner -o json
layer env rm partner
env add prompts for missing values on a TTY. On a non-TTY, the
required values must be supplied by flags. API keys are masked in
env ls and env show.
Initialize a Namespace
layer init products --shards 8
layer init products --shards 8 --watch=false
layer init products --shards 8 --poll-interval 5s
init calls POST /v2/namespaces/{namespace}/init through the selected
gateway environment. The command creates or reattaches to the namespace shard
marker, starts the shard backfill, and watches by default until
shard_lag_rows reaches 0 and scatter/gather is active. Re-running with the
same shard count is idempotent; requesting a different shard count returns a
conflict message instead of changing the marker.
Run A Function
layer run -f tag-products.yaml
layer run -f tag-products.yaml --index amazon-products-staging
layer run -f tag-products.yaml --detach
layer run -f tag-products.yaml --rm
The input is a Kubernetes Function manifest. --index overrides
spec.targetNamespaces with one target. --context selects a
kubeconfig context; --kube-namespace selects the Kubernetes namespace
for the Function CR. --no-apply skips the Kubernetes apply step for
workers managed outside the operator.
spec.version is registered with the gateway as the Function completion
marker version. Bump it before re-running a Function after changing a
model, prompt, taxonomy, or worker write contract.
--detach returns after registration and discovery. Without --detach,
the CLI polls UDF status until discovery has completed and
pending_count and processing_count are both zero. A drained queue
with failures exits non-zero.
--rm deletes the gateway registration and, unless --no-apply is
set, the Function CR after the queue drains cleanly. A drain with
failures leaves both in place so you can inspect them.
Watch a run from another terminal:
layer udf list
layer udf get product-tags --watch
udf list lists registered UDFs with pending, processing, failed, discovery
sweep count, and indexed rate. udf get shows those fields for one UDF;
--watch polls until pending_count and processing_count are both zero.
TUI
Bare layer on a TTY opens the read-only operations TUI (layer browse is
the explicit spelling); on a non-TTY it prints usage and exits 2. Press
i/f/p/k/e to switch between indexes, functions, pipelines, keys,
and environments from any view, enter to open a detail view, and esc/q
to back out. Every view has a non-interactive command twin with the same
data — the TUI humanizes timestamps and sizes; the commands emit raw values
for scripting.
| TUI view | Command |
|---|---|
| Environments | layer env ls |
| Functions | layer udf list |
| Function detail | layer udf get UDF_ID [--watch] |
| Indexes | layer index list |
| Index detail | layer index get NAME |
| Pipelines | layer pipeline list |
| Pipeline detail | layer pipeline get ID |
| Keys | layer keys ls |
| Key detail | layer keys get KEY_ID |
The keys views are read-only like the rest of the TUI: minting and revoking stay in the commands.
Keys
layer keys mint cohort-reader --owner acme \
--entitle vectorstore.prod-turbopuffer=read \
--namespaces "cohort-*" \
--claim warehouse.prod-snowflake="notes:cohort:*:read"
layer keys ls
layer keys get cohort-reader
layer keys revoke cohort-reader
layer keys rm cohort-reader
keys mint creates the key through the gateway and prints the token
once — alone on stdout, so layer keys mint … | pbcopy captures it;
the metadata table goes to stderr. There is no way to print it again.
keys revoke is the default way to retire a key and keeps its audit record.
keys rm is rare permanent cleanup and accepts only a key already in the
Revoked phase.
| Flag | Shape |
|---|---|
--entitle | TARGET[=SCOPE[+SCOPE]], repeatable. Targets are vectorstore.<name>, warehouse.<name>, or layer. |
--namespaces | Upstream-namespace globs for the vectorstore entitlement, comma-separated. |
--claim | TARGET=STRING, repeatable. Appends an opaque claim string to that target’s entitlement. |
--expires-after | Duration or never; defaults to 365d. |
--entitle layer=admin mints an admin key. For anything longer than a
couple of flags, write the object instead: layer keys mint -f key.yaml
takes the same ApiKey manifest kubectl apply does.
keys ls and keys get show metadata only — key id, owner, phase,
entitlement targets, expiry, last seen — never tokens or hashes.
revoke is idempotent and keeps the record; rm hard-deletes it. All
keys commands call the gateway key routes, which require a key with
the layer entitlement at admin scope (or the bootstrap gateway
key); no kube access is involved.
Vector Store And Warehouse
layer vectorstore list
layer vectorstore get
layer vectorstore get prod-turbopuffer -o json
layer warehouse list
layer warehouse get prod-snowflake
vectorstore list shows declared stores with kind, default marker,
region, reachability, and turbopuffer org id. vectorstore get prints
endpoint, credential Secret reference, inbound auth mode, reachability,
observed generation, and the turbopuffer dashboard link when the store
has spec.turbopuffer.orgId. Without a name, vectorstore get selects
the default-marked store, or the only store when exactly one exists.
warehouse list leads with name, kind, phase, verification time, and
consumer counts. warehouse get NAME shows the Snowflake source identity,
credential Secret reference, verification status, failure reason, and
what still depends on the warehouse. These commands are read-only and
gateway-backed; they never read or print Secret contents.
Ask The Docs
layer ask queries the committed docs digest with the ask CLI. It is
keyless and local by default: from a checkout, it finds site/.hev-ask, prefers
a sibling ../ask source checkout, and falls back to the docs site’s installed
@hevmind/ask package or an ask binary on PATH.
layer ask tree
layer ask grep "warm cache"
layer ask cat api/query
layer ask glossary get watermark
layer -o json ask tree
Use --endpoint to query a deployed hev ask endpoint instead of the local
digest:
layer ask --endpoint https://hevlayer.com/api/ask tree
Inspect An Index
layer index get shop-products
layer index get shop-products -o json
index get reports row count, size, schema summary, last write, stable
watermark and lag, index (WAL) status, cache state, and snapshot history.
Timestamps and sizes are raw (epoch-ms, bytes); -o json carries the full
snapshot list.
Manage Snapshots
layer index snapshot shop-products --field category
layer index policy shop-products --facet-field category --facet-field brand --interval 5m --retention 30d
index snapshot creates an on-demand snapshot job and waits for it to
complete. index policy writes the same facetFields, interval, and
retention shape used by Index.spec.snapshot, so shared-gateway
namespaces can enable the automatic writer without applying a Kubernetes
resource.
Delete An Index
layer index delete shop-products
layer index delete shop-products shop-products-staging
layer index delete --prefix shop-
layer index delete --prefix shop- --yes
index delete purges the upstream turbopuffer namespace, document cache
rows and snapshot mirrors, S3 snapshots/search history/clickstream/shard
metadata, in-memory job state, and the operator-discovered Index CR where
GC is enabled. Pass one or more names, or --prefix to delete every index
whose name starts with that prefix — name arguments and --prefix are
mutually exclusive, and the prefix must be non-empty.
The prefix form lists the matched indexes for confirmation before deleting;
on a TTY it prompts, and --yes skips the prompt. --yes is required when
stdin is not a TTY. A prefix that matches nothing exits 0 without deleting.
Pipelines
layer pipeline list
layer pipeline get product-images
pipeline list reads registered pipelines and fans out to the
pipeline status API for each one’s
live queue depth (pending, processing, failed, rate/min); pipeline get adds target namespace, distance metric, and created-at. A pipeline with
no worker staged into it yet renders without queue counts rather than
erroring. Reads need only an API key — no kube access.
layer push is deferred to the managed build/dev-loop milestone.