Skip to main content

Navin Manager SDK and CLI

This guide shows how to call the API of the Navin Manager (navin-manager), which installs and operates the infrastructure of the platform: hosts, clusters, services, high availability, backups, restores and disaster recovery. It covers the manager client of each SDK and the enterprise-ai manager command line. The API is described by navin-manager/docs/api/manager-openapi.json, written from the server by tools/manager/openapi.py.

Version française : manager.fr.md

Overview​

The manager clients are generated from the OpenAPI document by tools/manager/gen_sdks.py: one method per operation under /api/v1, grouped by tag (269 operations in 31 groups), plus contract aliases such as hosts.preflight, services.rollback, ha.test_failover, backups.create_plan, restores.execute and dr.request_failover. A coverage test in each SDK fails as soon as an operation of the document has no method.

SDKEntry pointGenerated tableCoverage test
Pythonenterprise_ai.manager.ManagerClient, AsyncManagerClientsdks/python/src/enterprise_ai/manager/_generated.pysdks/python/tests/test_manager.py
TypeScriptManagerClient of @enterprise-ai/sdksdks/typescript/packages/sdk/src/manager/generated/operations.tssdks/typescript/packages/sdk/test/manager.test.ts
Gopackage manager of the Go SDK modulesdks/go/manager/operations_gen.gosdks/go/manager/manager_test.go
Javaio.enterpriseai.manager.ManagerClientsdks/java/enterprise-ai-java/src/main/java/io/enterpriseai/manager/ManagerGroups.javathe Java test suite

The manager client is not the platform_manager sub-client of the Control Plane SDK: that one reaches the Platform Manager space of the console through the Control Plane, for a platform_admin.

Requirements and compatibility​

The manager client ships inside each SDK and has the same requirements: Python 3.10+, Node.js 18+, Go 1.26+, Java 17+ (SDK overview). It targets the manager API v1 (/api/v1). Install the SDK as described in its guide; no extra package is needed.

Authentication and delegation​

  1. Create a manager API token. In the manager console, Profile > API tokens, create a token with the smallest permission list. The token looks like nmt_<12 hex>_<secret>; every SDK refuses another format before any call.
  2. Store the token in a file readable by its owner only (mode 0600) and give its path (NM_MANAGER_TOKEN_FILE, token_file, tokenFile), or pass it from a secret store. No SDK and no CLI command prints it.
  3. Act for a user when a service calls on behalf of a person. The on_behalf_of option (onBehalfOf in TypeScript and Java, WithOnBehalfOf in Go) sends X-NM-On-Behalf-Of: <user>. The manager accepts it only from a token whose explicit permission list holds auth:delegate: the request then holds the intersection of the token and user permissions, and every audit event records the actor (the service token) plus details.on_behalf_of and details.delegation. Any other caller gets HTTP 403 on_behalf_of_forbidden; an unknown or disabled user gets 403 on_behalf_of_unknown.
warning

The Control Plane credentials (EAI_*) are never sent to the manager: the manager clients read only their own settings.

Client configuration​

SettingPython (ManagerConfig)TypeScript (ManagerClientOptions)Go (manager.With...)Java (ManagerClient.Builder)Environment variable
Manager URL (https, or http on localhost)base_url: strbaseUrl: stringWithBaseURL(string)baseUrl(String)NM_MANAGER_URL
Tokentoken: str | Nonetoken: string | () => string | Promise<string>WithToken(string)token(String)NM_MANAGER_TOKEN
Token filetoken_file: str | NonenonenonetokenFile(Path)NM_MANAGER_TOKEN_FILE
CA bundle (PEM)ca_bundle: str | Noneruntime trust (NODE_EXTRA_CA_CERTS)WithCABundle([]byte)caBundle(Path)NM_MANAGER_CA_BUNDLE
Delegationon_behalf_of: str | NoneonBehalfOf: stringWithOnBehalfOf(string)onBehalfOf(String)NM_MANAGER_ON_BEHALF_OF
Locale (en, fr)locale: str | NonelocaleWithLocale(string)locale(Locale)NM_MANAGER_LOCALE
Timeouttimeout: float = 30.0timeoutMs (default 60000)WithHTTPClient(...)timeout(Duration) (30 s), connectTimeout(Duration) (10 s)none
Retriesretries: int = 2retries (default 2)WithRetries(int) (2), WithRetryBaseDelay (250 ms)retries(int) (2), retryBaseDelay(Duration) (250 ms)none
Extra headersheaders: dict[str, str]headersWithHeader(name, value)header(name, value)none
HTTP clienthttp_client=fetchWithHTTPClient(*http.Client)httpClient(HttpClient)none

