Command-line interface
This page is the reference for foundation4ai, the command-line interface (CLI) of Foundation4. The page describes the global options, the configuration and the connections that the CLI uses, and the arguments, output, errors and exit status of every subcommand. Operators use this page to run maintenance commands in an installation and to read the logs of the installation Jobs. Operator command reference lists the subcommands next to the other operator commands.
Synopsis
foundation4ai [-h | --help] [-V | --version]
foundation4ai <command> [<subcommand>] [<arguments>]
| Command | Arguments | Purpose | Connection |
|---|---|---|---|
server | None | Runs the API server | Full |
worker | None | Runs a worker | Full |
database migrate | None | Applies pending database migrations | Database only |
database check-connection | None | Tests the database connection | Database only |
license system-id | None | Prints the system ID | Database only |
license check | None | Checks the configured license | Database only |
license details | <LICENSE> | Prints the contents of a license | Database only |
data providers | None | Lists the providers of the configured embedding models and text splitters | Database only |
data download-models | None | Downloads the files of the configured embedding models and text splitters | Full |
admin create-admin-api-key | <NAME> [DESCRIPTION] [EXPIRATION] | Creates the master key | Full |
admin update-admin-api-key | [NAME] [DESCRIPTION] | Changes the name or the description of the master key | Full |
admin generate-admin-api-key | <NAME> [DESCRIPTION] [EXPIRATION] | Creates an additional administration key | Full |
help | [<command>] [<subcommand>] | Prints the help of the binary or of a command | None |
Arguments are positional. Angle brackets mark a required argument, and square brackets mark an optional argument. An argument that contains spaces is quoted, as in "Master Admin Key". Subcommands accept no option other than -h and --help, and no subcommand reads standard input or asks for confirmation. Connections describes the two connection types.
Invocation
The API server image contains the binary as /app/foundation4ai, and /app is the working directory of the API server, worker and installation Job containers. Operators run subcommands in the server container of a running API server pod:
kubectl exec -n foundation4ai deploy/foundation4ai-api-server -c server -- ./foundation4ai license system-id
Expected result: the output of the subcommand, here one line of 64 hexadecimal characters. kubectl exec returns the exit status of the subcommand and prints command terminated with exit code <status> for any status other than 0.
The binary runs in the following places:
- Containers. The
servercontainer runs./foundation4ai server, and theworkercontainer runs./foundation4ai worker. Operators do not start either subcommand throughkubectl exec, because the containers already run both processes. - Installation Jobs. The application release runs
database migrate,license checkandadmin create-admin-api-key "Master Admin Key"as installation Jobs at every installation and upgrade, in the order described in Install on Kubernetes. - Image default. A container started from the API server image without arguments runs the binary without a command. The binary then prints the help and exits with status 2, so the charts always pass a command.
Global options
| Option | Effect | Exit status |
|---|---|---|
-h, --help | Prints the help of the binary, or of the command or subcommand before the option, on standard output | 0 |
-V, --version | Prints foundation4ai 0.1.0, the version of the program package | 0 |
help [<command>] [<subcommand>] | Prints the same help as --help | 0 |
The version of the program package does not follow the Foundation4 release. The tag of the API server image identifies the release, as described in Charts, images and installation bundle.
./foundation4ai --help prints the following text:
Foundation4.ai API Server
Usage: foundation4ai [COMMAND]
Commands:
admin Admin commands
license License commands
database Database operations
data Data operations
server Run the API Server
worker Run the Worker
help Print this message or the help of the given subcommand(s)
Options:
-h, --help Print help
-V, --version Print version
The following rules apply to the command line:
- Command groups.
admin,license,databaseanddataare groups of subcommands. A group without a subcommand prints the help of the group on standard error and exits with status 2. - No command. The binary without a command prints the help on standard error and exits with status 2.
- Unknown names. An unknown command or subcommand prints
error: unrecognized subcommand '<name>', followed by similar names when a similar name exists, and exits with status 2.
Configuration
Every subcommand reads the configuration from the working directory in the order that Configuration reference describes: defaults.yaml, config/settings.yaml, the config/f4ai-*.yaml files in name order, then the FOUNDATION4AI__<SECTION>__<KEY> environment variables. The configuration directory is fixed at ./config, and the CLI has no option that changes the directory or a configuration key.
The following rules apply to the configuration of the CLI:
- Complete configuration. Every subcommand parses the whole configuration, including the keys that the subcommand does not use. A missing or invalid required key stops the subcommand with a message such as
Error: "Failed to parse config: missing field `license` for key \"default.app\"". - Start time. A subcommand reads the configuration when the subcommand starts, and the API server and worker processes read the configuration when the processes start. Configuration change describes the restart that applies a change to the running processes.
- Database settings. The database-only subcommands use
database.urlanddatabase.ca_cert, and ignoredatabase.schema,database.embeddings_schemaanddatabase.pool_size. The license subcommands therefore compute the system ID from thepublicschema, as described in Licensing. - Worker pool.
workeruses a database pool of 1 connection, whatever the value ofdatabase.pool_size. - Log level.
app.log_levelapplies toserverandworker. The other subcommands write no log lines, only the output that this page lists. The warning with the system ID that the API server logs after a license failure therefore does not appear in the output of the admin subcommands or ofdata download-models.
Connections
Each subcommand uses one of two connection types:
- Database only.
database migrate,database check-connection, the three license subcommands anddata providersopen one PostgreSQL connection withdatabase.urlanddatabase.ca_cert. These subcommands report every connection failure asError: "Failed connecting to database", without the reason. Database shows how a PostgreSQL client finds the reason. - Full connection.
server,worker,data download-modelsand the three admin subcommands build the same connection as the API server. The full connection needs PostgreSQL with pgvector, a valid license, the Redis-compatible cache, NATS JetStream and a valid application secret.
The full connection runs the following steps in order, and the first failure stops the subcommand:
- Connects to PostgreSQL with the pool size, the schemas and the certificate authority (CA) certificate of the configuration, creates missing schemas and applies pending migrations.
- Computes the system ID from
database.schemaand checksapp.license. - Connects to the Redis-compatible cache.
- Connects to NATS JetStream, and creates the object store
nats.bucketand the streamnats.streamwhen missing. - Decodes the application secret
app.secret. - Prepares the address of the gRPC service in
grpc.url. The connection to the gRPC service opens on first use.
The admin subcommands and data download-models report a failure of any step as Error: "Failed to create database connection: <reason>". The beginning of the reason names the step:
| Reason begins with | Step |
|---|---|
ORM error: | PostgreSQL connection or migration |
Invalid license, Expired license | License check |
Redis error: | Redis-compatible cache |
Nats error: | NATS JetStream |
Decryption error: Error decoding secret key | Application secret |
gRPC error: | Address of the gRPC service |
Before these steps, the full connection reads the four paths keys, and a missing key stops the subcommand with Error: "missing field `<key>`". A cache URL that cannot be parsed stops the process with a panic message instead of an Error: line, as described in Troubleshooting. The messages of server and worker differ and are listed in Troubleshooting.
Output and exit status
Subcommands print results on standard output and errors on standard error:
| Exit status | Meaning | Standard error |
|---|---|---|
| 0 | The subcommand completed, or the help or version was printed on request | Empty |
| 1 | The subcommand failed | Error: "<message>" |
| 2 | The command line is invalid, or names a group without a subcommand, or no command | error: <reason> followed by the usage, or the help |
| 134 | The process stopped on an internal error with the abort signal | A message that contains panicked at |
The following rules apply to the output:
-
Quoted messages. The message after
Error:is printed as a quoted string, so a quotation mark inside the message appears as\". -
License results.
license detailsexits with status 0 when the license is invalid or expired, andlicense checkexits with status 0 after the wait that follows a failed check. Scripts read the printed result, not the exit status. -
Argument errors. An invalid argument prints the reason and a pointer to the help, as in the following output for an expiry without a time:
error: invalid value '2027-01-31' for '[EXPIRATION]': premature end of inputFor more information, try '--help'.
Process subcommands
Server
server runs the API server. The subcommand builds the full connection, authenticates with the master key and listens on app.host and app.port. The process logs at app.log_level, and at the level info the log shows Starting <branding.name> API on <host>:<port>. On the interrupt signal or the termination signal, the API server stops accepting connections, completes open requests and exits with status 0.
The API server reports connection and master key failures after Error: "Failed to initialize server: , and a listen address that cannot be used as Failed to bind to address: <reason>. Troubleshooting lists the messages with the causes.
Worker
worker runs a worker. The subcommand opens the metrics listener on port 9090, builds the full connection with a database pool of 1 connection, and authenticates with the master key. After a wait of 2 seconds, the worker logs Starting Foundation4.ai worker at the level info and fetches processing jobs from NATS JetStream in batches of up to 100 jobs.
The following rules apply to the worker:
- Stop signal. The worker stops on the interrupt signal. The termination signal that Kubernetes sends does not stop the worker, so a stopping worker pod runs until the termination grace period ends, as described in Scaling and performance.
- Startup errors. The worker reports connection failures as
Failed to connect to Foundation4.ai: <reason>, master key failures asFailed to initialize Foundation4.ai: <reason>, and queue consumer failures asError creating message queue consumer: <reason>. When port 9090 is already in use, the worker stops with a panic message that containsFailed to install recorder. - Queue errors. The worker ends the process when a read from the queue fails, as described in Troubleshooting.
Database subcommands
Database migration
database migrate applies the pending migrations of the database schema, records each migration in the table schema_migrations, and prints Migrated to latest schema. The migration Job runs the command before the license check at every installation and upgrade, and the API server, the workers and the master key Job also apply pending migrations at startup.
The following rules apply to the migration:
- Earlier table format. When a table named
schema_migrationswith exactly one column exists, the command drops that table before applying the migrations, because the table then has the format of an earlier Foundation4 version. The database is therefore dedicated to Foundation4, as Database requires. - Direction. Each migration runs in one transaction, and migrations only move forward. The CLI has no command that reverts a migration, as described in Database.
- Errors.
Error: "Failed connecting to database"means that the connection failed.Error: "Failed applying migrations: <reason>"means that the connection succeeded and a migration failed, as described in Troubleshooting.
Database connection check
database check-connection opens a connection with database.url and database.ca_cert and prints Ok. The check covers the address, the credentials and the Transport Layer Security (TLS) settings. The check does not cover the schemas, the migrations or the pgvector extension. A failure prints Error: "Failed connecting to database" without the reason; Operator command reference tests the same connection with a PostgreSQL client that shows the reason.
License subcommands
The license subcommands compute the system ID from the public schema of the database in database.url. Before the first migration, the database has no api_keys table, and the license subcommands fail with Error: "Failed generating system id". Licensing describes licenses and the system ID.
System ID
license system-id prints the system ID as one line of 64 hexadecimal characters. The Foundation4 provider issues a license for this value, as described in Licensing.
License check
license check checks the license in app.license against the system ID and prints two lines:
SystemID: <system ID>
Checking for a valid license... OK
| Result | Meaning | Process after the result |
|---|---|---|
OK | The license is valid for the system ID and has not expired | Exits with status 0 |
Missing | app.license is an empty string | Waits 365 days, then exits with status 0 |
Invalid | The license is malformed, of an unsupported version, or issued for another system ID | Waits 365 days, then exits with status 0 |
Expired | The expiry date of the license has passed | Waits 365 days, then exits with status 0 |
The wait keeps the license check Job running, so the system ID stays in the Job log and the application installation stops at the Helm timeout, as described in Troubleshooting. In a running pod, operators use license details instead of license check. Under the charts, an empty license value in the secrets file stops every installation Job with a configuration error before the check, as described in Secrets and keys.
License details
license details <LICENSE> checks the license given as the argument against the system ID and prints the contents of the license. The license is one argument in quotes:
kubectl exec -n foundation4ai deploy/foundation4ai-api-server -c server -- ./foundation4ai license details '<license>'
Expected result for a license that matches the database:
License: <license holder> (expires on <date> <time> UTC)
System ID: <system ID>
Version: 2
Limits:
Pipelines: <limit>
Documents: <limit>
A license without an expiry date shows (perpetual), and optional Description: and Environment: lines appear when the license carries these fields. Licensing describes every line. For a license that cannot be used, the single line Invalid or Expired replaces the contents, and the command exits with status 0. Operator command reference reads the license value from the secrets file.
Data subcommands
Provider list
data providers lists the distinct providers of the embedding models and of the text splitters in the database, in no fixed order. A database with only the seeded objects of Providers and models produces the following output:
Found embedding providers:
- FastEmbedEmbeddings
Found text splitters providers:
- RecursiveCharacterTextSplitter
- CharacterTextSplitter
- NLTKTextSplitter
The list names the providers that configured objects use, not every provider that Foundation4 supports. Providers and models lists the supported providers.
Model download
data download-models builds the full connection and downloads the files of the configured embedding models and text splitters. For each distinct combination of provider, model and parameters, the command prints Downloading data for embedding provider <provider>, model <model>. The command then prints Found text splitters providers: and one Downloading data for text splitter provider: <provider> line for each distinct text splitter provider and parameters.
| Provider | Download | Destination |
|---|---|---|
FastEmbedEmbeddings | The file named in the onnx parameter, the files in data_files and the tokenizer files, from the Hugging Face Hub; the model name has the form <owner>/<repository> | paths.fastembed in the container that runs the command |
OpenAIEmbeddings | None | None |
GPT4AllEmbeddings | The gRPC service loads the model and downloads the model file | paths.gpt4all in the gRPC service container of the pod |
HuggingFaceEmbeddings | The gRPC service loads the model through the Hugging Face library | paths.huggingface in the gRPC service container of the pod |
HuggingFaceEndpointEmbeddings | The gRPC service creates the endpoint client | None |
| Text splitter providers | The gRPC service creates each text splitter; NLTKTextSplitter downloads the NLTK punkt_tab data | paths.nltk in the gRPC service container of the pod, for NLTKTextSplitter |
The following limits apply to the model download:
- Seeded model. The seeded embedding model has no
onnxparameter, so the command stops at that model withError: "Invalid parameter: missing field `onnx`". The models listed after the seeded model and all text splitters are then not processed. - One pod. The files land in the containers of the pod where the command runs. Other pods do not receive the files, and the files are lost when the containers restart. Models, packages and air-gapped installs describes model and package images, which deliver files to every pod.
- Network access. The command needs access to the Hugging Face Hub and to the download sources of the gRPC service providers, so the command applies to connected deployments only.
- Errors. Download failures print
Error: "Invalid parameter: Error downloading model from Hugging Face: <reason>"for FastEmbed files and a message that begins withgRPC error:for providers in the gRPC service. Query failures printFailed to retrieve embedding providers: <reason>orFailed to retrieve text splitters providers: <reason>.
Admin subcommands
The admin subcommands create and change keys that hold every permission. Access control describes the master key, and Secrets and keys describes the master key values of an installation.
Master key creation
admin create-admin-api-key <NAME> [DESCRIPTION] [EXPIRATION] creates the master key from app.master.key and app.master.secret and prints Admin API key created successfully. The master key Job runs the command at every installation and upgrade with the name Master Admin Key and no other argument.
| Argument | Type | Required | Effect |
|---|---|---|---|
NAME | String | Yes | Name of the key. Every key has a unique name. |
DESCRIPTION | String | No | Description of the key |
EXPIRATION | Date and time in RFC 3339 form, such as 2027-01-31T00:00:00Z | No | Expiry of the key. A value without a time or without a UTC offset fails with exit status 2. |
The following rules apply to the master key creation:
- Existing key. When a key with the identifier
app.master.keyexists, the command leaves the name, the description, the expiry and the stored secret of that key unchanged, and prints the success message. - Permissions. The command sets the permissions of the key to read, write and execute on every object type, with the allow-list
*, and removes the cached copy of the key from the Redis-compatible cache. - Expiry. The API server and the workers authenticate with the master key at startup, so the master key stays active and unexpired. The master key Job therefore passes no expiry.
- Errors. A failure of the full connection prints
Error: "Failed to create database connection: <reason>". A key that cannot be stored printsError: "Failed creating admin API key: <reason>", and a name that another key uses produces a reason that begins withConflict error (unique):.
Master key update
admin update-admin-api-key [NAME] [DESCRIPTION] changes the name, the description or both of the key with the identifier app.master.key, and prints Admin API key updated successfully.
The following rules apply to the master key update:
- Arguments. The first argument sets the name, and the second argument sets the description. The help of the command lists four arguments,
[NAME] [DESCRIPTION] [ACTIVE] [EXPIRATION], but the command accepts at most two. A third argument fails witherror: unexpected value '<value>' for '[DESCRIPTION]' found; no more were expectedand exit status 2. - Omitted arguments. An omitted argument leaves the value unchanged, and the command without arguments changes neither value. The description cannot be removed; an empty string
""sets an empty description. - Other effects. The command sets the permissions of the master key as
admin create-admin-api-keydoes, and removes the cached copy of the key. The command changes no other property of the master key. - Errors.
Error: "Failed updating admin API key: Api Key not found: <master key identifier>"means that no key has the identifierapp.master.key.Error: "Failed updating admin API key: SQL error: <reason>"means that the change cannot be stored, for example because another key uses the name.
Administration key generation
admin generate-admin-api-key <NAME> [DESCRIPTION] [EXPIRATION] creates a new key with a random identifier, a random secret of 32 letters and digits, and the permissions of the master key. The arguments are those of admin create-admin-api-key:
kubectl exec -n foundation4ai deploy/foundation4ai-api-server -c server -- ./foundation4ai admin generate-admin-api-key "Operations key" "Administration key for the operations team"
Expected result:
Admin API key created successfully.
Key : <key identifier>
Secret: <32-character secret>
The following rules apply to the generated key:
- Single output. The output is the only copy of the secret. The command runs in a session whose output is not recorded, and the secret goes directly to the organization's secret store.
- Use. The new key is an administration key for API requests, as described in Manage API keys and permissions. The new key does not replace the master key, because the API server and the workers authenticate with
app.master.keyat startup. - Errors. The command prints the same errors as
admin create-admin-api-key.