The environment variables are read by ManagerConfig.from_env() (Python, also used when no config is given) and ManagerClient.Builder.fromEnv(System.getenv()) or ManagerClient.fromEnv() (Java). TypeScript and Go take the values from your code.

Quickstart and resource groups​

Python​

from enterprise_ai.manager import ManagerClient

with ManagerClient("<manager-url>", token=TOKEN, ca_bundle=None, http_client=HTTP) as nm:
check = nm.hosts.preflight({"cluster_id": "c1", "target": {"host": "10.0.0.5"}, "private_key": "ref",
"fqdn": "<host-fqdn>", "expected_ip": "10.0.0.5"})
op = nm.services.action("c1", "kafka", {"action": "restart"})
status = nm.operations.get_operation(op["operation_id"])
for item in nm.operations.list_operations("c1", limit=50):
print(item["id"])
as_alice = nm.on_behalf_of("alice")
as_alice.restores.plan({"artifact_id": "a1", "environment": "staging"})

What happens: the client checks the token format, opens one connection pool, runs a preflight of a new host, restarts a service, reads the resulting operation, walks every page of the operations of the cluster, then plans a restore on behalf of alice. AsyncManagerClient has the same methods, each returning an awaitable. nm.operation("<operationId>") returns the bound method of any operation id of the document.

TypeScript​

import { ManagerClient, collect, paginate } from "@enterprise-ai/sdk";

const nm = new ManagerClient({ baseUrl: "<manager-url>", token, onBehalfOf: "alice" });
const op = await nm.services.action("c1", "kafka", { action: "restart" });
const ops = await collect(paginate((q) => nm.operations.listOperations("c1", q), { limit: 50 }));

Go​

nm, err := manager.New(manager.WithBaseURL("<manager-url>"), manager.WithToken(token),
manager.WithCABundle(pem), manager.WithOnBehalfOf("alice"))
raw, err := nm.Services.Action(ctx, "c1", "kafka", map[string]any{"action": "restart"})

Java​

ManagerClient nm = ManagerClient.builder()
.baseUrl("<manager-url>")
.tokenFile(Path.of("/run/secrets/manager.token"))
.caBundle(Path.of("/etc/pki/manager-ca.pem"))
.build();
JsonNode op = nm.services().action("c1", "kafka", Map.of("action", "restart"));
for (JsonNode item : nm.operations().listOperations("c1").autoPaging()) {
System.out.println(item.path("id").asText());
}
ManagerClient asAlice = nm.onBehalfOf("alice");

Resource groups​

Every group exists in the four SDKs (Python nm.hosts, TypeScript nm.hosts, Go nm.Hosts, Java nm.hosts()). The number is the count of operations of the document in the group.

GroupOperationsGroupOperationsGroupOperations
alerts10configs12node_security22
audit3connections7operations7
auth2consoles4pki3
auth_config11hosts13services22
availability6hub5settings2
backup31kubernetes19stack3
blueprint3lifecycle29system3
clusters10mcp12telemetry1
me3mcp_runtime4users10
meta1mirror2vault7
network2

The contract groups backups, restores, ha and dr hold only aliases of the operations above (for example restores.plan, ha.test_failover). Every method, with its parameters and route, is in the generated reference: Python, TypeScript, Go, Java.

Errors​

Errors keep the manager envelope {"error": {"code", "message", "message_i18n", "details"}} and are the typed errors of each SDK: Python EaiError subclasses (messages holds message_i18n), TypeScript EaiError subclasses (messageI18n), Go *eai.APIError (MessageI18n), Java EaiException subclasses. The codes specific to the manager include on_behalf_of_forbidden, on_behalf_of_unknown (403) and the approval, lock and conflict codes of the operations (409, 423, 428).

Retries and timeouts​

The manager does not deduplicate POST calls by Idempotency-Key, so the clients never retry an operation that may have run:

SDKRetried callsRetried failures
PythonGET, PUT, DELETE; any method on HTTP 429network errors, 429, 500, 502, 503, 504
TypeScriptGET, PUT, DELETE (other methods use noRetry)network errors, timeouts, 429, 5xx
GoGET, PUT, DELETEnetwork errors, 408, 429, 502, 503, 504
JavaGET, PUT, DELETEI/O errors, 408, 429, 502, 503, 504

Pagination and long operations​

List operations take limit and cursor and return the {items, next_cursor} page of each SDK: Python Page, TypeScript Page<Doc> (walk it with paginate and collect), Go json.RawMessage (with eai.WithLimit and eai.WithCursor), Java Page<JsonNode> (autoPaging()). Actions on services, hosts and backups answer with an operation: read it with operations.get_operation(id) (getOperation, GetOperation), and its tasks and logs with the other methods of the operations group.

Exempt operations​

The browser and MFA flows are not wrapped: they need the session cookie and the CSRF token of a person, never a service token. The list with its reasons is EXEMPT (Python), MANAGER_EXEMPT (TypeScript), manager.Exempt (Go) and ManagerOperations.EXEMPT (Java): auth/login, auth/logout, auth/setup, auth/password/change, auth/oidc/{provider_id}/start and callback, auth/mfa/verify, auth/mfa/enroll/start and confirm, auth/mfa/setup, auth/mfa/confirm, DELETE auth/mfa, POST me/tokens (a token cannot mint tokens) and PATCH me (profile edited from the session).

Testing​

Each manager client accepts an injected HTTP layer, exactly like the Control Plane client: Python http_client=httpx.Client(transport=httpx.MockTransport(handler)), TypeScript fetch, Go WithHTTPClient with an httptest server, Java httpClient or a local server. The examples of this page are run by sdks/python/tests/test_manager.py against a mocked manager.

CLI reference​

Configuration, highest priority first: options (--manager-url, --ca-bundle, --token-file, --on-behalf-of, --manager-config), environment variables (NM_MANAGER_URL, NM_MANAGER_CA_BUNDLE, NM_MANAGER_TOKEN_FILE or NM_MANAGER_TOKEN, NM_MANAGER_ON_BEHALF_OF, NM_MANAGER_CONFIG), then the JSON file ~/.config/enterprise-ai/manager.json with the keys url, ca_bundle, token_file, on_behalf_of, locale. A token key in that file is refused (exit 7). --json prints the raw JSON response; --body FILE (JSON or YAML, - for stdin) gives the request body, the options are merged on top. Help works offline: enterprise-ai manager --help.

CommandManager route
host add --body F [--cluster C]POST /api/v1/hosts/bootstrap/plan (plan of the addition, nothing executed)
host preflight --body FPOST /api/v1/hosts/preflight
host bootstrap --body FPOST /api/v1/hosts/bootstrap (strict host key, temporary SSH)
host enroll --cluster C --fqdn N --fingerprint SHA256 [--ttl S]POST /api/v1/hosts/enroll
host list [--cluster C]GET /api/v1/hosts
host show HGET /api/v1/hosts/{host_id}
host revoke H [--reason R]POST /api/v1/hosts/{host_id}/revoke
host diagnose HGET /api/v1/agents/nodes/{host_id}, GET /api/v1/hosts/{host_id}/inventory, GET /api/v1/hosts/{host_id}/preflight
cluster import C --api-server URL --kubeconfig F [--namespace N]POST /api/v1/clusters/{cluster_id}/kubernetes
cluster listGET /api/v1/clusters
cluster nodes CGET /api/v1/clusters/{cluster_id}/hosts
cluster pools CGET /api/v1/clusters/{cluster_id}/topology, hosts grouped by rack (fault domain); the manager has no node pool route
service install C S [--body F] [--no-start]POST /api/v1/clusters/{cluster_id}/services
service configure C S --body F [--note N]PUT /api/v1/clusters/{cluster_id}/services/{service}/config
service start|stop|restart C S [--approval A]POST /api/v1/clusters/{cluster_id}/services/{service}/actions
service upgrade C S [--approval A] [--canary-host H]POST /api/v1/clusters/{cluster_id}/services/{service}/upgrade
service rollback C UPGRADE [--approval A]POST /api/v1/clusters/{cluster_id}/upgrades/{upgrade_id}/rollback
service status C SGET /api/v1/clusters/{cluster_id}/services/{service}
ha create --body FPOST /api/v1/ha-groups
ha status GGET /api/v1/ha-groups/{group_id}
ha test-failover GPOST /api/v1/ha-groups/{group_id}/test-failover
backup plan --body FPOST /api/v1/backup-plans
backup run P --location L [--kind K]POST /api/v1/backup-plans/{plan_id}/backups
backup verify BPOST /api/v1/backups/{backup_id}/verify
backup listGET /api/v1/backups
restore plan --artifact A --environment EPOST /api/v1/restores/plan
restore approve PPOST /api/v1/restores/{plan_id}/approve (separation of duties enforced by the manager)
restore execute PPOST /api/v1/restores/{plan_id}/execute
restore verify PGET /api/v1/restores/{plan_id} (state, approvers, verification)
dr plan --body FPOST /api/v1/dr-plans
dr exercise --plan PPOST /api/v1/dr-exercises
dr failover-request --plan PPOST /api/v1/dr-failovers/request (request only: approval required)

Exit codes: 0 success; 1 invalid input (local check, HTTP 400 or 422); 2 usage error; 3 authentication or permission refused (HTTP 401 or 403); 4 not found (HTTP 404); 5 conflict, lock or approval required (HTTP 409, 423 or 428); 6 server or network error; 7 configuration error.

Examples​

These lines are run by sdks/python/tests/test_manager.py against a mocked manager.

export NM_MANAGER_URL=<manager-url> NM_MANAGER_TOKEN_FILE=~/.config/enterprise-ai/manager.token
enterprise-ai manager host preflight --cluster c1 --body host.json --json
enterprise-ai manager host bootstrap --cluster c1 --body host.json
enterprise-ai manager host enroll --cluster c1 --fqdn <host-fqdn> --fingerprint SHA256:abc
enterprise-ai manager host list --cluster c1
enterprise-ai manager host diagnose h1 --json
enterprise-ai manager host revoke h1 --reason "key compromised"
enterprise-ai manager cluster import c1 --api-server <api-server-url> --kubeconfig kubeconfig
enterprise-ai manager cluster pools c1 --json
enterprise-ai manager service install c1 kafka
enterprise-ai manager service configure c1 kafka --body kafka.json --note "retention 7 days"
enterprise-ai manager service restart c1 kafka
enterprise-ai manager service upgrade c1 kafka --approval ap1
enterprise-ai manager service rollback c1 up1 --approval ap2
enterprise-ai manager service status c1 kafka --json
enterprise-ai manager ha create --body ha.json
enterprise-ai manager ha test-failover g1
enterprise-ai manager backup plan --body backup-plan.json
enterprise-ai manager backup run p1 --location s3://backups/pg/2026-10-30
enterprise-ai manager backup verify b1
enterprise-ai manager backup list --json
enterprise-ai manager restore plan --artifact a1 --environment staging
enterprise-ai manager restore approve r1 --on-behalf-of alice
enterprise-ai manager restore execute r1
enterprise-ai manager restore verify r1 --json
enterprise-ai manager dr plan --body dr-plan.json
enterprise-ai manager dr exercise --plan d1
enterprise-ai manager dr failover-request --plan d1

Reference​